Add and clean up rel_2_1 branch.
[Evergreen-DocBook.git] / development / datamodelsandaccess.xml
diff --git a/development/datamodelsandaccess.xml b/development/datamodelsandaccess.xml
new file mode 100644 (file)
index 0000000..93ec246
--- /dev/null
@@ -0,0 +1,789 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<chapter xml:id="data_models_and_access" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="EN"\r
+    xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">\r
+       <chapterinfo>\r
+       <title>Evergreen Data Models and Access</title>\r
+       </chapterinfo>\r
+               <abstract id="DM_abstract">\r
+               <simpara>This chapter was taken from Dan Scott's <emphasis>Developer Workshop</emphasis>, February 2010.</simpara>\r
+       </abstract>\r
+       <section id="exploring_database_schema">\r
+               <title>Exploring the Database Schema</title>\r
+               <simpara>The database schema is tied pretty tightly to PostgreSQL. Although PostgreSQL<indexterm><primary>databases</primary><secondary>PostgreSQL</secondary></indexterm>\r
+               adheres closely to ANSI SQL standards, the use of schemas, SQL functions<indexterm><primary>ANSI</primary></indexterm>\r
+               implemented in both <systemitem>plpgsql</systemitem> and <systemitem>plperl</systemitem>, and PostgreSQL&#8217;s native full-text\r
+               search would make it&#8230; challenging&#8230; to port to other database platforms.</simpara>\r
+               <simpara>A few common PostgreSQL interfaces for poking around the schema and\r
+               manipulating data are:</simpara>\r
+               <itemizedlist>\r
+               <listitem>\r
+               <simpara>\r
+               psql (the command line client)<indexterm><primary>databases</primary><secondary>PostgreSQL</secondary><tertiery>psql</tertiery></indexterm>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               pgadminIII (a GUI client).<indexterm><primary>databases</primary><secondary>PostgreSQL</secondary><tertiery>pgadminIII</tertiery></indexterm>\r
+               </simpara>\r
+               </listitem>\r
+               </itemizedlist>\r
+               <simpara>Or you can read through the source files in <filename class="directoy">Open-ILS/src/sql/Pg</filename>.</simpara>\r
+               <simpara>Let&#8217;s take a quick tour through the schemas, pointing out some highlights\r
+               and some key interdependencies:</simpara>\r
+               <itemizedlist>\r
+               <listitem>\r
+               <simpara>\r
+               actor.org_unit &#8594; asset.copy_location\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               actor.usr &#8594; actor.card\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               biblio.record_entry &#8594; asset.call_number &#8594; asset.copy\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               config.metabib_field &#8594; metabib.*_field_entry\r
+               </simpara>\r
+               </listitem>\r
+               </itemizedlist>\r
+               This documentation also contains an Appendix for the Evergreen <xref linkend="databaseschema"/>.         \r
+       </section>\r
+       <section id="_database_access_methods">\r
+               <title>Database access methods</title>\r
+               <simpara>You could use direct access to the database via Perl DBI, JDBC, etc,\r
+               but Evergreen offers several database CRUD services for\r
+               creating / retrieving / updating / deleting data. These avoid tying\r
+               you too tightly to the current database schema and they funnel database\r
+               access through the same mechanism, rather than tying up connections\r
+               with other interfaces.</simpara>\r
+       </section>\r
+       <section id="_evergreen_interface_definition_language_idl">\r
+               <title>Evergreen Interface Definition Language (IDL)</title>\r
+               <indexterm><primary>Evergreen Interface Definition Language (IDL)</primary></indexterm>\r
+               <simpara>Defines properties and required permissions for Evergreen classes.\r
+               To reduce network overhead, a given object is identified via a\r
+               class-hint and serialized as a JSON array of properties (no named properties).</simpara>\r
+               <simpara>As of 1.6, fields will be serialized in the order in which they appear\r
+               in the IDL definition file, and the is_new / is_changed / is_deleted\r
+               properties are automatically added. This has greatly reduced the size of\r
+               the <literal>fm_IDL.xml</literal> file and makes DRY people happier :)</simpara>\r
+               <itemizedlist>\r
+               <listitem>\r
+               <simpara>\r
+               &#8230; oils_persist:readonly tells us, if true, that the data lives in the database, but is pulled from the SELECT statement defined in the &lt;oils_persist:source_definition&gt; \r
+               child element\r
+               </simpara>\r
+               </listitem>\r
+               </itemizedlist>\r
+               <simplesect id="_idl_basic_example_config_language_map">\r
+                       <title>IDL basic example (config.language_map)</title>\r
+<programlisting language="xml" linenumbering="unnumbered">\r
+&lt;class id="clm" controller="open-ils.cstore open-ils.pcrud"\r
+       oils_obj:fieldmapper="config::language_map"\r
+       oils_persist:tablename="config.language_map"\r
+       reporter:label="Language Map" oils_persist:field_safe="true"&gt; <co id="dmCO5-1"/> <co id="dmCO5-2"/> <co id="dmCO5-3"/> <co id="dmCO5-4"/>\r
+    &lt;fields oils_persist:primary="code" oils_persist:sequence=""&gt;  <co id="dmCO5-5"/>\r
+       &lt;field reporter:label="Language Code" name="code"\r
+           reporter:selector="value" reporter:datatype="text"/&gt; <co id="dmCO5-6"/>\r
+       &lt;field reporter:label="Language" name="value"\r
+           reporter:datatype="text" oils_persist:i18n="true"/&gt; <co id="dmCO5-7"/>\r
+    &lt;/fields&gt;\r
+    &lt;links/&gt;\r
+    &lt;permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1"&gt; <co id="dmCO5-8"/>\r
+       &lt;actions&gt;\r
+           &lt;create global_required="true" permission="CREATE_MARC_CODE"&gt; <co id="dmCO5-9"/>\r
+           &lt;retrieve global_required="true"\r
+               permission="CREATE_MARC_CODE UPDATE_MARC_CODE DELETE_MARC_CODE"&gt;\r
+           &lt;update global_required="true" permission="UPDATE_MARC_CODE"&gt;\r
+           &lt;delete global_required="true" permission="DELETE_MARC_CODE"&gt;\r
+       &lt;/actions&gt;\r
+    &lt;/permacrud&gt;\r
+&lt;/class&gt;\r
+</programlisting>\r
+                       <calloutlist>\r
+                       <callout arearefs="dmCO5-1">\r
+                       <simpara>\r
+                       The <literal>class</literal> element defines the attributes and permissions for classes,\r
+                       and relationships between classes.\r
+                       </simpara>\r
+                       <indexterm><primary>Evergreen Interface Definition Language (IDL)</primary><secondary>class element</secondary></indexterm>\r
+                       <itemizedlist>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>id</literal> attribute on the <literal>class</literal> element defines the class hint that is\r
+                       used everywhere in Evergreen.\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>controller</literal> attribute defines the OpenSRF\r
+                       services that provide access to the data for the class objects.\r
+                       </simpara>\r
+                       </listitem>\r
+                       </itemizedlist>\r
+                       </callout>\r
+                       <callout arearefs="dmCO5-2">\r
+                       <simpara>\r
+                       The <literal>oils_obj::fieldmapper</literal> attribute defines the name of the class that\r
+                       is generated by <literal>OpenILS::Utils::Fieldmapper</literal>.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO5-3">\r
+                       <simpara>\r
+                       The <literal>oils_persist:tablename</literal> attribute defines the name of the table\r
+                       that contains the data for the class objects.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO5-4">\r
+                       <simpara>\r
+                       The reporter interface uses <literal>reporter:label</literal> attribute values in\r
+                       the source list to provide meaningful class and attribute names. The\r
+                       <literal>open-ils.fielder</literal> service generates a set of methods that provide direct\r
+                       access to the classes for which <literal>oils_persist:field_safe</literal> is <literal>true</literal>. For\r
+                       example,\r
+                       </simpara>\r
+<screen>\r
+<userinput>\r
+srfsh# request open-ils.fielder open-ils.fielder.clm.atomic \\r
+{"query":{"code":{"=":"eng"}}}\r
+\r
+Received Data: [\r
+       {\r
+       "value":"English",\r
+       "code":"eng"\r
+       }\r
+]\r
+</userinput>\r
+</screen>\r
+                       </callout>\r
+                       <callout arearefs="dmCO5-5">\r
+                       <simpara>\r
+                       The <literal>fields</literal> element defines the list of fields for the class.\r
+                       </simpara>\r
+                       <indexterm><primary>Evergreen Interface Definition Language (IDL)</primary><secondary>fields element</secondary></indexterm>\r
+                       <itemizedlist>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>oils_persist:primary</literal> attribute defines the column that acts as\r
+                       the primary key for the table.\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>oils_persist:sequence</literal> attribute holds the name of the database\r
+                       sequence.\r
+                       </simpara>\r
+                       </listitem>\r
+                       </itemizedlist>\r
+                       </callout>\r
+                       <callout arearefs="dmCO5-6">\r
+                       <simpara>\r
+                       Each <literal>field</literal> element defines one property of the class.\r
+                       </simpara>\r
+                       <indexterm><primary>Evergreen Interface Definition Language (IDL)</primary><secondary>field element</secondary></indexterm>\r
+                       <itemizedlist>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>name</literal> attribute defines the getter/setter method name for the field.\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>reporter:label</literal> attribute defines the attribute name as used in\r
+                       the reporter interface.\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>reporter:selector</literal> attribute defines the field used in the reporter\r
+                       filter interface to provide a selectable list. This gives the user a more\r
+                       meaningful access point than the raw numeric ID or abstract code.\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>reporter:datatype</literal> attribute defines the type of data held by\r
+                       this property for the purposes of the reporter.\r
+                       </simpara>\r
+                       </listitem>\r
+                       </itemizedlist>\r
+                       </callout>\r
+                       <callout arearefs="dmCO5-7">\r
+                       <simpara>\r
+                       The <literal>oils_persist:i18n</literal> attribute, when <literal>true</literal>, means that\r
+                       translated values for the field&#8217;s contents may be accessible in\r
+                       different locales.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO5-8">\r
+                       <simpara>\r
+                       <indexterm><primary>Evergreen Interface Definition Language (IDL)</primary><secondary>permacrud element</secondary></indexterm>\r
+                       The <literal>permacrud</literal> element defines the permissions (if any) required\r
+                       to <emphasis role="strong">c</emphasis>reate, <emphasis role="strong">r</emphasis>etrieve, <emphasis role="strong">u</emphasis>pdate, \r
+                       and <emphasis role="strong">d</emphasis>elete data for this\r
+                       class. <literal>open-ils.permacrud</literal> must be defined as a controller for the class\r
+                       for the permissions to be applied.\r
+                       </simpara>\r
+                       \r
+                       </callout>\r
+                       <callout arearefs="dmCO5-9">\r
+                       <simpara>\r
+                       Each action requires one or more <literal>permission</literal> values that the\r
+                       user must possess to perform the action.\r
+                       </simpara>\r
+                       <itemizedlist>\r
+                       <listitem>\r
+                       <simpara>\r
+                       If the <literal>global_required</literal> attribute is <literal>true</literal>, then the user must\r
+                       have been granted that permission globally (depth = 0) to perform\r
+                       the action.\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       The <literal>context_field</literal> attribute denotes the <literal>&lt;field&gt;</literal> that identifies\r
+                       the org_unit at which the user must have the pertinent permission.\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <indexterm><primary>Evergreen Interface Definition Language (IDL)</primary><secondary>action element</secondary></indexterm>\r
+                       <simpara>\r
+                       An action element may contain a <literal>&lt;context_field&gt;</literal> element that\r
+                       defines the linked class (identified by the <literal>link</literal> attribute) and\r
+                       the field in the linked class that identifies the org_unit where\r
+                       the permission must be held.\r
+                       </simpara>\r
+                       <itemizedlist>\r
+                       <listitem>\r
+                       <indexterm><primary>Evergreen Interface Definition Language (IDL)</primary><secondary>context_field element</secondary></indexterm>\r
+                       <simpara>\r
+                       If the <literal>&lt;context_field&gt;</literal> element contains a <literal>jump</literal> attribute,\r
+                       then it defines a link to a link to a class with a field identifying\r
+                       the org_unit where the permission must be held.\r
+                       </simpara>\r
+                       </listitem>\r
+                       </itemizedlist>\r
+                       </listitem>\r
+                       </itemizedlist>\r
+                       </callout>\r
+                       </calloutlist>\r
+               </simplesect>\r
+               <simplesect id="_reporter_data_types_and_their_possible_values">\r
+                       <title>Reporter data types and their possible values</title>\r
+                       <itemizedlist>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>bool</literal>: Boolean <literal>true</literal> or <literal>false</literal>\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>id</literal>: ID of the row in the database\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>int</literal>: integer value\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>interval</literal>: PostgreSQL time interval\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>link</literal>: link to another class, as defined in the <literal>&lt;links&gt;</literal>\r
+                       element of the class definition\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>money</literal>: currency amount\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>org_unit</literal>: list of org_units\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>text</literal>: text value\r
+                       </simpara>\r
+                       </listitem>\r
+                       <listitem>\r
+                       <simpara>\r
+                       <literal>timestamp</literal>: PostgreSQL timestamp\r
+                       </simpara>\r
+                       </listitem>\r
+                       </itemizedlist>\r
+               </simplesect>\r
+               <simplesect id="_idl_example_with_linked_fields_actor_workstation">\r
+                       <title>IDL example with linked fields (actor.workstation)</title>\r
+                       <simpara>Just as tables often include columns with foreign keys that point\r
+                       to values stored in the column of a different table, IDL classes\r
+                       can contain fields that link to fields in other classes. The <literal>&lt;links&gt;</literal>\r
+                       element defines which fields link to fields in other classes, and\r
+                       the nature of the relationship:</simpara>\r
+<programlisting language="xml" linenumbering="unnumbered">\r
+&lt;class id="aws" controller="open-ils.cstore"\r
+       oils_obj:fieldmapper="actor::workstation"\r
+       oils_persist:tablename="actor.workstation"\r
+       reporter:label="Workstation"&gt;\r
+    &lt;fields oils_persist:primary="id"\r
+           oils_persist:sequence="actor.workstation_id_seq"&gt;\r
+       &lt;field reporter:label="Workstation ID" name="id"\r
+               reporter:datatype="id"/&gt;\r
+       &lt;field reporter:label="Workstation Name" name="name"\r
+               reporter:datatype="text"/&gt;\r
+       &lt;field reporter:label="Owning Library" name="owning_lib"\r
+               reporter:datatype="org_unit"/&gt;\r
+       &lt;field reporter:label="Circulations" name="circulations"\r
+               oils_persist:virtual="true" reporter:datatype="link"/&gt; <co id="dmCO6-1"/>\r
+    &lt;/fields&gt;\r
+    &lt;links&gt;  <co id="dmCO6-2"/>\r
+       &lt;link field="owning_lib" reltype="has_a" key="id"\r
+               map="" class="aou"/&gt;  <co id="dmCO6-3"/>\r
+       &lt;link field="circulations" reltype="has_many" key="workstation"\r
+               map="" class="circ"/&gt;\r
+       &lt;link field="circulation_checkins" reltype="has_many"\r
+               key="checkin_workstation" map="" class="circ"/&gt;\r
+    &lt;/links&gt;\r
+&lt;/class&gt;\r
+</programlisting>\r
+                       <calloutlist>\r
+                       <callout arearefs="dmCO6-1">\r
+                       <simpara>\r
+                       This field includes an <literal>oils_persist:virtual</literal> attribute with the value of\r
+                       <literal>true</literal>, meaning that the linked class <literal>circ</literal> is a virtual class.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO6-2">\r
+                       <simpara>\r
+                       The <literal>&lt;links&gt;</literal> element contains 0 or more <literal>&lt;link&gt;</literal> elements.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO6-3">\r
+                       <simpara>\r
+                       Each <literal>&lt;link&gt;</literal> element defines the field (<literal>field</literal>) that links to a different\r
+                       class (<literal>class</literal>), the relationship (<literal>rel_type</literal>) between this field and the target\r
+                       field (<literal>key</literal>). If the field in this class links to a virtual class, the (<literal>map</literal>)\r
+                       attribute defines the field in the target class that returns a list of matching\r
+                       objects for each object in this class.\r
+                       </simpara>\r
+                       </callout>\r
+                       </calloutlist>\r
+               </simplesect>\r
+       </section>\r
+       <section id="open_ils_cstore_literal_data_access_interfaces">\r
+               <title><literal>open-ils.cstore</literal> data access interfaces</title>\r
+               <indexterm><primary>cstore</primary></indexterm>\r
+               <simpara>For each class documented in the IDL, the <literal>open-ils.cstore</literal> service\r
+               automatically generates a set of data access methods, based on the\r
+               <literal>oils_persist:tablename</literal> class attribute.</simpara>\r
+               <simpara>For example, for the class hint <literal>clm</literal>, cstore generates the following\r
+               methods with the <literal>config.language_map</literal> qualifer:</simpara>\r
+               <itemizedlist>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.direct.config.language_map.id_list {"code" { "like": "e%" } }</literal>\r
+               </simpara>\r
+               <simpara>Retrieves a list composed only of the IDs that match the query.</simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.direct.config.language_map.retrieve "eng"</literal>\r
+               </simpara>\r
+               <simpara>Retrieves the object that matches a specific ID.</simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.direct.config.language_map.search {"code" : "eng"}</literal>\r
+               </simpara>\r
+               <simpara>Retrieves a list of objects that match the query.</simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.direct.config.language_map.create &lt;_object_&gt;</literal>\r
+               </simpara>\r
+               <simpara>Creates a new object from the passed in object.</simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.direct.config.language_map.update &lt;_object_&gt;</literal>\r
+               </simpara>\r
+               <simpara>Updates the object that has been passed in.</simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.direct.config.language_map.delete "eng"</literal>\r
+               </simpara>\r
+               <simpara>Deletes the object that matches the query.</simpara>\r
+               </listitem>\r
+               </itemizedlist>\r
+       </section>\r
+       <section id="_open_ils_pcrud_data_access_interfaces">\r
+               <title>open-ils.pcrud data access interfaces</title>\r
+               <indexterm><primary>pcrud</primary></indexterm>\r
+               <simpara>For each class documented in the IDL, the <literal>open-ils.pcrud</literal> service\r
+               automatically generates a set of data access methods, based on the\r
+               <literal>oils_persist:tablename</literal> class attribute.</simpara>\r
+               <simpara>For example, for the class hint <literal>clm</literal>, <literal>open-ils.pcrud</literal> generates the following\r
+               methods that parallel the <literal>open-ils.cstore</literal> interface:</simpara>\r
+               <itemizedlist>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.id_list.clm &lt;_authtoken_&gt;, { "code": { "like": "e%" } }</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.retrieve.clm &lt;_authtoken_&gt;, "eng"</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.search.clm &lt;_authtoken_&gt;, { "code": "eng" }</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.create.clm &lt;_authtoken_&gt;, &lt;_object_&gt;</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.update.clm &lt;_authtoken_&gt;, &lt;_object_&gt;</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.delete.clm &lt;_authtoken_&gt;, "eng"</literal>\r
+               </simpara>\r
+               </listitem>\r
+               </itemizedlist>\r
+       </section>\r
+       <section id="_transaction_and_savepoint_control">\r
+               <title>Transaction and savepoint control</title>\r
+               <simpara>Both <literal>open-ils.cstore</literal> and <literal>open-ils.pcrud</literal> enable you to control database transactions\r
+               to ensure that a set of operations either all succeed, or all fail,\r
+               atomically:</simpara>\r
+               <itemizedlist>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.transaction.begin</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.transaction.commit</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.transaction.rollback</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.transaction.begin</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.transaction.commit</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.transaction.rollback</literal>\r
+               </simpara>\r
+               </listitem>\r
+               </itemizedlist>\r
+               <simpara>At a more granular level, <literal>open-ils.cstore</literal> and <literal>open-ils.pcrud</literal> enable you to set database\r
+               savepoints to ensure that a set of operations either all succeed, or all\r
+               fail, atomically, within a given transaction:</simpara>\r
+               <itemizedlist>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.savepoint.begin</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.savepoint.commit</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.cstore.savepoint.rollback</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.savepoint.begin</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.savepoint.commit</literal>\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               <literal>open-ils.pcrud.savepoint.rollback</literal>\r
+               </simpara>\r
+               </listitem>\r
+               </itemizedlist>\r
+               <simpara>Transactions and savepoints must be performed within a stateful\r
+               connection to the <literal>open-ils.cstore</literal> and <literal>open-ils.pcrud</literal> services.\r
+               In <literal>srfsh</literal>, you can open a stateful connection using the <literal>open</literal>\r
+               command, and then close the stateful connection using the <literal>close</literal>\r
+               command - for example:</simpara>\r
+               <screen>srfsh# open open-ils.cstore\r
+               ... perform various transaction-related work\r
+               srfsh# close open-ils.cstore</screen>\r
+               <simplesect id="_json_queries">\r
+                       <title>JSON Queries</title>\r
+                       <indexterm><primary>JSON</primary></indexterm>\r
+                       <simpara>Beyond simply retrieving objects by their ID using the <literal>\*.retrieve</literal>\r
+                       methods, you can issue queries against the <literal>\*.delete</literal> and <literal>\*.search</literal>\r
+                       methods using JSON to filter results with simple or complex search\r
+                       conditions.</simpara>\r
+                       <simpara>For example, to generate a list of barcodes that are held in a\r
+                       copy location that allows holds and is visible in the OPAC:</simpara>\r
+<programlisting language="sh" linenumbering="unnumbered">\r
+srfsh# request open-ils.cstore open-ils.cstore.json_query  <co id="dmCO7-1"/>\r
+    {"select": {"acp":["barcode"], "acpl":["name"]}, <co id="dmCO7-2"/>\r
+     "from":   {"acp":"acpl"},   <co id="dmCO7-3"/>\r
+     "where":  [     <co id="dmCO7-4"/>\r
+        {"+acpl": "holdable"},   <co id="dmCO7-5"/>\r
+        {"+acpl": "opac_visible"}     <co id="dmCO7-6"/>\r
+     ]}\r
+\r
+Received Data: {\r
+  "barcode":"BARCODE1",\r
+  "name":"Stacks"\r
+}\r
+\r
+Received Data: {\r
+  "barcode":"BARCODE2",\r
+  "name":"Stacks"\r
+}\r
+</programlisting>\r
+                       <calloutlist>\r
+                       <callout arearefs="dmCO7-1">\r
+                       <simpara>\r
+                       Invoke the <literal>json_query</literal> service.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO7-2">\r
+                       <simpara>\r
+                       Select the <literal>barcode</literal> field from the <literal>acp</literal> class and the <literal>name</literal>\r
+                       field from the <literal>acpl</literal> class.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO7-3">\r
+                       <simpara>\r
+                       Join the <literal>acp</literal> class to the <literal>acpl</literal> class based on the linked field\r
+                       defined in the IDL.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO7-4">\r
+                       <simpara>\r
+                       Add a <literal>where</literal> clause to filter the results. We have more than one\r
+                       condition beginning with the same key, so we wrap the conditions inside\r
+                       an array.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO7-5">\r
+                       <simpara>\r
+                       The first condition tests whether the boolean value of the <literal>holdable</literal>\r
+                       field on the <literal>acpl</literal> class is true.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO7-6">\r
+                       <simpara>\r
+                       The second condition tests whether the boolean value of the\r
+                       <literal>opac_visible</literal> field on the <literal>acpl</literal> class is true.\r
+                       </simpara>\r
+                       </callout>\r
+                       </calloutlist>\r
+                       <simpara>For thorough coverage of the breadth of support offered by JSON\r
+                       query syntax, see <ulink url="http://open-ils.org/dokuwiki/doku.php?id=documentation:technical:jsontutorial">JSON Queries: A Tutorial</ulink>.</simpara>\r
+               </simplesect>\r
+               <simplesect id="_fleshing_linked_objects">\r
+                       <title>Fleshing linked objects</title>\r
+                       <simpara>A simplistic approach to retrieving a set of objects that are linked to\r
+                       an object that you are retrieving - for example, a set of call numbers\r
+                       linked to the barcodes that a given user has borrowed - would be to:\r
+                         1. Retrieve the list of circulation objects (<literal>circ</literal> class)\r
+                       for a given user (<literal>usr</literal> class).\r
+                         2. For each circulation object, look up the target copy (<literal>target_copy</literal>\r
+                       field, linked to the <literal>acp</literal> class).\r
+                         3. For each copy, look up the call number for that copy (<literal>call_number</literal>\r
+                       field, linked to the <literal>acn</literal> class).</simpara>\r
+                       <simpara>However, this would result in potentially hundreds of round-trip\r
+                       queries from the client to the server. Even with low-latency connections,\r
+                       the network overhead would be considerable. So, built into the <literal>open-ils.cstore</literal> and\r
+                       <literal>open-ils.pcrud</literal> access methods is the ability to <emphasis>flesh</emphasis> linked fields -\r
+                       that is, rather than return an identifier to a given linked field,\r
+                       the method can return the entire object as part of the initial response.</simpara>\r
+                       <simpara>Most of the interfaces that return class instances from the IDL offer the\r
+                       ability to flesh returned fields. For example, the\r
+                       <literal>open-ils.cstore.direct.\*.retrieve</literal> methods allow you to specify a\r
+                       JSON structure defining the fields you wish to flesh in the returned object.</simpara>\r
+                       <formalpara><title>Fleshing fields in objects returned by <literal>open-ils.cstore</literal></title><para>\r
+<programlisting language="sh" linenumbering="unnumbered">\r
+srfsh# request open-ils.cstore open-ils.cstore.direct.asset.copy.retrieve 1, \\r
+    {\r
+       "flesh": 1,    <co id="dmCO8-1"/>\r
+       "flesh_fields": {   <co id="dmCO8-2"/>\r
+           "acp": ["location"]\r
+       }\r
+    }\r
+</programlisting>\r
+                       </para></formalpara>\r
+                       <calloutlist>\r
+                       <callout arearefs="dmCO8-1">\r
+                       <simpara>\r
+                       The <literal>flesh</literal> argument is the depth at which objects should be fleshed.\r
+                       For example, to flesh out a field that links to another object that includes\r
+                       a field that links to another object, you would specify a depth of 2.\r
+                       </simpara>\r
+                       </callout>\r
+                       <callout arearefs="dmCO8-2">\r
+                       <simpara>\r
+                       The <literal>flesh_fields</literal> argument contains a list of objects with the fields\r
+                       to flesh for each object.\r
+                       </simpara>\r
+                       </callout>\r
+                       </calloutlist>\r
+                       <simpara>Let&#8217;s flesh things a little deeper. In addition to the copy location,\r
+                       let&#8217;s also flesh the call number attached to the copy, and then flesh\r
+                       the bibliographic record attached to the call number.</simpara>\r
+                       <formalpara><title>Fleshing fields in fields of objects returned by <literal>open-ils.cstore</literal></title><para>\r
+<programlisting language="java" linenumbering="unnumbered">\r
+request open-ils.cstore open-ils.cstore.direct.asset.copy.retrieve 1, \\r
+    {\r
+       "flesh": 2,\r
+       "flesh_fields": {\r
+           "acp": ["location", "call_number"],\r
+           "acn": ["record"]\r
+        }\r
+    }\r
+</programlisting>\r
+                       </para></formalpara>\r
+               </simplesect>\r
+       </section>\r
+       <section id="_adding_an_idl_entry_for_resolverresolver">\r
+               <title>Adding an IDL entry for ResolverResolver</title>\r
+               <simpara>Most OpenSRF methods in Evergreen define their object interface in the\r
+               IDL. Without an entry in the IDL, the prospective caller of a given\r
+               method is forced to either call the method and inspect the returned\r
+               contents, or read the source to work out the structure of the JSON\r
+               payload. At this stage of the tutorial, we have not defined an entry\r
+               in the IDL to represent the object returned by the\r
+               <literal>open-ils.resolver.resolve_holdings</literal> method. It is time to complete\r
+               that task.</simpara>\r
+               <simpara>The <literal>open-ils.resolver</literal> service is unlike many of the other classes\r
+               defined in the IDL because its data is not stored in the Evergreen\r
+               database. Instead, the data is requested from an external Web service\r
+               and only temporarily cached in <literal>memcached</literal>. Fortunately, the IDL\r
+               enables us to represent this kind of class by setting the\r
+               <literal>oils_persist:virtual</literal> class attribute to <literal>true</literal>.</simpara>\r
+               <simpara>So, let&#8217;s add an entry to the IDL for the <literal>open-ils.resolver.resolve_holdings</literal>\r
+               service:</simpara>\r
+               <programlisting language="xml" linenumbering="unnumbered"></programlisting>\r
+               <simpara>And let&#8217;s make <literal>ResolverResolver.pm</literal> return an array composed of our new\r
+               <literal>rhr</literal> classes rather than raw JSON objects:</simpara>\r
+               <programlisting language="perl" linenumbering="unnumbered"></programlisting>\r
+               <simpara>Once we add the new entry to the IDL and copy the revised <literal>ResolverResolver.pm</literal>\r
+               Perl module to <literal>/openils/lib/perl5/OpenILS/Application/</literal>, we need to:</simpara>\r
+               <orderedlist numeration="arabic">\r
+               <listitem>\r
+               <simpara>\r
+               Copy the updated IDL to both the <literal>/openils/conf/</literal> and\r
+               <literal>/openils/var/web/reports/</literal> directories. The Dojo approach to\r
+               parsing the IDL uses the IDL stored in the reports directory.\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               Restart the Perl services to make the new IDL visible to the services\r
+               and refresh the <literal>open-ils.resolver</literal> implementation\r
+               </simpara>\r
+               </listitem>\r
+               <listitem>\r
+               <simpara>\r
+               Rerun <filename>/openils/bin/autogen.sh</filename> to regenerate the JavaScript versions<indexterm><primary>autogen</primary></indexterm>\r
+               of the IDL required by the HTTP translator and gateway.\r
+               </simpara>\r
+               </listitem>\r
+               </orderedlist>\r
+               <simpara>We also need to adjust our JavaScript client to use the nifty new<indexterm><primary>JavaScript</primary></indexterm>\r
+               objects that <literal>open-ils.resolver.resolve_holdings</literal> now returns.\r
+               The best approach is to use the support in Evergreen&#8217;s Dojo extensions<indexterm><primary>Dojo toolkit</primary></indexterm>\r
+               to generate the JavaScript classes directly from the IDL XML file.</simpara>\r
+               <formalpara><title>Accessing classes defined in the IDL via Fieldmapper</title><para>\r
+               <programlisting language="html" linenumbering="unnumbered"></programlisting>\r
+               </para></formalpara>\r
+               <calloutlist>\r
+               <callout arearefs="">\r
+               <simpara>\r
+               Load the Dojo core.\r
+               </simpara>\r
+               </callout>\r
+               <callout arearefs="">\r
+               <simpara>\r
+               <literal>fieldmapper.AutoIDL</literal> reads <filename>/openils/var/reports/fm_IDL.xml</filename> to\r
+               generate a list of class properties.\r
+               </simpara>\r
+               </callout>\r
+               <callout arearefs="">\r
+               <simpara>\r
+               <literal>fieldmapper.dojoData</literal> seems to provide a store for Evergreen data\r
+               accessed via Dojo.\r
+               </simpara>\r
+               </callout>\r
+               <callout arearefs="">\r
+               <simpara>\r
+               <literal>fieldmapper.Fieldmapper</literal> converts the list of class properties into\r
+               actual classes.\r
+               </simpara>\r
+               </callout>\r
+               <callout arearefs="">\r
+               <simpara>\r
+               <literal>fieldmapper.standardRequest</literal> invokes an OpenSRF method and returns\r
+               an array of objects.\r
+               </simpara>\r
+               </callout>\r
+               <callout arearefs="">\r
+               <simpara>\r
+               The first argument to <literal>fieldmapper.standardRequest</literal> is an array\r
+               containing the OpenSRF service name and method name.\r
+               </simpara>\r
+               </callout>\r
+               <callout arearefs="">\r
+               <simpara>\r
+               The second argument to <literal>fieldmapper.standardRequest</literal> is an array\r
+               containing the arguments to pass to the OpenSRF method.\r
+               </simpara>\r
+               </callout>\r
+               <callout arearefs="">\r
+               <simpara>\r
+               As Fieldmapper has instantiated the returned objects based on their\r
+               class hints, we can invoke getter/setter methods on the objects.\r
+               </simpara>\r
+               </callout>\r
+               </calloutlist>\r
+       </section>\r
+       \r
+</chapter>\r