Skip to content

Latest commit

 

History

History
93 lines (71 loc) · 2.8 KB

triggers.md

File metadata and controls

93 lines (71 loc) · 2.8 KB

Triggers

As of sembast 3.0.1, a trigger like feature is supported. It allows implementing features like "on delete cascade" to ensure data integrity.

  • Triggers are called when records are added, updated or deleted.
  • Triggers are called in the same transaction than the one where the record was modified
  • A trigger can itself perform other modification that could itself call other triggers
  • Like transactions, a trigger must be idempotent, i.e. if for some reason a transaction is re-started, pending changes are discarded and triggers will be called again.
  • You can set triggers on stores.

Listen to store changes

You can listen to changes in a store

// Track record changes
store.addOnChangesListener(db).listen((transaction, changes) async {
  // ...
});

In each change:

  • oldSnapshot is null for item added
  • newSnapshot is null for item deleted
  • none are null for modification

Warning: setting triggers could have write penalty if your callback is a lenghty operation. Tu use with care.

If you modify a record in the callback, the callback will be called again, so make sure you don't update indefinitely the same record.

Example

Create a 'student' and 'enroll' store. A student can enroll a course.

var studentStore = intMapStoreFactory.store('student');
var enrollStore = intMapStoreFactory.store('enroll');

Setup trigger to delete a record in 'enroll' when a student is deleted

studentStore.addOnChangesListener(db, (transaction, changes) async {
  // For each student deleted, delete the entry in enroll store
  for (var change in changes) {
    // newValue is null for deletion
    if (change.isDelete) {
      // Delete in enroll, use the transaction!
      await enrollStore.delete(transaction,
          finder:
              Finder(filter: Filter.equals('student', change.ref.key)));
    }
  }
});

In an application, you would likely considered your database 'ready' when triggers are set.

Add some data

var studentId1 = await studentStore.add(db, {'name': 'Jack'});
var studentId2 = await studentStore.add(db, {'name': 'Joe'});

await enrollStore.add(db, {'student': studentId1, 'course': 'Math'});
await enrollStore.add(db, {'student': studentId2, 'course': 'French'});
await enrollStore.add(db, {'student': studentId1, 'course': 'French'});

// The initial data in enroll is
expect((await enrollStore.find(db)).map((e) => e.value), [
  {'student': 1, 'course' : 'Math'},
  {'student': 2, 'course': 'French'},
  {'student': 1, 'course': 'French'}
]);

Delete the student. It will trigger the listener and the entries in the enroll store will be deleted.

await studentStore.record(studentId1).delete(db);

// Data has been deleted in 'enroll' store too!
expect((await enrollStore.find(db)).map((e) => e.value), [
  {'student': 2, 'course': 'French'},
]);