Helma Logo
main list history

Version 6 by hannes on 21. September 2009, 15:32

1Helma 1 comes with its own home-grown fully featured Object-Relational Mapping framework.

Version 5 by hannes on 21. September 2009, 15:23

145

Version 4 by hannes on 21. September 2009, 15:21

3=== ### Overview
7    _db = antville
8    _table = AV_TEXT
9     
10    _parent = site.stories
11    _id = TEXT_ID
12    _prototype = TEXT_PROTOTYPE
9 _parent = site.stories  # object references
10 _id   creator = TEXT_IDobject (user)
11 _prototype   creator.local = TEXT_PROTOTYPETEXT_F_USER_CREATOR
12    creator.foreign = USER_ID
13 # object references    
14 creator = object (user)  # primitive properties
15 creator.local   title = TEXT_F_USER_CREATORTEXT_TITLE
16 creator.foreign   text = USER_IDTEXT_TEXT
17    createtime = TEXT_CREATETIME
18    modifytime = TEXT_MODIFYTIME
11    # primitive propertiescollections
12 title   comments = TEXT_TITLEcollection (comment)
13 text   comments.local = TEXT_TEXTTEXT_ID
14 createtime   comments.foreign = TEXT_CREATETIMETEXT_F_TEXT_STORY
15 modifytime   comments.filter = TEXT_MODIFYTIMETEXT_ISONLINE >
16    comments.order = TEXT_MODIFYTIME DESC
17 # collections
18 comments = collection (comment)
19 comments.local = TEXT_ID
20 comments.foreign = TEXT_F_TEXT_STORY
21 comments.filter = TEXT_ISONLINE > 0
22 comments.order = TEXT_MODIFYTIME DESC
15=== ### Basic Mappings
17The <tt>_db</tt> `_db` entry describes the database to use for storing objects of this type. <tt>dbname</tt> `dbname` is the name of a database as defined in the <tt>db`db.properties</tt> properties` file.
19<pre>_db     _db = dbname</pre>dbname
21The <tt>_table</tt> `_table` entry tells Helma which table to use for objects of this type within the database.
23<pre>_table     _table = TABLENAME</pre> TABLENAME
25The <tt>_id</tt> `_id` entry defines the column to use as primary key. Helma requires a single primary key with no other functionality.
27<pre>_id     _id = ID_COLUMN</pre>ID_COLUMN
29The optional <tt>_name</tt> `_name` entry tells Helma which database column to use as object name. This is important for the user prototype, since it defines which column constitutes the user name.
31<pre>_name     _name = NAME_COLUMN</pre>NAME_COLUMN
33The <tt>_parent</tt> `_parent` entry contains a comma-separated list of properties of objects of this type to be used as parent. Objects must know their parent in order to generate correct URLs in their <tt>href()</tt> `href()` function.
35<pre>_parent     _parent = property1, property2.collectionX, root.collectionY</pre>collectionY
39A type can inherit its data mapping and functions from another type. This is done with the <tt>_extends</tt> `_extends` entry. Simply specify the name of the parent type:
41<pre>_extends     _extends = parenttype</pre>parenttype
43Extended prototypes are usually stored in the same relational database table. Thus, Helma needs a way to tell which row in the table should be instantiated with which object prototype. This is done using the <tt>_prototype</tt> `_prototype` entry, specifying a column in the table containing the name of the prototype for each row.
45<pre>_prototype     _prototype = PROTO_COLUMN</pre>PROTO_COLUMN
47=== ### Simple Property Mappings
51<pre>prop1     prop1 = DB_COLUMN_1
52    prop2 = DB_COLUMN_2</pre>DB_COLUMN_2
55<pre>prop1    prop1.readonly = true</pre>true
59<pre>prop1    prop1.private = true</pre>true
61=== ### Object Reference Mappings
65<pre>prop3     prop3 = object (protoype)
66    prop3.local = LOCAL_DB_COLUMN
67    prop3.foreign = FOREIGN_DB_COLUMN</pre>FOREIGN_DB_COLUMN
67<tt>prop3`prop3.local</tt> local` specifies the part of the reference in the local database-table, <tt>prop3`prop3.foreign</tt> foreign` the column in the table where objects of the referenced prototype are stored. By executing the assignment <tt>obj`obj.prop3 = someObject</tt>someObject`, the database-column specified by <tt>prop3`prop3.local</tt> local` will be set to the value of <tt>FOREIGN_DB_COLUMN</tt>`FOREIGN_DB_COLUMN`, or <tt>null</tt> `null` if <tt>someObject `someObject == null</tt>null`.
69=== ### Collection Mappings
71The following section describes the entries used to define collections of objects. There are two kinds of collections: First, every object can itself act as a collection, and second, it can define additional properties to be used as collections. Direct descendents are defined with entries starting with <tt>_children</tt>`_children`, while additional collections are defined using their property name. Otherwise the syntax for the two is the same.
73The following are examples for simple collection mappings for both the direct descendants and those contained in a collection-property called <tt>prop4</tt>`prop4`. The <tt>`.foreign</tt> foreign` entry is used in both cases to specify a column in the foreign table used to collect the objects. Exactly those objects will be collected whose <tt>FOREIGN_DB_COLUMN</tt> `FOREIGN_DB_COLUMN` value equals the <tt>LOCAL_DB_COLUMN</tt> `LOCAL_DB_COLUMN` value of the object holding the collection. Leaving away <tt>`.local</tt> local` and <tt>`.foreign</tt> foreign` creates a collection of all available objects of the specified prototype.
75<pre>_children     _children = collection (protoype)
76    _children.local = LOCAL_DB_COLUMN
77    _children.foreign = FOREIGN_DB_COLUMN
77    prop4 = collection (protoype)
78    prop4.local = LOCAL_DB_COLUMN
79    prop4.foreign = FOREIGN_DB_COLUMN</pre>FOREIGN_DB_COLUMN
79By executing <tt>obj`obj.add(otherObj)</tt> add(otherObj)` resp. <tt>obj`obj.prop4.add(otherObj)</tt>add(otherObj)`, the <tt>FOREIGN_DB_COLUMN</tt> `FOREIGN_DB_COLUMN` will be set to the value of <tt>LOCAL_DB_COLUMN</tt>`LOCAL_DB_COLUMN`.
81By default, child objects can be accessed from the containing parent object through their index-position or <tt>ID</tt> `ID` value. Additionally the entry <tt>`.accessname</tt> accessname` can be used to specify a database column in the child table. The value of this column will be used as name of the objects contained in this collection.
83<pre>prop4    prop4.accessname = DB_COLUMN</pre>DB_COLUMN
85With the above mapping, an object contained in the <tt>prop4</tt> `prop4` collection with a <tt>DB_COLUMN</tt> `DB_COLUMN` value of "xyz" would be reachable as <tt>this`this.prop4.xyz</tt> xyz` from the containing object.
87<tt>filter</tt> `filter` can be used to add an additional condition for the selection of objects which is not dependent on the object holding the collection. <tt>order</tt> `order` contains the sorting to be applied to the child objects. <tt>group</tt> `group` tells Helma to group the objects in the collection according to the value in <tt>DB_GROUPCOLUMN</tt>`DB_GROUPCOLUMN`.
89<pre>prop4    prop4.filter = DB_FILTERCOLUMN is not null
90    prop4.order = DB_ORDERCOLUMN desc
91    prop4.group = DB_GROUPCOLUMN
92    prop4.group.order = DB_GROUPORDERCOLUMN
93    prop4.group.prototype = SomePrototype</pre>SomePrototype
91Notice the two appearences of <tt>order</tt> `order` above. The first one, <tt>prop4`prop4.order</tt> order` sorts the objects, the second, <tt>prop4`prop4.group.order</tt> order` sorts the grouped objects, that Helma will create as a result of the <tt>group</tt> `group` entry. With this it's also possible to sort the grouped objects ascending, but the contents of the grouped objects descending.
93The <tt>prop4`prop4.group.prototype</tt> prototype` property sets the Prototype to be used for the group objects generated by Helma.
95Filters can contain references to the values of the current object's database entry fields. This is the syntax for these variables: <tt>${FIELD_NAME}</tt>`${FIELD_NAME}`. The variables are then replaced by the actual values of the fields before the query is executed.
97<pre>prop4 = collection (protoype)
98prop4.filter = FOREIGN_DB_COLUMN = ${LOCAL_DB_COLUMN}</pre>
99<tt>filter.additionalTables</tt> allows adding additional tables to the query, so that their fields can be used in the condition of the filter as well. The table of the collection's prototype is allways the first table in the query.  prop4 = collection (protoype)
100Table references can be aliased using <tt>TABLE_NAME AS ALIAS_NAME</tt> or <tt>TABLE_NAME ALIAS_NAME</tt>    prop4.filter = FOREIGN_DB_COLUMN = ${LOCAL_DB_COLUMN}
101<pre>#Node is stored `filter.additionalTables` allows adding additional tables to the query, so that their fields can be used in in the database condition of the filter as well. The table NODEof the collection's prototype is allways the first table in the query. Table references can be aliased using `TABLE_NAME AS ALIAS_NAME` or `TABLE_NAME ALIAS_NAME`.
103#subChildren     #Node is a collection containing all stored in in the Node's children's children:database table NODE
104subChildren = collection(Node)  #subChildren is a collection containing all the Node's children's children:
105subChildren.filter.additionalTables     subChildren = NODE AS CHILDRENcollection(Node)
106    subChildren.filter = NODEfilter.FOREIGN_DB_COLUMN additionalTables = ${LOCAL_DB_COLUMN} AND NODE.LOCAL_DB_COLUMN = NODE AS CHILDREN.FOREIGN_DB_COLUMN
107</pre>    subChildren.filter = NODE.FOREIGN_DB_COLUMN = ${LOCAL_DB_COLUMN} AND NODE.LOCAL_DB_COLUMN = CHILDREN.FOREIGN_DB_COLUMN
105Another example: Short arrays of objects of which the sequence can be changed without using a position field for each object can be created with the SQL statements <tt>ID_FIELD `ID_FIELD IN (ID_LIST)</tt> (ID_LIST)` and <tt>FIND_IN_SET(ID_FIELD`FIND_IN_SET(ID_FIELD, ID_LIST)</tt>ID_LIST)`, <tt>ID_LIST</tt> `ID_LIST` being a string field that contains the IDs seperated by commas. This comes in handy when the objects are used in more than one such array and the objects stored in such a way should know about all their referencing objects.
107<pre>#Object1/type**Object1/type.propertiesproperties**:
109    #the id list string containing a comma seperated list of OBJECT2 ids:
110    strObject2Ids = OBJECT2_IDS
111    #object2s lists the Object2 objects as referenced by strObject2Ids:
112    object2s = collection(Object2)
113    object2s.filter = OBJECT2.ID IN (${OBJECT1.OBJECT2_IDS})
113#Object2/type**Object2/type.propertiesproperties**:
115    #object1s lista all Object1 objects that are referencing this Object2 through their object2s collection:
116    object1s = collection(Object1)
117    object1s.filter.additionalTables = OBJECT2
118    object1s.filter = OBJECT2.ID = ${ID} AND FIND_IN_SET(OBJECT2.ID, OBJECT1.OBJECT2_IDS)</pre>OBJECT2_IDS)
117=== ### Additional Join Conditions
121<pre>prop4    prop4.local.1 = FIRST_LOCAL_COLUMN
122    prop4.foreign.1 = FIRST_FOREIGN_COLUMN
123    prop4.local.2 = SECOND_LOCAL_COLUMN
124    prop4.foreign.2 = SECOND_FOREIGN_COLUMN</pre>SECOND_FOREIGN_COLUMN
123Whenever one specifies more than one restraint, the use of <tt>.[Number]</tt> number suffix is mandatory.
125=== ### Mountpoint Mappings
127Mountpoints provide a simple way to directly attach a prototype to the URL path. If the path contains the name of a mountpoint the prototype's objects are accessible simply by adding their id (or a property defined by <tt>`._accessname</tt>) _accessname`) to the URL string.
129<pre>myMountpoint     myMountpoint = mountpoint(myProto)</pre>mountpoint(myProto)
131In the example above, the path <tt>/myMountpoint/23/test</tt> `/myMountpoint/23/test` refers to the action <tt>test`test.hac</tt> hac` of the object with id 23, which is derived from the <tt>myProto</tt> `myProto` prototype.
133=== ### Advanced Settings
140<p>
144<p>
150
151<p>
154<p>

