sembast 2.4.6+1

  • Readme
  • Changelog
  • Example
  • Installing
  • 98

sembast.dart #

sembast db stands for Simple Embedded Application Store database

Build Status

General #

Yet another NoSQL persistent store database solution for single process io applications. The whole document based database resides in a single file and is loaded in memory when opened. Changes are appended right away to the file and the file is automatically compacted when needed.

Works on Dart VM and Flutter (no plugin needed, 100% Dart so works on all platforms - MacOS/Android/iOS/Linux/Windows). Inspired from IndexedDB, DataStore, WebSql, NeDB, Lawndart...

Supports encryption using user-defined codec.

  • Pure dart single file IO VM/Flutter storage supported.
  • Web support (including Flutter Web) through sembast_web.
  • Can work on top of sqflite through sembast_sqflite.

Usage example: notepad_sembast: Simple flutter notepad working on all platforms (web/mobile/mac) (online demo)

Follow the guide.

Usage #

Opening a database #

A database is a single file represented by a path in the file system

// File path to a file in the current directory
String dbPath = 'sample.db';
DatabaseFactory dbFactory = databaseFactoryIo;

// We use the database factory to open the database
Database db = await dbFactory.openDatabase(dbPath);

The db object is ready for use.

More information here.

Reading and writing records #

Simple example of writing and reading records

// dynamically typed store
var store = StoreRef.main();
// Easy to put/get simple values or map
// A key can be of type int or String and the value can be anything as long as it can
// be properly JSON encoded/decoded
await store.record('title').put(db, 'Simple application');
await store.record('version').put(db, 10);
await store.record('settings').put(db, {'offline': true});

// read values
var title = await store.record('title').get(db) as String;
var version = await store.record('version').get(db) as int;
var settings = await store.record('settings').get(db) as Map;
  
// ...and delete
await store.record('version').delete(db);

Store #

The store has some similarities with IndexedDB store and DataStore entities. The database always has a main store for easy access (like in the example aboves or typically to save singletons) and allows for an infinite number of stores where a developer would store entity specific data (such as a list of records of the same 'type')

 // Use the animals store using Map records with int keys
var store = intMapStoreFactory.store('animals');

// Store some objects
await db.transaction((txn) async {
  await store.add(txn, {'name': 'fish'});
  await store.add(txn, {'name': 'cat'});
  
  // You can specify a key
  await store.record(10).put({'name': 'dog'});
});

The API takes advantage of Dart strong mode to make database access less error prone.

// Use the main store for storing key values as String
var store = StoreRef<String, String>.main();

// Writing the data
await store.record('username').put(db, 'my_username');
await store.record('url').put(db, 'my_url');

// Reading the data
var url = await store.record('url').get(db);
var username = await store.record('username').get(db);

More info on the store API here

When record values are of type Map, record fields can be referenced using a dot (.) unless escaped.

var store = intMapStoreFactory.store();
var key = await store.add(db, {'path': {'sub': 'my_value'}, 'with.dots': 'my_other_value'});

var record = await store.record(key).getSnapshot(db);
var value = record['path.sub'];
// value = 'my_value'
var value2 = record[FieldKey.escape('with.dots')];
// value2 = 'my_other_value'

Follow the links for more information on how to write or read data

Auto increment #

If no key is provided, the object is inserted with an auto-increment value

var store = StoreRef<int, String>.main();
// Auto incrementation is built-in
var key1 = await store.add(db, 'value1');
var key2 = await store.add(db, 'value2');
// key1 = 1, key2 = 2...

Transaction #

Actions can be grouped into transactions for consistency and optimization (single write on the file system). If an error is thrown, the transaction is cancelled and the changes reverted.

To prevent deadlock, never use an existing Database or Store object.

await db.transaction((txn) async {
  await store.add(txn, 'value1');
  await store.add(txn, 'value2');
});

More info on transaction here

Simple find mechanism #

