25.3.1The SandstoneDB API
SandstoneDB has a very simple API for querying and iterating on the classes representing the repository for their instances:
Class Query API. The API looks a lot like the standard Smalltalk collection protocol slightly renamed to make it clear these queries could potentially be more expensive than just a standard collection.
atId:ifAbsent:allow one to access an instance of the receiver based on its ID. Here is an example of
| auction |
(aRequest url endsWith: '/enable-account') ifTrue:
[ auction := CAAuction atId: (self fieldsAt: #id).
self session pendingAction: 'User has been enabled!' ->
[ self session user isAdmin ifTrue:
[ auction seller
commit ] ] ]
do:iterates over all the instances of the class but does a copy in case the do modifies the collection.
find:returns the first instance satisfying the predicate, as do
findAll:returns all the instances that match a predicate. Here is an example of
^ (CAAuction findAll: [ :each | each vin = aVin ])
allSatisfy: [ :each | each isClosed ]
findAllreturns all the instances of the class.
Instance API. There’s a simple API for the instance side:
idreturns a UUID string in base 36 which uniquely identifies the instance.
updatedOnreturn the timestamps of the creation and last update of the instance.
versionreturns the version of the instance. The version is increased for each save. It is useful in critical sections to validate you’re working on the version you expect.
indexStringreturns all instance variable’
asStrings as a single string for easy searching.
Instance Actions. Here is the list of actions you can perform on a record.
savesaves the instance but is not thread safe.
critical:grabs or creates a Monitor for thread safety.
commitis just a
commit:is similar to
commitbut you can pass a block if you have other work you want done while the object is locked.
abortChangesrolls back to the last saved version.
deletedeletes the instance.
validateis a hook that subclasses can override to specify validation action and throw exceptions to prevent saves.
Here are some trivial examples of using an
person := Person find: [ :each | each name = 'Joe' ]. person commit. person delete. user := User find: [ :each | each email = 'Joe@Schmoe.com' ] ifAbsent: [ User named: 'Joe' email: 'Joe@Schmoe.com' ]. joe := Person atId: anId. managers := Employee findAll: [ :each | each hasSubordinates ].
The framework offers some hooks that you can override on record life cycle events. But pay attention to invoke the superclass methods.
There is also a testing method you might find useful:
isNew answers true prior to the first successful commit.