adding perl XSLT and (maybe?) finishing up the javascript one
[OpenSRF.git] / examples / fieldmapper2javascript.xsl
1 <xsl:stylesheet
2         version='1.0'
3         xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
4         xmlns:opensrf="http://opensrf.org/xmlns/opensrf"
5         xmlns:cdbi="http://opensrf.org/xmlns/opensrf/cdbi"
6         xmlns:perl="http://opensrf.org/xmlns/opensrf/perl"
7         xmlns:javascript="http://opensrf.org/xmlns/opensrf/javascript"
8         xmlns:c="http://opensrf.org/xmlns/opensrf/c">
9         <xsl:output method="text" />
10         <xsl:strip-space elements="xsl:*"/>
11         <xsl:variable name="last_field_pos"/>
12
13         <xsl:template match="/">
14 // support functions
15  
16 var IE = false;
17 var unit_test = false;
18  
19 function instanceOf(object, constructorFunction) {
20         if(!IE) {
21                 while (object != null) {
22                         if (object == constructorFunction.prototype)
23                                 return true;
24                         object = object.__proto__;
25                 }
26         } else {
27                 while(object != null) {
28                         if( object instanceof constructorFunction )
29                                 return true;
30                         object = object.__proto__;
31                 }
32         }
33         return false;
34 }
35  
36 // Top level superclass
37 function Fieldmapper(array) {
38         this.array = [];
39         if(array) {
40                 if (array.constructor == Array) {
41                         this.array = array;
42                 } else if ( instanceOf( array, String ) || instanceOf( array, Number ) ) {
43
44                         var obj = null;
45                         if (this.cacheable) {
46                                 try {
47                                         obj = this.baseClass.obj_cache[this.classname][array];
48                                 } catch (E) {};
49                         }
50
51                         if (!obj) {
52                                 obj = user_request(
53                                         'open-ils.proxy',
54                                         'open-ils.proxy.proxy',
55                                         [
56                                                 mw.G.auth_ses[0],
57                                                 'open-ils.storage',
58                                                 'open-ils.storage.direct.' + this.db_type + '.retrieve',
59                                                 array
60                                         ]
61                                 )[0];
62
63                                 if (this.cacheable) {
64                                         if (this.baseClass.obj_cache[this.classname] == null)
65                                                 this.baseClass.obj_cache[this.classname] = {};
66
67                                         this.baseClass.obj_cache[this.classname][obj.id()] = obj;
68                                 }
69                         }
70                         this.array = obj.array;
71
72                 } else {
73                         throw new FieldmapperException( "Attempt to build fieldmapper object with something wierd");
74                 }
75         }
76 }
77 Fieldmapper.prototype.baseClass = Fieldmapper;
78 Fieldmapper.prototype.obj_cache = {};
79
80 Fieldmapper.prototype.search function (type,field,value) {
81
82         var list = user_request(
83                 'open-ils.proxy',
84                 'open-ils.proxy.proxy',
85                 [
86                         mw.G.auth_ses[0],
87                         'open-ils.storage',
88                         'open-ils.storage.direct.' + type.db_type + '.search.' + field,
89                         array
90                 ]
91         )[0];
92         if (type.cacheable) {
93                 if (type.baseClass.obj_cache[type.classname] == null)
94                         type.baseClass.obj_cache[type.classname] = {};
95                 for (var i in list) {
96                         type.baseClass.obj_cache[type.classname][list[i].id()] = list[i];
97                 }
98         }
99         return list;
100 }
101  
102 Fieldmapper.prototype.clone = function() {
103         var obj = new this.constructor();
104
105         for( var i in this.array ) {
106                 var thing = this.array[i];
107                 if(thing == null) continue;
108
109                 if( thing._isfieldmapper ) {
110                         obj.array[i] = thing.clone();
111                 } else {
112
113                         if(instanceOf(thing, Array)) {
114                                 obj.array[i] = new Array();
115
116                                 for( var j in thing ) {
117
118                                         if( thing[j]._isfieldmapper )
119                                                 obj.array[i][j] = thing[j].clone();
120                                         else
121                                                 obj.array[i][j] = thing[j];
122                                 }
123                         } else {
124                                 obj.array[i] = thing;
125                         }
126                 }
127         }
128         return obj;
129 }
130   
131 function FieldmapperException(message) {
132         this.message = message;
133 }
134
135 FieldmapperException.toString = function() {
136         return "FieldmapperException: " + this.message + "\n";
137
138 }
139
140         
141                 <xsl:apply-templates select="opensrf:fieldmapper/opensrf:classes"/>
142         </xsl:template>
143
144
145
146
147
148 <!-- sub-templates -->
149         <xsl:template match="opensrf:fieldmapper/opensrf:classes">
150                 <xsl:for-each select="opensrf:class">
151                         <xsl:sort select="@id"/>
152                         <xsl:apply-templates select="."/>
153                 </xsl:for-each>
154         </xsl:template>
155
156
157
158
159         <xsl:template match="opensrf:class">
160                 <xsl:apply-templates select="@javascript:class"/>
161                 <xsl:apply-templates select="opensrf:fields"/>
162                 <xsl:apply-templates select="opensrf:links/opensrf:link[@type='has_many']"/>
163         </xsl:template>
164
165
166
167
168         <xsl:template match="opensrf:fields">
169                 <xsl:apply-templates select="opensrf:field"/>
170         </xsl:template>
171
172
173
174
175
176         <xsl:template match="@javascript:class">
177
178 // Class definition for "<xsl:value-of select="."/>"
179
180 function <xsl:value-of select="."/> (array) {
181
182         if (!instanceOf(this, <xsl:value-of select="."/>))
183                 return new <xsl:value-of select="."/>(array);
184
185         this.baseClass.call(this,array);
186         this.classname = "<xsl:value-of select="."/>";
187         this._isfieldmapper = true;
188         this.uber = <xsl:value-of select="."/>.baseClass.prototype;
189 }
190
191 <xsl:value-of select="."/>.prototype                    = new <xsl:value-of select="../javascript:superclass"/>();
192 <xsl:value-of select="."/>.prototype.constructor        = <xsl:value-of select="."/>;
193 <xsl:value-of select="."/>.baseClass                    = <xsl:value-of select="../javascript:superclass"/>;
194 <xsl:value-of select="."/>.prototype.cachable           = true;
195 <xsl:value-of select="."/>.prototype.fields             = [];
196 <xsl:value-of select="."/>.last_real_field              = 2;
197  
198 <!-- XXX This needs to come from somewhere else!!!! -->
199 <xsl:value-of select="."/>.prototype.db_type            = "<xsl:value-of select="../cdbi:table[@rdbms='Pg']/cdbi:name"/>";
200  
201 <xsl:value-of select="."/>.prototype.isnew = function(new_value) {
202         if(arguments.length == 1) { this.array[0] = new_value; }
203         return this.array[0];
204 }
205  
206 <xsl:value-of select="."/>.prototype.ischanged = function(new_value) {
207         if(arguments.length == 1) { this.array[1] = new_value; }
208         return this.array[1];
209 }
210  
211 <xsl:value-of select="."/>.prototype.isdeleted = function(new_value) {
212         if(arguments.length == 1) { this.array[2] = new_value; }
213         return this.array[2];
214 }
215  
216         </xsl:template>
217
218
219
220
221
222         <!-- scalar valued fields and "has_a" relationships -->
223         <xsl:template match="opensrf:field">
224
225                 <xsl:variable name="num"><xsl:number/></xsl:variable>
226                 <xsl:variable name="field_pos" select="$num + 2"/>
227                 <xsl:variable name="last_field_pos" select="$field_pos + 1"/>
228                 <xsl:variable name="field_name" select="@name"/>
229
230 // Accessor/mutator for <xsl:value-of select="../../@javascript:class"/>.<xsl:value-of select="$field_name"/>:
231 <xsl:value-of select="../../@javascript:class"/>.last_real_field++;
232 <xsl:value-of select="../../@javascript:class"/>.prototype.fields.push("<xsl:value-of select="$field_name"/>");
233 <xsl:value-of select="../../@javascript:class"/>.prototype.<xsl:value-of select="$field_name"/> = function (new_value) {
234         if(arguments.length == 1) { this.array[<xsl:value-of select="$field_pos"/>] = new_value; }
235
236                 <xsl:if test="../../opensrf:links/opensrf:link[@field=$field_name and @type='has_a']">
237                         <!-- We have a fkey on this field.  Go fetch the referenced object. -->
238                         <xsl:variable
239                                 name="source"
240                                 select="../../opensrf:links/opensrf:link[@field=$field_name and @type='has_a']/@source"/>
241
242         var val = this.array[<xsl:value-of select="$field_pos"/>];
243
244         if (!instanceOf(this.array[<xsl:value-of select="$field_pos"/>], <xsl:value-of select="$source"/>)) {
245                 if (this.array[<xsl:value-of select="$field_pos"/>] != null) {
246                         this.array[<xsl:value-of select="$field_pos"/>] = new <xsl:value-of select="$source"/>(val);
247                 }
248         }
249                 </xsl:if>
250         return this.array[<xsl:value-of select="$field_pos"/>];
251 }
252         </xsl:template>
253
254
255
256
257
258         <!-- "has_many" relationships -->
259         <xsl:template match="opensrf:links/opensrf:link[@type='has_many']">
260                 <xsl:variable name="num"><xsl:number/></xsl:variable>
261                 <xsl:variable name="source"><xsl:value-of select="@source"/></xsl:variable>
262                 <xsl:variable name="classname"><xsl:value-of select="../../@javascript:class"/></xsl:variable>
263                 <xsl:variable name="id"><xsl:value-of select="../../@id"/></xsl:variable>
264                 <xsl:variable name="fkey" select="//*[@id=$source]/opensrf:links/opensrf:link[@type='has_a' and @source=$id]/@field"/>
265                 <xsl:variable name="pkey" select="../../opensrf:fields/opensrf:field[@cdbi:primary='true']/@name"/>
266
267 // accessor for <xsl:value-of select="$classname"/>:
268 <xsl:value-of select="$classname"/>.prototype.<xsl:value-of select="@field"/> = function () {
269  
270         var _pos = <xsl:value-of select="$classname"/>.last_real_field + <xsl:value-of select="$num"/>;
271  
272         if (!instanceOf(this.array[_pos], Array)) {
273                 this.array[_pos] = [];
274  
275         if (this.array[_pos].length == 0) {
276                 /* get the real thing.
277                  * search where <xsl:value-of select="$source"/>.<xsl:value-of select="$fkey"/>()
278                  * equals this.<xsl:value-of select="../../opensrf:fields/opensrf:field[@cdbi:primary='true']/@name"/>();
279                  */
280                 this.array[_pos] = this.uber.search(
281                         <xsl:value-of select="$source"/>,
282                         "<xsl:value-of select="$fkey"/>",
283                         this.<xsl:value-of select="$pkey"/>()
284                 );
285         }
286  
287         return this.array[_pos];
288 }
289
290         </xsl:template>
291
292
293
294
295 </xsl:stylesheet>
296