Filtering and sorting can be done on any field

More information here.

 // Use the animals store using Map records with int keys
var store = intMapStoreFactory.store('animals');

// Store some objects
await db.transaction((txn) async {
  await store.add(txn, {'name': 'fish'});
  await store.add(txn, {'name': 'cat'});
  await store.add(txn, {'name': 'dog'});
});

// Look for any animal "greater than" (alphabetically) 'cat'
// ordered by name
var finder = Finder(
    filter: Filter.greaterThan('name', 'cat'),
    sortOrders: [SortOrder('name')]);
var records = await store.find(db, finder: finder);

expect(records.length, 2);
expect(records[0]['name'], 'dog');
expect(records[1]['name'], 'fish');

Listen to changes #

Similarly to firestore, you can listen to record, store or query changes.

More information here

Codec and encryption #

Sembast supports using a user-defined codec to encode/decode data when read/written to disk. It provides a way to support encryption. Encryption itself is not part of sembast but an example of a simple encryption codec is provided in the test folder.

// Initialize the encryption codec with a user password
var codec = getEncryptSembastCodec(password: '[your_user_password]');

// Open the database with the codec
Database db = await factory.openDatabase(dbPath, codec: codec);

// ...your database is ready to use

More information here.

Information #

Storage format #

Data is stored in a text file where each line is (json format) either:

  • meta information of the database (first line)
  • record data

Each data written is appended lazily to the file for best performance. Compact might happen at any moment to prevent record duplication. The whole compact information is done in a new file followed by a rename to make it atomic.

More information here.

Supported types #

Supported types depends on JSON supported types. More information here

Keys

Supported key types are:

  • int (default with autoincrement when no key are passed)
  • String (String keys can also be generated à la firestore)

Values

Supported value types are:

  • String
  • num (int and double)
  • Map (Map<String, dynamic>)
  • List (List<dynamic>)
  • bool
  • null (value)
  • Blob (custom type)
  • Timestamp (custom type)

Resources #

Third party examples and tutorials available are listed here.

Issue #

Build status #

Travis: Build Status

2.4.6+1 #

  • Optimize cooperator delay for the web and allow custom values for delay and pause.
  • Fix listener for imported data during transaction (sembast_web and sembast_sqflite)

2.4.5 #

  • Fix version handling when an error is thrown during open.

2.4.4+4 #

  • Add support for filter operator & and |
  • Allow importing sembast_io.dart in non-io app.
  • Optimize query without sort orders.
  • Optimize count without sort filter.

2.4.3 #

  • Export disableSembastCooperator() for unit tests.
  • Store and record database access now implemented as extensions.

2.4.2 #

  • Fix finder start end of list issue

2.4.1+1 #

  • Allow importing a database export using a codec
  • Fix export for custom types

2.4.0 #

  • Add Blob and Timestamp support

2.3.0 #

  • Remove 1.x deprecated APIs

2.2.0+1 #

  • Support for sembast_web

2.1.3 #

  • Export cloneValue and cloneList from utils/value_utils.dart

2.1.2+3 #

  • Pedantic 1.9 support
  • Fix Store.drop behavior
  • Fix listener behavior when no listener is attached

2.1.1 #

  • Add RecordsRef.add to RecordsRef.update to insert/update multiple records.

2.1.0+1 #

  • Add code documentation, code coverage and build badges

2.1.0 #

  • Remove logging dependency

2.0.1+2 #

  • Add RecordRef.add to insert a record if it does not exist.
  • BREAKING CHANGE RecordsRef.put returns the list of values not the list of keys

2.0.0+1 #

  • No change. Currently deprecated APIs will be removed.

1.19.0-dev.3 #

  • Deprecated old APIs

1.17.2+2 #

  • Add QueryRef.getSnapshot
  • BREAKING CHANGE RecordRef.put returns the value not the key

1.17.1 #

  • Add StoreRef.addAll

1.17.0 #

  • Sdk 2.5.0 support