Version 3 by hannes on 18. February 2009, 17:43

Version 2 by hannes on 17. February 2009, 22:23

36The <tt>_db</tt> entry describes the database to use for storing objects of this type. <tt>dbname</tt> is the name of a database as defined in the <tt>db.properties</tt> file.
37
38<pre>_db = dbname</pre>
39
40The <tt>_table</tt> entry tells Helma which table to use for objects of this type within the database.
41
42<pre>_table = TABLENAME</pre>
43
44The <tt>_id</tt> entry defines the column to use as primary key. Helma requires a single primary key with no other functionality.
45
46<pre>_id = ID_COLUMN</pre>
47
48The optional <tt>_name</tt> entry tells Helma which database column to use as object name. This is important for the user prototype, since it defines which column constitutes the user name.
49
50<pre>_name = NAME_COLUMN</pre>
51
52The <tt>_parent</tt> entry contains a comma-separated list of properties of objects of this type to be used as parent. Objects must know their parent in order to generate correct URLs in their <tt>href()</tt> function.
53
54<pre>_parent = property1, property2.collectionX, root.collectionY</pre>
55
56If an entry in the _parent item does not contain a dot, it is interpreted as an object property of the current object that acts as the object's parent. If an entry contains a dot character, the part after the dot is interpreted as a collection in the parent object in which the current object is contained. If the _parent is specified as "root", it is not interpreted as a property of the current object. Instead, the application's root object is used as parent object.
57
58A type can inherit its data mapping and functions from another type. This is done with the <tt>_extends</tt> entry. Simply specify the name of the parent type:
59
60<pre>_extends = parenttype</pre>
61
62Extended prototypes are usually stored in the same relational database table. Thus, Helma needs a way to tell which row in the table should be instantiated with which object prototype. This is done using the <tt>_prototype</tt> entry, specifying a column in the table containing the name of the prototype for each row.
63
64<pre>_prototype = PROTO_COLUMN</pre>
65
39The mappings for simple properties (versus properties that are objects containing further properties) simply map a property name of the specified object type to a column of the relational database table. The type of the property or column need not be specified. Helma does all necessary conversion when reading or writing a property value.
40
41<pre>prop1 = DB_COLUMN_1
42prop2 = DB_COLUMN_2</pre>
43
44To prevent a property from being overwritten by the application it can be made readonly.
45
46<pre>prop1.readonly = true</pre>
47
48In a similar manner marking a property as private will prevent any corresponding collection or reference from being updated but still perform all necessary updates in the database.
49
50<pre>prop1.private = true</pre>
51
42Properties that contain other objects are defined by the object keyword and the prototype name of the referenced object in brackets. The object reference is resolved via two entries:
43
44<pre>prop3 = object (protoype)
45prop3.local = LOCAL_DB_COLUMN
46prop3.foreign = FOREIGN_DB_COLUMN</pre>
47
48<tt>prop3.local</tt> specifies the part of the reference in the local database-table, <tt>prop3.foreign</tt> the column in the table where objects of the referenced prototype are stored. By executing the assignment <tt>obj.prop3 = someObject</tt>, the database-column specified by <tt>prop3.local</tt> will be set to the value of <tt>FOREIGN_DB_COLUMN</tt>, or <tt>null</tt> if <tt>someObject == null</tt>.
49
45The following section describes the entries used to define collections of objects. There are two kinds of collections: First, every object can itself act as a collection, and second, it can define additional properties to be used as collections. Direct descendents are defined with entries starting with <tt>_children</tt>, while additional collections are defined using their property name. Otherwise the syntax for the two is the same.
46
47The following are examples for simple collection mappings for both the direct descendants and those contained in a collection-property called <tt>prop4</tt>. The <tt>.foreign</tt> entry is used in both cases to specify a column in the foreign table used to collect the objects. Exactly those objects will be collected whose <tt>FOREIGN_DB_COLUMN</tt> value equals the <tt>LOCAL_DB_COLUMN</tt> value of the object holding the collection. Leaving away <tt>.local</tt> and <tt>.foreign</tt> creates a collection of all available objects of the specified prototype.
48
49<pre>_children = collection (protoype)
50_children.local = LOCAL_DB_COLUMN
51_children.foreign = FOREIGN_DB_COLUMN
52
53prop4 = collection (protoype)
54prop4.local = LOCAL_DB_COLUMN
55prop4.foreign = FOREIGN_DB_COLUMN</pre>
56
57By executing <tt>obj.add(otherObj)</tt> resp. <tt>obj.prop4.add(otherObj)</tt>, the <tt>FOREIGN_DB_COLUMN</tt> will be set to the value of <tt>LOCAL_DB_COLUMN</tt>.
58
59By default, child objects can be accessed from the containing parent object through their index-position or <tt>ID</tt> value. Additionally the entry <tt>.accessname</tt> can be used to specify a database column in the child table. The value of this column will be used as name of the objects contained in this collection.
60
61<pre>prop4.accessname = DB_COLUMN</pre>
62
63With the above mapping, an object contained in the <tt>prop4</tt> collection with a <tt>DB_COLUMN</tt> value of "xyz" would be reachable as <tt>this.prop4.xyz</tt> from the containing object.
64
65<tt>filter</tt> can be used to add an additional condition for the selection of objects which is not dependent on the object holding the collection. <tt>order</tt> contains the sorting to be applied to the child objects. <tt>group</tt> tells Helma to group the objects in the collection according to the value in <tt>DB_GROUPCOLUMN</tt>.
66
67<pre>prop4.filter = DB_FILTERCOLUMN is not null
68prop4.order = DB_ORDERCOLUMN desc
69prop4.group = DB_GROUPCOLUMN
70prop4.group.order = DB_GROUPORDERCOLUMN
71prop4.group.prototype = SomePrototype</pre>
72 
73Notice the two appearences of <tt>order</tt> above. The first one, <tt>prop4.order</tt> sorts the objects, the second, <tt>prop4.group.order</tt> sorts the grouped objects, that Helma will create as a result of the <tt>group</tt> entry. With this it's also possible to sort the grouped objects ascending, but the contents of the grouped objects descending.
74
75The <tt>prop4.group.prototype</tt> property sets the Prototype to be used for the group objects generated by Helma.
76
77Filters can contain references to the values of the current object's database entry fields. This is the syntax for these variables: <tt>${FIELD_NAME}</tt>. The variables are then replaced by the actual values of the fields before the query is executed.
78With these variables, the above collection could also be described like this:
79<pre>prop4 = collection (protoype)
80prop4.filter = FOREIGN_DB_COLUMN = ${LOCAL_DB_COLUMN}</pre>
81
82<tt>filter.additionalTables</tt> allows adding additional tables to the query, so that their fields can be used in the condition of the filter as well. The table of the collection's prototype is allways the first table in the query.
83Table references can be aliased using <tt>TABLE_NAME AS ALIAS_NAME</tt> or <tt>TABLE_NAME ALIAS_NAME</tt>.
84
85<pre>#Node is stored in in the database table NODE
86
87#subChildren is a collection containing all the Node's children's children:
88subChildren = collection(Node)
89subChildren.filter.additionalTables = NODE AS CHILDREN
90subChildren.filter = NODE.FOREIGN_DB_COLUMN = ${LOCAL_DB_COLUMN} AND NODE.LOCAL_DB_COLUMN = CHILDREN.FOREIGN_DB_COLUMN
91</pre>
92
93Another example: Short arrays of objects of which the sequence can be changed without using a position field for each object can be created with the SQL statements <tt>ID_FIELD IN (ID_LIST)</tt> and <tt>FIND_IN_SET(ID_FIELD, ID_LIST)</tt>, <tt>ID_LIST</tt> being a string field that contains the IDs seperated by commas. This comes in handy when the objects are used in more than one such array and the objects stored in such a way should know about all their referencing objects.
94
95<pre>#Object1/type.properties
96
97#the id list string containing a comma seperated list of OBJECT2 ids:
98strObject2Ids = OBJECT2_IDS
99
100#object2s lists the Object2 objects as referenced by strObject2Ids:
101object2s = collection(Object2)
102object2s.filter = OBJECT2.ID IN (${OBJECT1.OBJECT2_IDS})
103
104#Object2/type.properties
105
106#object1s lista all Object1 objects that are referencing this Object2 through their object2s collection:
107object1s = collection(Object1)
108object1s.filter.additionalTables = OBJECT2
109object1s.filter = OBJECT2.ID = ${ID} AND FIND_IN_SET(OBJECT2.ID, OBJECT1.OBJECT2_IDS)</pre>
110
48For both object and collection mappings, it is possible to provide any number of additional restraints used to join the local with the other table to further limit the selected objects.
49
50<pre>prop4.local.1 = FIRST_LOCAL_COLUMN
51prop4.foreign.1 = FIRST_FOREIGN_COLUMN
52prop4.local.2 = SECOND_LOCAL_COLUMN
53prop4.foreign.2 = SECOND_FOREIGN_COLUMN</pre>
54
55Whenever one specifies more than one restraint, the use of <tt>.[Number]</tt> is mandatory.
56
51Mountpoints provide a simple way to directly attach a prototype to the URL path. If the path contains the name of a mountpoint the prototype's objects are accessible simply by adding their id (or a property defined by <tt>._accessname</tt>) to the URL string.
52
53<pre>myMountpoint = mountpoint(myProto)</pre>
54
55In the example above, the path <tt>/myMountpoint/23/test</tt> refers to the action <tt>test.hac</tt> of the object with id 23, which is derived from the <tt>myProto</tt> prototype.
56
54Some techniques to optimize Helma's strategy for managing objects from a relational table.
56<dl><dt><b>_children.loadmode=aggressive</b></dt>
57<dd>When this is set for _children or a virtual node, all child objects will be fetched in one query. The default way is to just fetch an index of children consisting of the object's keys, and then fetch the objects on demand, which allows the Hop to scale to large child collections where only few of the objects are actually accessed.</dd>
58
59<p>
60<dt><b>_children.cachemode=aggressive</b></dt>
61<dd>By default, Hop refreshes a children index when any object with the prototype contained in the subnodes was modified since the last access. By setting this flag on _children or a virtual node, children will only be refreshed when an object is added to or removed from the child collection itself, or an object already contained in it is modified.</dd>
62
63<p>
64<dt><b>_children.maxsize=XX</b></dt>
65<dd>
66When specifying children (either directly or within a virtual container) an optional maxsize property can be used to limit the number of objects contained. A setting of e.g. 100 would cause the collection to contain maximally 100 objects, regardless of how many (matching) rows the database table contains.
67</dd>
68
69
70<p>
71<dt><b>propname.readonly=true</b></dt>
72<dd>Use the readonly flag to tell the Hop never to update this column in the database. Actually the column won't be updated if the property is not modified, but this is like an extra layer of security.</dd>
73
74<p>
75<dt><b>propname.private=true</b></dt>
76<dd>The readonly flag tells Hop to update this column in the database only, but to prevent any collections containing or any other object referring to the very object with that property.</dd>
77</dl>

