OiRc-0004 The library system revisited
A few years later, in 2002, while I was recuperating from the effects of 9/11 and the devastation wrought on the buildings that were literally my next door neighbours, I had a chance to revisit the Library system and come up with a better definition for the object model.
I was still cogitating; mulling over the real impact of relationships on software design. Like a dutiful son, I was going back to the family business and mining it for the nuggets of insight in what was after all familiar ground.
I was beginning to come to grips with Relationships.
Once again, I return to my wiki.
An Object model
This is where every Class and the hierarchy of every Class is defined and every Relationships is defined.
Functionally the definitions are:
- every instantiable class shall define class methods to:
- new() return a new empty intance of itself.
- fromXMLString( aString ) return a new instance of itself filled with aString
- fromDatabase( aDatabase, aTable, aKey ) return a new instance of itself filled with a row returned data obtained by query against aDataBase in aTable for aKey.
- radixTable( aTableSymbolString, aLanguageRadix) answer any radixed value sets (array of labels) to associate aTableSymbolString, aRadix with a string value. The defaults are hardcoded English and internationalization will be handled by an internationalizationTable where sets named aTableSymbolName are stored in the table as aTableSymbolName, languageRadix, setRadix => aString.metadata
- slotLabel( aLanguageRadix, slotName) answers a label for a slot named aSlotNamed in language aLanguageRadix. The defaults are hardcoded English and internationalization will be handled by an internationalizationTable where slot named className, slotName, languageRadix => aString.metadata
- every instantiable class shall define instance methods to:
- get
() its constituent slots - get(
) its constituent slots - set
( aValue ) its constituent slots - set(
, aValue) its constituent slots - asXMLString() return itself as an XML string
- asTable(aLanguageRadix) returns itself for interaction as a table with its rows with each slot defined as one datumLabelStyle, slotLabel(slotLabel, aLanguageRadix)datumValueStyle, value row per slot and
- one col spanned subtable for any instantiableFragment.
- fromTable(aTable) fills its slots with the contents of aTable. The table is the same as would have been answered by asTable()
- asTableRows(aLanguageRadix) returns itself for display as a table rows.
- one datumLabelStyle, slotLabel(slotLabel, aLanguageRadix)datumValueStyle, value row per slot. If the slot is a compound instantiableFagment, it will be asked to answer itself asTableRows(aLanguageRadix).
Structurally the definitions are:
InstantiableFragment
- objects can be instantiated but have no independent existence. They are only have meaning when embedded within other object instances.
Superclass: Object Instance Variables are:
- NONE
The following classes are subclasses of InstantiableFragment:
Amount
- objects define the monetary cost or value of an object
Superclass: Object Instance GVariables are:
- currencyID Integer(3) radix of an item in a CurrencyTable
- currency String(14) is the currencyID is nil
- date Date
- amount FixedDecimal(14) the quantity of specie involved.
RecordID
- objects define how the entire system handles uniqueness identifiers.
Superclass: InstantiableFragment Instance Variables are:
DateTimeStamp
- objects record the date and time of an event such as record creation, update, deletion, or state change.
Superclass: InstantiableFragment Instance Variables are:
- date Date (yyyymmdd)
- time Time (hhmmsstht)
Operator
- objects record the ID of the agent that created, updated, deleted a record or caused a state change. The ID can be that of a human being or of a batch process. They are stored in a CRUDE table
Superclass: InstantiableFragment Instance Variables are:
- operatorID String(14)
- memberID RecordID the ID of any member human agent
Address
- objects record the position in space of an object
Superclass: InstantiableFragment Instance Variables are:
- countryID Integer(3) radix of item in a CountryTable
- countryName String(64) name of the country if radix is nil
- postalID String(16) depending on the countryID this is variously called a ZIP Code, PostalCode, Code Postal or some other nmemonic.
- firstDivision String(64) depending on the countryID this is variously called a State, Province, Prefecture, Departement or some other geopolitical boundary
- secondDivision String(64) depending on the countryID this may be ommitted of refers to a county or other geopolitical boundary.
- city String(64) name of the city of residence
- streetName String(64) coarse grained postal service location marker
- streetNumber String(64) fine grained postal service location marker
- internalRoute String(64) internal routing post postal delivery mechanism
- homePhone String(32)
- workPhone String(32)
- homeFax String(32)
- workFax String(32)
- homeEMail String(64)
- workEMail String(64)
Name
- objects record the human nmemonic identifier of an object
Superclass: InstantiableFragment Instance Variables are:
- 1=> Mr.
- 2=> Mrs.
- 3=> Ms.
- 4=> Lord ...
- salutation String(12) if salutationID is nil
- nameType Integer(1)
- lastName String(64) patronimic or or corporation name
- firstName String(64) filionimic
- middleInitial String(16) (may be Band Number for Amerinds)
- suffixID Integer(2) radix of item in a SuffixTable
- 1=> Esq.
- 2=> 2nd.
- 3=> 3rd.
- 4=> 4th. ...
- suffix String(16) if suffixID is nil.
Abstract classes
ModelObject
- objects are abstract (uninstantiable) objects that define structure and behavior for their subclasses. They define the relationship between objects and the table that stores them.
Superclass: Object Instance Variables are:
- uniqueID RecordID
- createDTS DateTimeStamp
- createOID OperatorID
- updateDTS DateTimeStamp
- updateOID OperatorID
- deleteDTS DateTimeStamp
- deleteOID OperatorID
- objectID String(14) name of the object Class for reinstantiation from persistent store
- tableName String(14) name of the table where a persistent copy of the object is/will be stored
- nmemonic String(255) human readable nmemonic device.
- description String(1024) human readable description of the object
Concrete classes
Location
- object is a point in space time where an Entity can be found.
Superclass: ModelObject Instance Variables are:
- locationID RecordID
- address Address
- effectiveFrom Date nil implies since record creation
- when the date is partial, this implies a cyclic relocation
- effectiveUntil Date nil implies forever
Entity
- object is a person or corporation
Superclass: ModelObject Instance Variables are:
- 1=> Library
- 2=> Member
- 3=> Supplier
- 4=> Publisher
- 5=> Operator
- role String(12) if roleID is nil
Library
- object is the library itself
Superclass: ModelObject Instance Variables are:
- entityID RecordID
- sic String(16) Standard Industry Code
- tin String(16) Tax ID Number
Acquisition
- object is any item acquired for the purposes of presentation or circulation
Superclass: ModelObject Instance Variables are:
- the uniquenessID is known as an accession number
- content String(1024) This may be a CSV string which can be parsed further
- costOfPurchase Amount the price paid to acquire the object
- costOfReplacement Amount the price which would be paid to replace the objec
- Circulatable Boolean
- True=> this acquisition can leave the library premises
- False=> For viewing in reference section only
Member
- object can play service recipient roles in circulation
Superclass: ModelObject Instance Variables are:
- the uniquenessID is known as a membership number
- entityID RecordID
- since Date
- renewalDue Date
- outstandingFines Amount
Catalogue
- object describe any identical accessions
Superclass: ModelObject Instance Variables are:
- the uniquenessID is known as a card image number for historical reasons
- cardImage String(2028) contains the catalog card/entry image
- typeID Integer(2) radix into a TypeTable
- 1=> Book
- 2=> Periodical
- 3=> Manuscript
- 4=> Audio Tape
- 5=> Audio CD
- 6=> URL
- type String(12) is typeID is nil
- externalID String(16) ISBN, ISSN, UPC or other real world designation
- publicationLocation Address
- publicationDate Date
- metric Integer(5) # of pages, running time or other indication of heft
- dimensions String(64) physical/spacial dimensions, if applicable
- summary String(64) may de redundant?
- accompanyingMaterialID Integer(2) radix into a MaterialTable
- 1=> ?
- accompanyingMaterial String(12) is accompanyingMaterialID is nil
Category
- object describes the search taxonomy
Superclass: ModelObject Instance Variables are:
- superCategory RecordID (optimization feature only)
- the mnemonic is the category name
- subcategories are dynamically constructed and cached in a single structure
Keyword
- object provides indexes into the search space
Superclass: ModelObject Instance Variables are:
- the mnemonic is the keyword
index
- object provides links between keywords and the search taxonomy
Superclass: ModelObject Instance Variables are:
- taxonomyID RecordID of the category
- keywordID RecordID of the keyword
Relationships
These define the articulations of the library system and provide for its functionality.
In case you're wondering these are index tables. In many database systems they would be defined as external keys and stored with the objects (a Fourth Normal Form no no but a good idea for quick relationship reconstruction after crashes.)
For our purposes, we will define one table per relationship and store connections in rows consisting of the owner objectID, row RecordID, member objectID, row RecordID.
This system had been remarkable for being defined without any participation sort order and this perhaps might need to be addressed. The sort information (one or more member slot name and collating sequence,) is defined in the relationship and the specific values are stored in-fixed between the owner data and the member data in the connection row.
Relational integrity is maintained very simply by sweeping through the indexes looking for connection rows where an object might have been participating in a relationship and deleting the connections. If recessary, the object referred to would also be deleted (recursively calling the delete routine,) before executing the actual deletion of the connection.
All relationships are subclasses of the generic Relationship class and all connections are instances of the generic Connection class.
The methods of the Connection class are markably simple.
Connection
- object provides links between persistent object instances
Superclass: Object Instance Variables are:
- connectionID RecordID
- relationshipID Integer radix identifying the connection class
- ownerID RecordID
- orderString String
- member ID RecordID
class method:
- connect: anObject to: anotherObject via: aRelationship
instance method:
- disconnect via aRelationship
EntityN-m-:isWhere:M--Location
- define the, possibly periodic, position in space/time of any entity or group of entities such as a family. It should be deleted when deleting the last entity at that location.
Library1-m-:is:1-d-Entity
- defines the library entity, its deleted with the library (entity should be a library.)
Member1-m-:is:1-d-Entity
- defines the member entity, its deleted with the member (entity should be a member.)
- birthDate Date
- adhesionDate Date
- schoolGrade
- schoolTeacher
Library1-m-:holding:0N--Acquisition
- defines a library's holdings
Member1-m-:familyGroup:0N--Member
- defines family groups of members
Member0N-m:reservation:0M--Catalogue
- defines the reservation of (m)any catalogue item. The limit on the number of links from any member (max reservations by a member) or from any catalogue item (max reservation before we stop trying to enforce them) is a matter of policy.
Member01-m-:onLoan:0N--Acquisition
- defines the loan of acquisitions to members. The entire system is being evolved to maintain this information. Strangely enough its not even worth its own independent object. Its a valued connection node. The limit on the number of link from any member (max loans) is a matter of policy. Just to keep things interesting and on the cutting edge (see AdvancedRelationshipTheory), these connections carry data:
- loanDate Date on which the acquisition was circulated.
- dueDate Date by which the acquisition is supposed to be returned.
- returnDate Date on which the acquisition was returned.
- loanState radix into LoanStateMachine.
Acquisition1--:supplier:N--Entity
- defines the supplier of the acquisition (entity should be a supplier.)
Acquisition1--:author:N--Entity
- defines the author of the acquisition (entity should be an author.)
Catalog0N--:publisher:1-m-Entity
- defines the publisher of the catalog item (entity should be a publisher.)
Catalog0N-m-:classification:0N--Acquisition
- defines the classication of a holding. There can be many copies of the same item
Category01-m-:taxonomy:0N--Category
- defines the hierarchy of categories. (virtual relationship as the actual taxonomy is re-aggragated into dynamically constructed and cached single structure)
Category1-m-:catPivot:0N-d-index
- defines the category-keyword search space
Keyword1-m-:keyPivot:0N-d-index
- defines the keyword-category search space
Something I have to date neglected in the definition and use of state machines to describe
- Entity: birthday ->
- juvenile |
- adult.
- Acquisition: physical; state ->
- ordered not yet received |
- received not yet catalogued |
- catalogued not yet on shelf |
- onshelf reference only |
- onshelf circulatable (no OnLoan connection exists) |
- onshelf on loan (OnLoan connection exists) |
- being repaired (RepairEntity connection exists) * I'll have to add this
- widthdrawn
- on time (returnDate is nil & dueDate <= currentDate) |
- late (returnDate is nil & dueDate > currentDate) |
- lost (returnDate NOT nil & loanState is LOST)
You get the idea.
But sadly, I was making a mistake. Many of the data values are being carried as radixes into 'code tables'. This is infact an N:1 relationship. While the class defines many instances, only one of them participates in a relationship with (and therefore has a connection to) the object instance. (I know. Its hard to keep all these relationships and conections straight.)
Likewise, OnLoan is a state machine and the value is actually a relationship that an instance has with the OnLoan state machine.
We'll get to how I was able to discover the origin of the error and what I did to solve a completely different problem which led me to a few epiphanies; specifically about visualization of a large and complex database.
0 Comments:
Post a Comment
<< Home