rpc_dart_data 3.4.4 copy "rpc_dart_data: ^3.4.4" to clipboard
rpc_dart_data: ^3.4.4 copied to clipboard

Data service layer (CRUD + querying + change streams) built on rpc_dart.

example/example.dart

import 'dart:convert';
import 'dart:io';

import 'package:rpc_dart_data/rpc_dart_data.dart';

/// Minimal in-memory transport with a file-backed SQLite adapter.
///
/// The SQLite file lives on disk, while the RPC transport between client and
/// server is in-memory for simplicity. Replace the transport with your own
/// network layer to expose the same repository remotely.
Future<void> main() async {
  final dbFile = File('notes.sqlite');
  if (dbFile.existsSync()) {
    dbFile.deleteSync();
  }

  final connection = await openFileDb(
    options: SqliteConnectionOptions(nativeFileName: dbFile.path),
    // Add your own PRAGMAs or WAL config here.
    sqliteSetup: (db) => db.execute('PRAGMA journal_mode=WAL;'),
    // To enable SQLCipher, also pass sqlCipherKey.
    // sqlCipherKey: cipherKey,
  );

  final storage = SqliteDataStorageAdapter.connection(connection);
  await storage.ensureReady();

  // Enable schema validation and migrations (SQLite repo rebuilds indexes/FTS
  // after migrations by default).
  final schemaEngine = SchemaValidationEngine(
    registry: storage.schemaRegistry,
    config: const SchemaValidationConfig(
      defaultSchemaEnabled: true,
      defaultRequireValidation: true,
    ),
  );

  final env = await DataServiceFactory.inMemory(
    repository: SqliteDataRepository(
      storage: storage,
      schemaValidation: schemaEngine,
    ),
  );
  final client = env.client;
  final serverRepo = env.server.repository as SqliteDataRepository;

  // Bootstrap schema and migrations declaratively (including initial schema).
  final notesMigrations = MigrationPlan.forCollection('notes')
      .initial(
        migrationId: 'notes_init_v1',
        toVersion: 1,
        schema: {
          'type': 'object',
          'required': ['title'],
          'properties': {
            'title': {'type': 'string'},
            'done': {'type': 'boolean'},
            'tags': {
              'type': 'array',
              'items': {'type': 'string'},
              'minItems': 0,
            },
            'meta': {
              'type': 'object',
              'properties': {
                'priority': {'type': 'integer', 'minimum': 1, 'maximum': 5},
                'rating': {'type': 'number', 'minimum': 0, 'maximum': 1},
                'archived': {'type': 'boolean'},
              },
            },
          },
        },
      )
      .next(
        migrationId: 'notes_add_slug_v2',
        toVersion: 2,
        schema: {
          'type': 'object',
          'required': ['title', 'slug'],
          'properties': {
            'title': {'type': 'string'},
            'slug': {'type': 'string'},
            'done': {'type': 'boolean'},
            'tags': {
              'type': 'array',
              'items': {'type': 'string'},
            },
            'meta': {
              'type': 'object',
              'properties': {
                'priority': {'type': 'integer'},
                'rating': {'type': 'number'},
                'archived': {'type': 'boolean'},
              },
            },
          },
        },
        transformer: _addSlug,
      );

  final helper = MigrationRunnerHelper(
    repository: serverRepo,
    migrations: [...notesMigrations.build()],
  );
  await helper.applyPendingMigrations();
  final schema = await serverRepo.schemaValidationEngine.getSchema('notes');
  print('active schema version=${schema?.version}');

  final created = await client.create(
    collection: 'notes',
    payload: {
      'title': 'Hello',
      'slug': 'hello',
      'done': false,
      'tags': ['welcome', 'intro'],
      'meta': {'priority': 3, 'rating': 0.75, 'archived': false},
    },
  );
  print('created id=${created.id} v=${created.version}');

  final updated = await client.patch(
    collection: 'notes',
    id: created.id,
    expectedVersion: created.version,
    patch: const RecordPatch(set: {'done': true}),
  );
  print('patched id=${updated.id} v=${updated.version}');

  final listed = await client.list(
    collection: 'notes',
    options: const QueryOptions(limit: 10),
  );
  for (final note in listed.records) {
    print(
      'note ${note.id} title=${note.payload['title']} done=${note.payload['done']}',
    );
  }

  final export = await client.exportDatabase(includePayloadString: false);
  await for (final chunk in export.payloadStream!) {
    print(utf8.decode(chunk));
  }

  // Demonstrate schema RPCs via client: list schemas and fetch one.
  final schemas = await client.listSchemas();
  print(
    'schemas: ${schemas.schemas.map((s) => '${s.collection}@${s.version}')}',
  );
  final fetchedSchema = await client.getSchema(collection: 'notes');
  final activeSchema = fetchedSchema.schema;
  print('active schema for notes v=${activeSchema?.version}');
  // Toggle policy via RPC (e.g., ensure validation is on).
  await client.setSchemaPolicy(
    collection: 'notes',
    enabled: true,
    requireValidation: true,
  );

  final first = (await client.list(
    collection: 'notes',
    options: const QueryOptions(limit: 1),
  )).records.first;
  //
  await client.update(
    collection: 'notes',
    id: first.id,
    expectedVersion: first.version,
    payload: {'author': 'not exists'},
  );

  await env.dispose();
  await connection.close();
}

Map<String, dynamic> _addSlug(Map<String, dynamic> payload) => {
  ...payload,
  'slug': (payload['title'] as String).toLowerCase(),
};
0
likes
160
points
890
downloads

Publisher

verified publisherdart.nogipx.dev

Weekly Downloads

Data service layer (CRUD + querying + change streams) built on rpc_dart.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

async, collection, equatable, licensify, meta, path, postgres, rpc_dart, sqlite3

More

Packages that depend on rpc_dart_data