Smalltalk Object Sink - Vision
Introduction
Most people who are working in object-oriented environments and ever had the chance to use object-oriented database management systems (ODBMS) love the easiness of how to acess those databases. OK, you've got to follow some constraints. Like the concentration on access per navigation and not queries. But you don't have to deal with the object-relational impedance mismatch to press your flexible objects into the strict corset of a relational schema.
But often you are forced to use a relational database due to the requirements of your customer. Now you could do everything by hand or you could use an object-relational mapping tool. Both is needed if you've got to access a given schema bottom-up, e.g. because off legacy applications or the sharing of the database through multiple applications.
If your schema is not specified and you can design it top-down, it may be the administrator who forces the usage of a RDBMS due to his knowledge for maintenance and backup or because of available licenses. Now you're free to define your own way of how to use this RDBMS for your persistency.
The concept below will try to show a way to handle this situation. It will definitely not be the one and only right way. Especially it will not be the fastest one. It is focussed on persistence by navigation, not query, on complex structures and on small to medium sized databases. Different requirements, different solutions.
Idea
The Smalltalk Object Sink provides a simple ODBMS interface to the user. So sessions looks like
cfg := SosFileConfiguration fileName: 'test.db'.
...
db := SosDatabase open: cfg.
tx := db newTransaction begin.
tx
root: 'Employees'
at: 'fmueller'
put: (Employee firstName: 'Frank' lastName: 'Müller').
tx commit.
...
db close.
to create a new root of employees filled with a first entry and
db
transaction: [:tx | (tx root: 'Employees' at: 'fmueller') city: 'Oldenburg']
onError: [ ... ]
to change the city of this employee to "Oldenburg". All objects that can be reached by any root object and that are added or changed will be persisted automicly.
But the management system behind this easy and small API has no own persistency implementation. Exchangeable strategies allows to plug in the connection to allmost any persisteny system - mostly relational database management system, but also a simple ASCII file storrage is possible. The strategy is responsible to persist data passed through commands, to retrieve named root objects and objects identified by an OID (object identifier) and to handle the transactions.
The data to persist is analyzed by the framework inside the Smalltalk Object Sink. And the API between this framework and the strategies is defined.
Technical Concept
Architecture Overview

Logical Relational Model
Right now the system needs just three tables:
Root
This table stores the relation from a name to an instance referenced by an object identifier (oid). The name is the primary key.
Instance
Each instance is stored in one row in this table. It conatins the object identifier as primary key, the type (in its string representation), the value (also a string representation able to conain large data, e.g. TEXT on PostgreSQL) and a version number. Instances are differentiated between atomic and complex types. The atomics are defined by the library (e.g. UndefinedObject, True, False, String, SmallInteger ...). Their values get serialized through the library. All other classes are complex and will be analyzed down until there are left only atomic instance variables for storrage.
Reference
The reference table stores the references of named instance variables of complex types to the referenced objects. The primary key is the referencing oid together with the name of the instance variable. The referenced oid points to the referenced primitive or complex instance.
