scenario constant

List<ProtocolExample> const scenario

Every example, in order.

Implementation

static const List<ProtocolExample> scenario = [
  ProtocolExample(
    'Define a table with a composite index and a unique index',
    {
      'v': 1,
      'op': 'define_table',
      'table': {
        'name': 'users',
        'primary_key': 'id',
        'auto_increment': true,
        'indexes': [
          {
            'name': 'by_city_age',
            'fields': ['city', 'age'],
            'unique': false,
          },
          {
            'name': 'by_email',
            'fields': ['email'],
            'unique': true,
          },
        ],
      },
    },
    ok: {'changed': true},
  ),
  ProtocolExample(
    'Define a second table',
    {
      'v': 1,
      'op': 'define_table',
      'table': {
        'name': 'posts',
        'primary_key': 'id',
        'auto_increment': false,
        'indexes': [
          {
            'name': 'by_author',
            'fields': ['author_id'],
            'unique': false,
          },
        ],
      },
    },
    ok: {'changed': true},
  ),
  ProtocolExample(
    'Insert rows; the auto-increment key is generated',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'insert',
        'table': 'users',
        'on_conflict': 'error',
        'rows': [
          {
            'name': 'Ada',
            'email': 'ada@example.com',
            'city': 'Lima',
            'age': 36,
          },
          {
            'name': 'Grace',
            'email': 'grace@example.com',
            'city': 'Bogotá',
            'age': 45,
          },
          {'name': 'Linus', 'email': null, 'city': 'Lima', 'age': 28},
        ],
      },
    },
    ok: {
      'affected': 3,
      'rows': [
        {
          'name': 'Ada',
          'email': 'ada@example.com',
          'city': 'Lima',
          'age': 36,
          'id': 1,
        },
        {
          'name': 'Grace',
          'email': 'grace@example.com',
          'city': 'Bogotá',
          'age': 45,
          'id': 2,
        },
        {'name': 'Linus', 'email': null, 'city': 'Lima', 'age': 28, 'id': 3},
      ],
    },
  ),
  ProtocolExample(
    'A duplicate value of a unique index fails the whole insert',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'insert',
        'table': 'users',
        'rows': [
          {'name': 'Ada II', 'email': 'ada@example.com', 'city': 'Lima'},
        ],
      },
    },
    errorCode: 'UniqueViolation',
  ),
  ProtocolExample(
    'Select with a filter, an order and a limit',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'select',
        'table': 'users',
        'filter': {
          'op': 'and',
          'args': [
            {'op': 'eq', 'field': 'city', 'value': 'Lima'},
            {'op': 'gt', 'field': 'age', 'value': 30},
          ],
        },
        'order': [
          {'field': 'age', 'desc': true},
        ],
        'limit': 10,
      },
    },
    ok: {
      'rows': [
        {
          'name': 'Ada',
          'email': 'ada@example.com',
          'city': 'Lima',
          'age': 36,
          'id': 1,
        },
      ],
    },
  ),
  ProtocolExample(
    'Project two fields, each value once',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'select',
        'table': 'users',
        'order': [
          {'field': 'city', 'desc': false},
        ],
        'fields': ['city'],
        'distinct': true,
      },
    },
    ok: {
      'rows': [
        {'city': 'Bogotá'},
        {'city': 'Lima'},
      ],
    },
  ),
  ProtocolExample(
    'Count and aggregate',
    {
      'v': 1,
      'op': 'batch',
      'statements': [
        {
          'op': 'count',
          'table': 'users',
          'filter': {'op': 'is_null', 'field': 'email'},
        },
        {
          'op': 'aggregate',
          'table': 'users',
          'function': 'avg',
          'field': 'age',
        },
      ],
    },
    ok: {
      'results': [
        {'count': 1},
        {'value': 36.333333333333336},
      ],
    },
  ),
  ProtocolExample(
    'Group by with aggregates and having',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'group',
        'table': 'users',
        'by': ['city'],
        'aggregates': [
          {'function': 'count', 'as': 'people'},
          {'function': 'max', 'field': 'age', 'as': 'oldest'},
        ],
        'having': {'op': 'ge', 'field': 'people', 'value': 2},
      },
    },
    ok: {
      'rows': [
        {'city': 'Lima', 'people': 2, 'oldest': 36},
      ],
    },
  ),
  ProtocolExample(
    'Insert into the second table',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'insert',
        'table': 'posts',
        'rows': [
          {'id': 'p1', 'author_id': 1, 'title': 'Types', 'views': 0},
          {'id': 'p2', 'author_id': 1, 'title': 'Joins'},
        ],
      },
    },
    ok: {
      'affected': 2,
      'rows': [
        {'id': 'p1', 'author_id': 1, 'title': 'Types', 'views': 0},
        {'id': 'p2', 'author_id': 1, 'title': 'Joins'},
      ],
    },
  ),
  ProtocolExample(
    'Explain a join without running it',
    {
      'v': 1,
      'op': 'explain',
      'query': {
        'from': {'table': 'users', 'as': 'users'},
        'joins': [
          {
            'table': 'posts',
            'as': 'posts',
            'kind': 'left',
            'on': {'left': 'users.id', 'right': 'author_id'},
          },
        ],
        'filter': {'op': 'eq', 'field': 'users.city', 'value': 'Lima'},
      },
    },
    ok: {
      'plan': {
        'strategy': any,
        'tables': [
          {'table': 'users', 'as': 'users', 'access': any},
          {'table': 'posts', 'as': 'posts', 'access': any},
        ],
        'filter': 'after_join',
      },
    },
  ),
  ProtocolExample(
    'Left join: every user, with their posts or null',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'join',
        'from': {'table': 'users', 'as': 'users'},
        'joins': [
          {
            'table': 'posts',
            'as': 'posts',
            'kind': 'left',
            'on': {'left': 'users.id', 'right': 'author_id'},
          },
        ],
        'filter': {'op': 'eq', 'field': 'users.city', 'value': 'Lima'},
        'order': [
          {'field': 'posts.id', 'desc': false},
        ],
      },
    },
    ok: {
      'rows': [
        {
          'users': {
            'name': 'Linus',
            'email': null,
            'city': 'Lima',
            'age': 28,
            'id': 3,
          },
          'posts': null,
        },
        {
          'users': {
            'name': 'Ada',
            'email': 'ada@example.com',
            'city': 'Lima',
            'age': 36,
            'id': 1,
          },
          'posts': {'id': 'p1', 'author_id': 1, 'title': 'Types', 'views': 0},
        },
        {
          'users': {
            'name': 'Ada',
            'email': 'ada@example.com',
            'city': 'Lima',
            'age': 36,
            'id': 1,
          },
          'posts': {'id': 'p2', 'author_id': 1, 'title': 'Joins'},
        },
      ],
    },
  ),
  ProtocolExample(
    'Update with a counter; a missing value counts as 0',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'update',
        'table': 'posts',
        'filter': {'op': 'eq', 'field': 'author_id', 'value': 1},
        'set': {'title': 'Updated'},
        'increment': {'views': 1},
        'expect': 2,
      },
    },
    ok: {'affected': 2, 'rows': <Object?>[]},
  ),
  ProtocolExample(
    'Begin a write transaction',
    {'v': 1, 'op': 'begin', 'mode': 'write', 'timeout_ms': 30000},
    ok: {'transaction': transaction},
  ),
  ProtocolExample(
    'Write inside the transaction',
    {
      'v': 1,
      'op': 'tx_execute',
      'transaction': transaction,
      'statement': {
        'op': 'delete',
        'table': 'posts',
        'filter': {'op': 'eq', 'field': 'id', 'value': 'p2'},
      },
    },
    ok: {'affected': 1, 'rows': <Object?>[]},
  ),
  ProtocolExample('Open a savepoint', {
    'v': 1,
    'op': 'savepoint',
    'transaction': transaction,
  }, ok: <String, Object?>{}),
  ProtocolExample('A failed write inside the savepoint', {
    'v': 1,
    'op': 'tx_execute',
    'transaction': transaction,
    'statement': {
      'op': 'insert',
      'table': 'posts',
      'rows': [
        {'id': 'p1', 'author_id': 2, 'title': 'Duplicate'},
      ],
    },
  }, errorCode: 'DuplicateKey'),
  ProtocolExample('Roll the savepoint back; the transaction goes on', {
    'v': 1,
    'op': 'rollback_to',
    'transaction': transaction,
  }, ok: <String, Object?>{}),
  ProtocolExample('Commit', {
    'v': 1,
    'op': 'commit',
    'transaction': transaction,
  }, ok: <String, Object?>{}),
  ProtocolExample(
    'The committed state',
    {
      'v': 1,
      'op': 'execute',
      'statement': {'op': 'find', 'table': 'posts', 'key': 'p1'},
    },
    ok: {
      'row': {'id': 'p1', 'author_id': 1, 'title': 'Updated', 'views': 1},
    },
  ),
  ProtocolExample('A closed transaction cannot be used', {
    'v': 1,
    'op': 'commit',
    'transaction': transaction,
  }, errorCode: 'TransactionClosed'),
  ProtocolExample(
    'Every table definition, in name order',
    {'v': 1, 'op': 'tables'},
    ok: {
      'tables': [
        {
          'name': 'posts',
          'primary_key': 'id',
          'auto_increment': false,
          'indexes': [
            {
              'name': 'by_author',
              'fields': ['author_id'],
              'unique': false,
            },
          ],
        },
        {
          'name': 'users',
          'primary_key': 'id',
          'auto_increment': true,
          'indexes': [
            {
              'name': 'by_city_age',
              'fields': ['city', 'age'],
              'unique': false,
            },
            {
              'name': 'by_email',
              'fields': ['email'],
              'unique': true,
            },
          ],
        },
      ],
    },
  ),
  ProtocolExample(
    'Explain a query; each engine chooses its own plan',
    {
      'v': 1,
      'op': 'explain',
      'query': {
        'table': 'users',
        'filter': {'op': 'eq', 'field': 'city', 'value': 'Lima'},
      },
    },
    ok: {
      'plan': {
        'table': 'users',
        'access': any,
        'index': any,
        'descending': any,
        'presorted': any,
        'exact': any,
      },
    },
  ),
  ProtocolExample(
    'Describe the database',
    {'v': 1, 'op': 'info'},
    ok: {'protocol': 1, 'tables': 2, 'lmdb': any, 'map_size': any},
  ),
  ProtocolExample(
    'Begin a read transaction',
    {'v': 1, 'op': 'begin', 'mode': 'read', 'timeout_ms': 30000},
    ok: {'transaction': transaction},
  ),
  ProtocolExample(
    'Read inside it, from its snapshot',
    {
      'v': 1,
      'op': 'tx_execute',
      'transaction': transaction,
      'statement': {'op': 'count', 'table': 'users'},
    },
    ok: {'count': 3},
  ),
  ProtocolExample('A read transaction refuses writes', {
    'v': 1,
    'op': 'tx_execute',
    'transaction': transaction,
    'statement': {'op': 'delete', 'table': 'users'},
  }, errorCode: 'ReadOnlyTransaction'),
  ProtocolExample('End it', {
    'v': 1,
    'op': 'rollback',
    'transaction': transaction,
  }, ok: <String, Object?>{}),
  ProtocolExample(
    'Begin another write transaction',
    {'v': 1, 'op': 'begin', 'mode': 'write', 'timeout_ms': 30000},
    ok: {'transaction': transaction},
  ),
  ProtocolExample('Open a savepoint in it', {
    'v': 1,
    'op': 'savepoint',
    'transaction': transaction,
  }, ok: <String, Object?>{}),
  ProtocolExample(
    'Write inside the savepoint',
    {
      'v': 1,
      'op': 'tx_execute',
      'transaction': transaction,
      'statement': {
        'op': 'insert',
        'table': 'posts',
        'rows': [
          {'id': 'p9', 'author_id': 1, 'title': 'Kept'},
        ],
      },
    },
    ok: {
      'affected': 1,
      'rows': [
        {'id': 'p9', 'author_id': 1, 'title': 'Kept'},
      ],
    },
  ),
  ProtocolExample(
    'Release the savepoint; its write stays in the transaction',
    {'v': 1, 'op': 'release', 'transaction': transaction},
    ok: <String, Object?>{},
  ),
  ProtocolExample('Roll the whole transaction back', {
    'v': 1,
    'op': 'rollback',
    'transaction': transaction,
  }, ok: <String, Object?>{}),
  ProtocolExample(
    'Nothing of a rolled back transaction is stored',
    {
      'v': 1,
      'op': 'execute',
      'statement': {'op': 'find', 'table': 'posts', 'key': 'p9'},
    },
    ok: {'row': null},
  ),
  ProtocolExample(
    'Drop a table with its rows and indexes',
    {'v': 1, 'op': 'drop_table', 'name': 'posts'},
    ok: {'dropped': true},
  ),
  ProtocolExample(
    'Dropping it again answers false',
    {'v': 1, 'op': 'drop_table', 'name': 'posts'},
    ok: {'dropped': false},
  ),
  ProtocolExample(
    'Define a synchronized table: every write records a change',
    {
      'v': 1,
      'op': 'define_table',
      'table': {
        'name': 'notes',
        'primary_key': 'id',
        'auto_increment': false,
        'indexes': <Object?>[],
        'sync': 'primary',
      },
    },
    ok: {'changed': true},
  ),
  ProtocolExample(
    'Write to it as to any table',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'insert',
        'table': 'notes',
        'rows': [
          {'id': 'n1', 'title': 'Draft'},
        ],
      },
    },
    ok: {
      'affected': 1,
      'rows': [
        {'id': 'n1', 'title': 'Draft'},
      ],
    },
  ),
  ProtocolExample(
    'The change is pending, committed with the row',
    {'v': 1, 'op': 'sync_status', 'remote': 'primary'},
    ok: {'checkpoint': null, 'pending': 1, 'conflicts': 0},
  ),
  ProtocolExample(
    'Claim a batch to push: a lease and immutable envelopes',
    {
      'v': 1,
      'op': 'sync_claim',
      'remote': 'primary',
      'max_changes': 10,
      'max_bytes': null,
      'lease_ms': 30000,
    },
    ok: {
      'lease_id': lease,
      'envelopes': [
        {
          'mutation_id': mutation,
          'table': 'notes',
          'key': 'n1',
          'generation': 1,
          'local_revision': 1,
          'local_transaction_id': any,
          'operation': 'upsert',
          'row': {'id': 'n1', 'title': 'Draft'},
          'base_version': null,
          'predecessor': null,
          'attempt': 1,
        },
      ],
    },
  ),
  ProtocolExample(
    'List the open changes',
    {
      'v': 1,
      'op': 'sync_pending',
      'remote': 'primary',
      'table': null,
      'limit': null,
    },
    ok: {
      'count': 1,
      'changes': [
        {
          'mutation_id': mutation,
          'table': 'notes',
          'key': 'n1',
          'local_revision': 1,
          'operation': 'upsert',
          'state': 'leased',
          'attempts': 1,
          'last_error': null,
        },
      ],
    },
  ),
  ProtocolExample(
    'Record what the server stored: one mutation and revision',
    {
      'v': 1,
      'op': 'sync_push_result',
      'remote': 'primary',
      'lease_id': lease,
      'acknowledged': [
        {
          'mutation_id': mutation,
          'table': 'notes',
          'key': 'n1',
          'local_revision': 1,
          'server_version': 'v1',
        },
      ],
      'rejected': <Object?>[],
    },
    ok: {
      'acknowledged': 1,
      'rejected': 0,
      'released': 0,
      'ignored': <Object?>[],
    },
  ),
  ProtocolExample(
    'A duplicate acknowledgement changes nothing',
    {
      'v': 1,
      'op': 'sync_push_result',
      'remote': 'primary',
      'lease_id': null,
      'acknowledged': [
        {
          'mutation_id': mutation,
          'table': 'notes',
          'key': 'n1',
          'local_revision': 1,
          'server_version': 'v1',
        },
      ],
      'rejected': <Object?>[],
    },
    ok: {
      'acknowledged': 0,
      'rejected': 0,
      'released': 0,
      'ignored': <Object?>[],
    },
  ),
  ProtocolExample(
    'The row is synchronized',
    {'v': 1, 'op': 'sync_state', 'table': 'notes', 'key': 'n1'},
    ok: {
      'state': {
        'state': 'synced',
        'deleted': false,
        'sending': false,
        'attempts': 0,
        'last_error': null,
        'pending': 0,
        'local_revision': 1,
        'acknowledged_local_revision': 1,
        'settled_local_revision': 1,
        'row_version': 1,
        'server_version': 'v1',
        'conflict': null,
      },
    },
  ),
  ProtocolExample(
    'Edit it locally',
    {
      'v': 1,
      'op': 'execute',
      'statement': {
        'op': 'update',
        'table': 'notes',
        'filter': {'op': 'eq', 'field': 'id', 'value': 'n1'},
        'set': {'title': 'Edited'},
      },
    },
    ok: {'affected': 1, 'rows': <Object?>[]},
  ),
  ProtocolExample(
    'A server change over the pending edit becomes a conflict',
    {
      'v': 1,
      'op': 'sync_apply_remote',
      'remote': 'primary',
      'expected_checkpoint': null,
      'next_checkpoint': 'c1',
      'changes': [
        {
          'table': 'notes',
          'key': 'n1',
          'operation': 'upsert',
          'row': {'id': 'n1', 'title': 'Remote'},
          'server_version': 'v2',
          'mutation_id': null,
        },
      ],
    },
    ok: {'applied': 0, 'conflicts': 1, 'acknowledged': 0, 'skipped': 0},
  ),
  ProtocolExample(
    'The conflict keeps both variants',
    {'v': 1, 'op': 'sync_conflicts', 'remote': 'primary'},
    ok: {
      'conflicts': [
        {
          'id': conflict,
          'table': 'notes',
          'key': 'n1',
          'local_row_version': 2,
          'local_row': {'id': 'n1', 'title': 'Edited'},
          'outstanding': [any],
          'remote_version': 'v2',
          'remote_operation': 'upsert',
          'remote_row': {'id': 'n1', 'title': 'Remote'},
          'base_version': 'v1',
        },
      ],
    },
  ),
  ProtocolExample('A resolution on an old row version is refused', {
    'v': 1,
    'op': 'sync_resolve',
    'conflict': conflict,
    'expected_row_version': 1,
    'resolution': {'kind': 'accept_remote'},
  }, errorCode: 'RowVersionMismatch'),
  ProtocolExample('Accept the server variant', {
    'v': 1,
    'op': 'sync_resolve',
    'conflict': conflict,
    'expected_row_version': 2,
    'resolution': {'kind': 'accept_remote'},
  }, ok: <String, Object?>{}),
  ProtocolExample('A page read after an old checkpoint is refused', {
    'v': 1,
    'op': 'sync_apply_remote',
    'remote': 'primary',
    'expected_checkpoint': null,
    'next_checkpoint': 'c2',
    'changes': <Object?>[],
  }, errorCode: 'StaleCheckpoint'),
  ProtocolExample(
    'Releasing a lease that holds nothing releases nothing',
    {
      'v': 1,
      'op': 'sync_release',
      'remote': 'primary',
      'lease_id': lease,
      'reason': 'timeout',
    },
    ok: {'released': 0},
  ),
  ProtocolExample(
    'Retrying a settled mutation retries nothing',
    {
      'v': 1,
      'op': 'sync_retry',
      'remote': 'primary',
      'mutation_ids': [mutation],
    },
    ok: {'retried': 0},
  ),
  ProtocolExample('An acknowledgement of an unknown mutation is refused', {
    'v': 1,
    'op': 'sync_push_result',
    'remote': 'primary',
    'lease_id': null,
    'acknowledged': [
      {
        'mutation_id': 'nobody-1',
        'table': 'notes',
        'key': 'n1',
        'local_revision': 1,
        'server_version': 'v9',
      },
    ],
    'rejected': <Object?>[],
  }, errorCode: 'UnknownMutation'),
  ProtocolExample(
    'Everything is settled, at the checkpoint of the last page',
    {'v': 1, 'op': 'sync_status', 'remote': 'primary'},
    ok: {'checkpoint': 'c1', 'pending': 0, 'conflicts': 0},
  ),
  ProtocolExample('Another protocol version is refused', {
    'v': 2,
    'op': 'tables',
  }, errorCode: 'UnsupportedProtocol'),
];