Symbolic Logic:Programming:ORM Persistence

An Object to Relational Mapping (ORM) for a logic programming language allow access to a relational database using logic programming. No SQL need be written while providing a wide range of SQL functionality.

This page describes how to create persistent classes. A persistent class has the data for each object stored as a row in a table. There is one table per class.

Usage of Persistence
Persistence is added to a class by inheriting from the Persist class.


 * class Person
 * inherit Persist("person", Person);
 * }
 * }

Inheriting from Persist gives access to the following methods.

A persistent class may have Attributes. The following attributes are added by default,

Attributes may be added,


 * class Person
 * Attribute("name", String) as Name;
 * }
 * }

One to Many Relations may be added by defining a relation class,


 * class FKPet
 * FKOneToMany(class Person, symbol Pet, class Dog, symbol Owner)
 * }
 * }

Selection of Records
A list of objects may be retrieved using code like,


 * Simple query
 * List(Person) personList = Person.Select(p : p.GetName == "Bob");


 * Conditions on related files,
 * List(Person) personList = Person.Select(p : p.GetPetList.Count > 0);


 * Setting up a constraint.
 * Person person = Person.CreateTemplate;
 * person.GetAge > 50;
 * List(Person) personList = person.Select; // All people older than 50.
 * List(Dog) personList = person.GetPetList.Select; //All dogs for people older than 50.

Implementation of Persist
Persist is a generic class with very little functionality. Its main purpose is to associate a table name with the class. Most of the implementation is in PersistBase.


 * class Persist(String tableName, class T)
 * inherit PersistBase;
 * T CreateTemplate
 * T t = new T;
 * t.SetMode(EnumMode::TemplateMode);
 * return t;
 * }
 * T CreateObject
 * T t = new T;
 * t.SetMode(EnumMode::InsertMode);
 * return t;
 * }
 * String GetTableName
 * return tableName;
 * }
 * List(T) Select(SqlCondition condition, SqlOrder order)
 * return PersistBase.SelectBase(SqlCondition condition, SqlOrder order);
 * }
 * }
 * List(T) Select(SqlCondition condition, SqlOrder order)
 * return PersistBase.SelectBase(SqlCondition condition, SqlOrder order);
 * }
 * }
 * }

Persists base implements attributes that all tables must support.


 * class PersistBase
 * public:
 * inherit Attribute("id", DbIdType) as Id; // Identifies the record
 * inherit Attribute("timestamp", Time) as TimeStamp; // Identifes the time of last modification.
 * inherit Attribute("update_user", String) as UpdateUser; // Identifies the used
 * }
 * }

Selection of Records
Selection of records is implemented in PersistBase by,


 * class PersistBase
 * public:
 * // Return a list of objects from this class and all classes that inherit from it.
 * List(PersistBase) SelectBase(SqlCondition condition, SqlOrder order)
 * return GetAllClasses.ForEachCombineList(t : t.SelectTable(condition, order), order);
 * }
 * // Return a list of objects that match the condition from only this object.
 * List(PersistBase) SelectTable(SqlCondition condition, SqlOrder order)
 * db.Query(GenerateSelect(condition, order), GenerateBind(condition))
 * .ForEachCombine(row : CreateObject.Read(row));
 * }
 * protected:
 * // Get a list of classes that inherit from the implementing class.
 * abstract List(PersistBase) GetInheritingClasses;
 * // Get a comma separate string of field names.
 * abstract String GetAttributeNames;
 * abstract void Read;
 * String CommaCombine(String first, String second)
 * return first + ", " + second;
 * }
 * private:
 * // Generate the SQL statement that returns the rows from the table.
 * String GenerateSelect(SqlCondition condition, SqlOrder order)
 * return "SELECT " + GetAttributeNames
 * + " FROM " + GetTableName
 * + " WHERE " + condition(this).GetText
 * + " ORDER BY " + order(this).GetText
 * }
 * DBBind GenerateBind(SqlCondition condition)
 * return condition.GetBind;
 * }
 * }
 * }
 * DBBind GenerateBind(SqlCondition condition)
 * return condition.GetBind;
 * }
 * }
 * }

Saving

 * class PersistBase
 * enum EnumMode { TemplateMode, InsertMode, UpdateMode, DeleteMode, DeletedMode };
 * inherit Property(EnumMode) as Mode;
 * void Save(role Database db)
 * if IsDirty then
 * DBBind bind = new DBBind;
 * if (GetMode == InsertMode)
 * Bind(bind);
 * db.Call(GetSPITName, bind);
 * SetMode(UpdateMode);
 * }
 * else if (GetMode == UpdateMode)
 * Bind(bind);
 * db.Call(GetSPUTName, bind);
 * }
 * else if (GetMode == DeleteMode)
 * db.Call(GetSPDTName, bind);
 * SetMode(DeletedMode);
 * }
 * }
 * }
 * protected:
 * abstract bool IsDirty;
 * abstract Bind(DBBind bind);
 * private:
 * String GetSPITName
 * return "SPIT" + GetTableName;
 * }
 * String GetSPUTName
 * return "SPUT" + GetTableName;
 * }
 * String GetSPDTName
 * return "SPDT" + GetTableName;
 * }
 * }
 * }
 * String GetSPUTName
 * return "SPUT" + GetTableName;
 * }
 * String GetSPDTName
 * return "SPDT" + GetTableName;
 * }
 * }
 * }
 * }

Database Tables
Upgrading the database tables is restricted to,
 * creating tables
 * adding columns
 * modifying columns
 * class PersistBase
 * public:
 * void UpgradeDB(role Database db, role Time currentTime)
 * if (not db.TableExists(GetTableName)
 * UpgradeColumns(db.CreateTable);
 * }
 * else
 * UpgradeColumns(db.GetTable(GetTableName));
 * }
 * }
 * protected:
 * abstract void UpgradeColumns(DBTable table);
 * }
 * }
 * }
 * protected:
 * abstract void UpgradeColumns(DBTable table);
 * }

Stored Procedures
Upgrading the stored procedures is relatively straight forward. There are standard templates for the stored procedures. The templates implement optimistic locking.

Inserting a record makes sense in a logic programming environment because of the timestamp. The record is being brought into existence at time. From the mathematical point of view the whole history of the database is a single unchanging entity. But we dont know the whole history yet. Inserting a row is discovering more history.

Technically updating a row makes sense in terms of logic programming as long as we think of it as steps.
 * Inserting a new row at the time of the new timestamp.
 * Archiving off or forgetting the old row.

As long as we only ask questions about the state of the database now Updating and Deleting are OK.

Links

 * Symbolic Logic:Programming:Object Relational Mapping
 * Symbolic Logic:Programming:Framework
 * Symbolic Logic:Programming
 * Intelligence and Reasoning