1.16.0+3 #

  • Add record and query change tracking
  • Fix onVersionChanged hangs if compact is triggered

1.15.4+1 #

  • Fix inner map merging when updating a record

1.15.3 #

  • Enforce Map<String, dynamic> for maps in the store API
  • Add cloneMap utility to allow modifying a read record

1.15.2 #

  • Add the ability to escape keys with dot in their names for updates and queries (filter, sort)
  • Fix codec signature check to compare the decrypted value instead of the encrypted one

1.15.1 #

  • Add custom filter support and allow filtering on list content for Filter.equals and Filter.matches

1.15.0 #

  • Add new API to allow strict typing on keys and values

1.14.0 #

  • Make the database work in cooperate mode to avoid stuttering with big databases on Flutter
  • Commit changes lazily to the storage

1.13.3 #

  • Add support for user-defined codec to allow encryption

1.13.0 #

  • Add support for nested dotted fields, i.e. 'path.sub' allow setting/getting/filtering/sorting on path inner value sub
  • support for boundaries (start and end) in a query with sort orders

1.12.0 #

  • Add Filter.matchs for regular expression filtering
  • Add rootPath support for DatabaseFactoryIo to allow relative path to a root folder

1.10.1 #

  • Add update method to allow updating partially a Map record
  • Add updateRecords utility methods to update multiple records based on a a filter
  • properly clone each value when written and read

1.9.5 #

  • Fix database manipulation issues during onVersionChanged

1.9.4 #

  • Add value_utils to help comparing value and arrays

1.9.1 #

  • New transaction API
  • dart2 only

1.8.0 #

  • fix flutter cast issue
  • fix limit/offset implementation
  • Update synchronized dependency
  • make all constants lowercase

1.7.0 #

  • mode databaseModeNeverFails is the new default
  • API cleanup and add deprecations

1.6.1 #

  • Add implicit-cast: false support

1.6.0 #

1.5.0 #

  • Update synchronized dependency
  • Add DatabaseMode.NEVER_FAILS that will ignore the file once a corrupted record is encountered

1.3.9 #

  • Add web example to test ddc support
  • Fix transaction

1.3.7 #

  • Strong mode support
  • support for setting record field directly
  • fix support for dart 1.24

1.3.1 #

  • Add support for import/export

1.2.2 #

  • Add for support for isNull and notNull filter
  • Add for support for sorting null last
  • Travis test integration

1.0.0 #

  • Initial revision

example/main.dart

// basically same as the io runner but with extra output
import 'dart:async';

import 'package:path/path.dart';
import 'package:sembast/sembast.dart';
import 'package:sembast/sembast_io.dart';

Future main() async {
  final db = await databaseFactoryIo
      .openDatabase(join('.dart_tool', 'sembast', 'example', 'record_demo.db'));
  var store = intMapStoreFactory.store('my_store');

  var key = await store.add(db, {'name': 'ugly'});
  var record = await store.record(key).getSnapshot(db);
  record =
      (await store.find(db, finder: Finder(filter: Filter.byKey(record.key))))
          .first;
  print(record);
  var records = (await store.find(db,
      finder: Finder(filter: Filter.matches('name', '^ugly'))));
  print(records);
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  sembast: ^2.4.6+1

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:sembast/sembast.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
97
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
98
Learn more about scoring.

We analyzed this package on Jul 2, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.13

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.7.0 <3.0.0
meta >=1.1.6 <3.0.0 1.1.8
path >=1.5.1 <3.0.0 1.7.0
synchronized >=2.1.0 <4.0.0 2.2.0+1
Dev dependencies
build_runner >=0.9.0
build_test >=0.10.2+5
build_web_compilers >=0.4.0+4
crypto >=2.0.6
encrypt >=3.1.0
http >=0.11.0
io any
pedantic >=1.4.0
process_run >=0.10.2
pub_semver any
test >=1.5.1
yaml any