Version 1 by hannes on 17. February 2009, 22:17

1Helma 1 comes with its own home-grown Object-Relational Mapping framework.
2
3=== Overview
4
5Helma O/R maps rows from relational tables against JavaScript host objects called *HopObjects*. HopObjects are defined by prototype directories, which contain the JavaScript code and templates (called *skins* in Helma lingo) to be applied to them. The object-relational mapping itself is defined in a type.properties file, which may look like this:
6
7 _db = antville
8 _table = AV_TEXT
9    
10 _parent = site.stories
11 _id = TEXT_ID
12 _prototype = TEXT_PROTOTYPE
13   
14 # object references
15 creator = object (user)
16 creator.local = TEXT_F_USER_CREATOR
17 creator.foreign = USER_ID
18    
19 # primitive properties
20 title = TEXT_TITLE
21 text = TEXT_TEXT
22 createtime = TEXT_CREATETIME
23 modifytime = TEXT_MODIFYTIME
24    
25 # collections
26 comments = collection (comment)
27 comments.local = TEXT_ID
28 comments.foreign = TEXT_F_TEXT_STORY
29 comments.filter = TEXT_ISONLINE > 0
30 comments.order = TEXT_MODIFYTIME DESC
31
32The different kinds of entries and their use are described below.
33
34=== Basic Mappings
35
36=== Simple Property Mappings
37
38=== Object Reference Mappings
39
40=== Collection Mappings
41
42=== Additional Join Conditions
43
44=== Mountpoint Mappings
45
46=== Advanced Settings
47