refactor: Replace drift by serverpod as core engine (#33)

This commit is contained in:
Marcelo Mendonça Soares 2026-05-03 09:09:23 -03:00 • committed by GitHub
commit 3545bbba1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
95 changed files with 6196 additions and 671 deletions

View file

@ -16,109 +16,194 @@ concurrency:
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs: jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Dart
uses: dart-lang/setup-dart@v1
- name: Install Melos
run: dart pub global activate melos
- name: Run pub get
run: dart pub get
- name: Generate code and migrations
run: melos generate && melos create-migration
- name: Upload generated code
uses: actions/upload-artifact@v4
with:
name: generated-code
path: |
**/lib/migrations/**
**/lib/src/generated/**
**/lib/src/protocol/**
**/*_server/migrations/**
**/test/**/serverpod_test_tools.dart
dart_format: dart_format:
name: dart format name: dart format
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up Dart - name: Set up Dart
uses: dart-lang/setup-dart@v1 uses: dart-lang/setup-dart@v1
# - name: Run pub get
# run: dart pub get - name: Run pub get
# - name: Verify formatting run: dart pub get
# run: dart format --output=none --set-exit-if-changed .
# Skip code generation for formatting check
- name: Verify formatting
run: dart format --output=none --set-exit-if-changed .
dart_analyze: dart_analyze:
needs: generate
name: dart analyze name: dart analyze
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up Dart - name: Set up Dart
uses: dart-lang/setup-dart@v1 uses: dart-lang/setup-dart@v1
# - name: Run pub get
# run: dart pub get
# - name: Run lint
# run: dart analyze .
# tests: - name: Install Melos
# name: dart test run: dart pub global activate melos
# runs-on: ubuntu-latest
# permissions:
# pull-requests: write
# contents: read
# steps:
# - uses: actions/checkout@v4
# - name: Set up Dart
# uses: dart-lang/setup-dart@v1
# with:
# sdk: stable
# - name: Run pub get
# run: dart pub get
# - name: Run tests with coverage
# run: dart test --coverage=coverage --reporter=failures-only
# - name: Activate coverage package
# run: dart pub global activate coverage
# - name: Format coverage
# run: dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --report-on=lib --check-ignore --ignore-files="**/*.g.dart"
# - name: Generate coverage report
# run: dart scripts/coverage_report.dart --ci > coverage-results.txt
# - name: Comment on PR
# if: github.event_name == 'pull_request'
# uses: thollander/actions-comment-pull-request@v3
# with:
# file-path: coverage-results.txt
# comment-tag: coverage-results
# benchmarks: - name: Download generated code
# name: run benchmarks uses: actions/download-artifact@v4
# runs-on: ubuntu-latest with:
# permissions: name: generated-code
# pull-requests: write
# contents: write
# steps:
# - uses: actions/checkout@v4
# - name: Set up Dart
# uses: dart-lang/setup-dart@v1
# with:
# sdk: stable
# - name: Run pub get
# run: dart pub get
# - name: Configure Git
# run: |
# git config --global user.name "GitHub Actions"
# git config --global user.email "actions@github.com"
# - name: Fetch Existing Benchmark Data
# run: git fetch origin refs/notes/benchmarks:refs/notes/benchmarks || true
# - name: Run benchmarks
# run: dart benchmark/run.dart --ci > benchmark-results.txt
# - name: Comment on PR
# if: github.event_name == 'pull_request'
# uses: thollander/actions-comment-pull-request@v3
# with:
# file-path: benchmark-results.txt
# comment-tag: benchmark-results
# - name: Store Benchmark Data in Git Notes
# run: |
# if [ "${{ github.event_name }}" = "pull_request" ]; then
# COMMIT_SHA=${{ github.event.pull_request.head.sha }}
# else
# COMMIT_SHA=${{ github.sha }}
# fi
# git notes --ref=benchmarks add -f -F benchmark-results.txt $COMMIT_SHA
# - name: Push Benchmark Data
# if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork != true
# run: git push origin refs/notes/benchmarks
- name: Run pub get
run: dart pub get
- name: Run lint
run: melos lint
tests:
needs: generate
name: dart test
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up Dart
uses: dart-lang/setup-dart@v1
- name: Download generated code
uses: actions/download-artifact@v4
with:
name: generated-code
- name: Run pub get
run: dart pub get
- name: Run tests with coverage
run: dart test packages/ test/ --coverage=coverage --reporter=failures-only
# TODO: Find a way to make coverage work with the tests running from a
# test project and not as part of the module.
#
# - name: Activate coverage package
# run: dart install coverage
#
# - name: Format coverage
# run: dart run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --report-on=lib --check-ignore --ignore-files="**/*.g.dart"
#
# - name: Generate coverage report
# run: dart scripts/coverage_report.dart --ci > coverage-results.txt
#
# - name: Comment on PR
# if: github.event_name == 'pull_request'
# uses: thollander/actions-comment-pull-request@v3
# with:
# file-path: coverage-results.txt
# comment-tag: coverage-results
benchmarks:
needs: generate
name: run benchmarks
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
steps:
- uses: actions/checkout@v4
- name: Set up Dart
uses: dart-lang/setup-dart@v1
- name: Download generated code
uses: actions/download-artifact@v4
with:
name: generated-code
- name: Run pub get
run: dart pub get
- name: Configure Git
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
- name: Fetch Existing Benchmark Data
run: git fetch origin refs/notes/benchmarks:refs/notes/benchmarks || true
- name: Run benchmarks
working-directory: benchmark
# --verbosity=error avoids "Running build hooks..." on stdout (pollutes PR comment).
run: dart run --verbosity=error run.dart --ci > ../benchmark-results.txt
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v3
with:
file-path: benchmark-results.txt
comment-tag: benchmark-results
- name: Store Benchmark Data in Git Notes
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
COMMIT_SHA=${{ github.event.pull_request.head.sha }}
else
COMMIT_SHA=${{ github.sha }}
fi
git notes --ref=benchmarks add -f -F benchmark-results.txt $COMMIT_SHA
- name: Push Benchmark Data
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork != true
run: git push origin refs/notes/benchmarks
# TODO: Re-enable the publish check when the package is ready for first
# public version.
#
# publish_check: # publish_check:
# needs: generate
# name: dart publish check # name: dart publish check
# runs-on: ubuntu-latest # runs-on: ubuntu-latest
# steps: # steps:
# - uses: actions/checkout@v4 # - uses: actions/checkout@v4
#
# - name: Set up Dart # - name: Set up Dart
# uses: dart-lang/setup-dart@v1 # uses: dart-lang/setup-dart@v1
#
# - name: Install Melos
# run: dart pub global activate melos
#
# - name: Download generated code
# uses: actions/download-artifact@v4
# with: # with:
# sdk: stable # name: generated-code
#
# - name: Run pub get # - name: Run pub get
# run: dart pub get # run: dart pub get
#
# - name: Run publish dry run # - name: Run publish dry run
# run: dart pub publish --dry-run # run: melos publish-check

View file

@ -21,8 +21,12 @@ jobs:
- name: Set up Dart - name: Set up Dart
uses: dart-lang/setup-dart@v1 uses: dart-lang/setup-dart@v1
with:
sdk: stable - name: Install Melos
run: dart pub global activate melos
- name: Install all dependencies - name: Install all dependencies
run: dart pub get run: dart pub get
- name: Generate code and migrations
run: melos generate && melos create-migration

12
.gitignore vendored
View file

@ -7,7 +7,19 @@
pubspec.lock pubspec.lock
.vscode/ .vscode/
.dart_skills/
.cursor/skills/relic*
.cursor/skills/serverpod*
# Coverage reports # Coverage reports
coverage/ coverage/
coverage-results.txt coverage-results.txt
# Melos
.idea/
*melos_*.iml
# TODO: Remove this once the generated code is stable.
**/lib/src/generated/
**/lib/src/protocol/
**/test/integration/test_tools/serverpod_test_tools.dart

View file

@ -0,0 +1,13 @@
include: ../analysis_options.yaml
linter:
rules:
- public_member_api_docs: false
analyzer:
language:
strict-casts: true
strict-inference: true
formatter:
trailing_commas: preserve

21
benchmark/pubspec.yaml Normal file
View file

@ -0,0 +1,21 @@
name: serverpod_offline_sync_benchmark
description: Local CRDT vs baseline performance impact measurement.
publish_to: none
environment:
sdk: '^3.10.3'
resolution: workspace
dependencies:
benchmark_harness: ^2.4.0
intl: ^0.20.2
path: ^1.9.1
serverpod_database: 3.5.0-beta.5
serverpod_offline_sync_server:
path: ../packages/serverpod_offline_sync_server
serverpod_offline_sync_test_client:
path: ../test/serverpod_offline_sync_test_client
dev_dependencies:
lints: '>=3.0.0 <7.0.0'

100
benchmark/run.dart Normal file
View file

@ -0,0 +1,100 @@
import 'utils/benchmark.dart';
import 'utils/conversion.dart';
import 'utils/results.dart';
import 'utils/runner.dart';
Future<void> main(List<String> args) async {
final runningInCI = args.contains('--ci');
String? rowCountArg;
for (final arg in args) {
if (arg.startsWith('--rows=')) {
rowCountArg = arg.substring(7);
}
}
final rowCount = rowCountArg == null ? 1000 : int.parse(rowCountArg);
final rowsString = formatter0.format(rowCount);
if (!runningInCI) print('\n${'=' * 60}');
print('## Performance Benchmark ($rowsString rows)\n');
print(
[
'This benchmark measures the performance impact of using CRDT ',
'metadata synchronization on database operations.',
].join(runningInCI ? '' : '\n'),
);
if (!runningInCI) print('-' * 60);
final benchmarkResults = <BenchmarkResults>[];
for (final operation in Operation.values) {
final baselineResult = await runWithProgress(
'Running ${operation.name} benchmark (baseline)',
() => TypesTableBenchmark(
'${operation.name} (baseline)',
crdtEnabled: false,
operation: operation,
rowCount: rowCount,
).report(),
skipProgress: runningInCI,
);
final crdtResult = await runWithProgress(
'Running ${operation.name} benchmark (CRDT)',
() => TypesTableBenchmark(
'${operation.name} (CRDT)',
crdtEnabled: true,
operation: operation,
rowCount: rowCount,
).report(),
validator: (result) => result.$1 > baselineResult.$1,
skipProgress: runningInCI,
);
benchmarkResults.add(
BenchmarkResults(
operation: operation,
baseline: baselineResult,
crdt: crdtResult,
),
);
}
final spuriousBenchmarks = benchmarkResults.where(
(result) => result.baseline.$1 > result.crdt.$1,
);
if (spuriousBenchmarks.isNotEmpty) {
final leadingText = runningInCI ? '\n> ' : '\n';
print(
[
'$leadingText❌ Baseline time is greater than CRDT time. This is likely due ',
'to running with a very low number of rows ($rowsString). This is not ',
' a valid benchmark and the time comparison should be ignored.',
].join(runningInCI ? '' : '\n'),
);
for (final result in spuriousBenchmarks) {
final baselineDelay = result.baseline.$1.toFormattedDuration();
final crdtDelay = result.crdt.$1.toFormattedDuration();
print(
' - ${result.operation.name.toUpperCase()}: $baselineDelay > $crdtDelay',
);
}
}
for (final result in benchmarkResults) {
printPerformanceImpact(
result,
rowCount: rowCount,
runningInCI: runningInCI,
);
}
printStorageImpact(
benchmarkResults.first,
rowCount: rowCount,
runningInCI: runningInCI,
);
print('\n${'-' * 60}');
print('✅ Benchmark complete!\n');
}

View file

@ -0,0 +1,295 @@
// Benchmark harness types — internal to the runner CLI.
import 'dart:io';
import 'dart:typed_data';
import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:path/path.dart' as p;
import 'package:serverpod_database/serverpod_database.dart';
import 'package:serverpod_offline_sync_server/serverpod_offline_sync_server.dart';
import 'package:serverpod_offline_sync_test_client/serverpod_offline_sync_test_client.dart';
import 'tables.dart';
enum Operation { insert, update, delete }
/// Benchmarks plain SQLite writes vs CRDT-wrapped writes using the wide [Types]
/// row (same shape idea as legacy Drift `TableWithEveryColumnType`).
class TypesTableBenchmark extends AsyncBenchmarkBase {
TypesTableBenchmark(
super.name, {
required this.crdtEnabled,
required this.operation,
required this.rowCount,
});
/// Minimal blob column payload (shared; column stays non-null with zero bytes).
static final ByteData _emptyBlob = ByteData(0);
final bool crdtEnabled;
final Operation operation;
final int rowCount;
static const _clientUrl = 'http://localhost:8081/';
late final File _dbFile;
late final ClientDatabaseSession _plainSession;
CrdtDatabaseSession? _crdtSession;
final UuidValue _userId = const Uuid().v7obj();
int _valueSeq = 0;
int _lastDatabaseSize = 0;
int _lastRowsCount = 0;
List<Types> _seededRows = [];
Types _createTypesRow(int i, DateTime baseTimestamp) {
return Types(
aBool: i.isEven,
aDateTime: baseTimestamp.add(Duration(seconds: i)),
aText: 'Text $i',
anInt: i,
anInt64: BigInt.from(i),
aReal: i.toDouble(),
aBlob: _emptyBlob,
anEnum: null,
optionalText: null,
optionalUuid: const Uuid().v7obj(),
);
}
Future<List<Types>> _insertTypes(int count) async {
final baseTimestamp = DateTime.now();
final start = _valueSeq;
_valueSeq += count;
final rows = List.generate(
count,
(j) => _createTypesRow(start + j, baseTimestamp),
);
if (crdtEnabled) {
return _crdtSession!.db.transactionForUser(_userId, (tx) async {
return Types.db.insert(_crdtSession!, rows, transaction: tx);
});
}
return Types.db.insert(_plainSession, rows);
}
Future<void> _deleteTypes(List<Types> rows) async {
if (rows.isEmpty) {
return;
}
if (crdtEnabled) {
await _crdtSession!.db.transactionForUser(_userId, (tx) async {
await Types.db.delete(_crdtSession!, rows, transaction: tx);
});
} else {
await Types.db.delete(_plainSession, rows);
}
}
Future<void> _updateTypesInPlace() async {
final baseTimestamp = DateTime.now();
final updated = _seededRows.map((row) {
final i = _valueSeq++;
return row.copyWith(
aBool: i.isEven,
aDateTime: baseTimestamp.add(Duration(seconds: i)),
aText: 'Text $i',
anInt: i,
anInt64: BigInt.from(i),
aReal: i.toDouble(),
aBlob: _emptyBlob,
optionalUuid: const Uuid().v7obj(),
);
}).toList();
if (crdtEnabled) {
_seededRows = await _crdtSession!.db.transactionForUser(
_userId,
(tx) async {
return Types.db.update(
_crdtSession!,
updated,
columns: (t) => [
t.aBool,
t.aDateTime,
t.aText,
t.anInt,
t.anInt64,
t.aReal,
t.aBlob,
t.optionalUuid,
],
transaction: tx,
);
},
);
} else {
_seededRows = await Types.db.update(
_plainSession,
updated,
columns: (t) => [
t.aBool,
t.aDateTime,
t.aText,
t.anInt,
t.anInt64,
t.aReal,
t.aBlob,
t.optionalUuid,
],
);
}
}
Future<void> _bootstrapDatabase() async {
await clearUserTables(_plainSession);
CrdtUserManager.clearCache();
HlcManager.reset();
final wrapped = CrdtDatabaseSession.wraps(
_plainSession,
syncTables: benchmarkSyncTables,
);
await wrapped.db.initialize();
_crdtSession = crdtEnabled ? wrapped : null;
}
@override
Future<void> setup() async {
_valueSeq = 0;
final dbPath = p.join(
Directory.systemTemp.path,
'offline_sync_benchmark_$name.db',
);
_dbFile = File(dbPath);
if (_dbFile.existsSync()) {
_dbFile.deleteSync();
}
_plainSession = await Client(_clientUrl).createSession(
_dbFile.path,
isDebugMode: true,
);
await _bootstrapDatabase();
switch (operation) {
case Operation.insert:
_seededRows = [];
case Operation.update:
_seededRows = await _insertTypes(rowCount);
case Operation.delete:
_seededRows = [];
}
}
@override
Future<void> warmup() async {}
@override
Future<void> run() async {
switch (operation) {
case Operation.insert:
await _insertTypes(rowCount);
case Operation.update:
await _updateTypesInPlace();
case Operation.delete:
await _deleteTypes(_seededRows);
}
}
Future<void> _prepareDeleteCycle() async {
await _bootstrapDatabase();
_seededRows = await _insertTypes(rowCount);
}
Future<void> _timedDeleteBatch() async {
await _deleteTypes(_seededRows);
}
@override
Future<double> measure() async {
if (operation == Operation.delete) {
await setup();
try {
await AsyncBenchmarkBase.measureFor(() async {}, 100);
const minimumMicros = 2000 * 1000;
final watch = Stopwatch()..start();
var totalTimedMicros = 0.0;
var timedIterations = 0;
while (watch.elapsedMicroseconds < minimumMicros) {
await _prepareDeleteCycle();
final sw = Stopwatch()..start();
await _timedDeleteBatch();
totalTimedMicros += sw.elapsedMicroseconds;
timedIterations++;
}
return totalTimedMicros / timedIterations;
} finally {
await teardown();
}
}
return super.measure();
}
@override
Future<(double, int)> report() async {
final averageMicroseconds = await measure();
return (averageMicroseconds, measureStorage());
}
@override
Future<void> teardown() async {
try {
await _plainSession.db.unsafeExecute('PRAGMA wal_checkpoint(TRUNCATE)');
} on Exception {
// WAL checkpoint is best-effort (e.g. non-SQLite tests).
}
_lastDatabaseSize = _sqliteDbFootprintBytes(_dbFile);
_lastRowsCount = await Types.db.count(_plainSession);
await _plainSession.close();
if (_dbFile.existsSync()) {
_dbFile.deleteSync();
}
for (final companion in [
File('${_dbFile.path}-wal'),
File('${_dbFile.path}-shm'),
]) {
if (companion.existsSync()) {
companion.deleteSync();
}
}
}
int measureStorage() {
if (operation == Operation.delete) {
return _lastDatabaseSize;
}
if (_lastDatabaseSize == 0) {
throw Exception('Last database size is not set.');
}
if (_lastRowsCount < rowCount) {
throw Exception(
'Rows count is $_lastRowsCount but expected at least $rowCount.',
);
}
return _lastDatabaseSize ~/ (_lastRowsCount / rowCount);
}
}
/// Bytes used by SQLite for [mainDb], including WAL sidecars (often omitted by
/// `mainDb.lengthSync()` alone).
int _sqliteDbFootprintBytes(File mainDb) {
var total = mainDb.existsSync() ? mainDb.lengthSync() : 0;
final wal = File('${mainDb.path}-wal');
final shm = File('${mainDb.path}-shm');
if (wal.existsSync()) {
total += wal.lengthSync();
}
if (shm.existsSync()) {
total += shm.lengthSync();
}
return total;
}

View file

@ -0,0 +1,53 @@
// Formatter helpers for CLI output only.
import 'package:intl/intl.dart';
final NumberFormat formatter0 = NumberFormat.decimalPatternDigits(
decimalDigits: 0,
);
final NumberFormat formatter2 = NumberFormat.decimalPatternDigits(
decimalDigits: 2,
);
extension FormattedUnits on num {
String toFormattedDuration() {
var time = this;
var unit = 1;
while (time.abs() > 1000 && unit < Duration.microsecondsPerSecond) {
time /= 1000;
unit *= 1000;
}
while (unit > Duration.microsecondsPerMinute && time.abs() > 60) {
time /= 60;
unit *= 60;
}
return '${formatter2.format(time)} ${switch (unit) {
1 => 'μs',
Duration.millisecondsPerSecond => 'ms',
Duration.microsecondsPerSecond => 's',
Duration.microsecondsPerMinute => 'min',
Duration.microsecondsPerHour => 'h',
_ => throw Exception('Unexpected time unit: $unit'),
}}';
}
String toFormattedStorageSize() {
var storageIncrease = toDouble();
var storageUnit = 1;
while (storageIncrease > 1024) {
storageIncrease /= 1024;
storageUnit *= 1024;
}
final storageUnitString = switch (storageUnit) {
1 => 'B',
1024 => 'KB',
const (1024 * 1024) => 'MB',
_ => throw Exception('Unexpected storage unit: $storageUnit'),
};
return '${formatter2.format(storageIncrease)} $storageUnitString';
}
}

View file

@ -0,0 +1,70 @@
// Pretty-printing benchmark comparison output.
import 'benchmark.dart';
import 'conversion.dart';
void printPerformanceImpact(
BenchmarkResults benchmarkResults, {
required int rowCount,
bool runningInCI = false,
}) {
print(
'${runningInCI ? '```' : ''}'
'\n📊 ${benchmarkResults.operation.name.toUpperCase()} performance impact:',
);
final (baselineTime, _) = benchmarkResults.baseline;
final (crdtTime, _) = benchmarkResults.crdt;
final runDelayUs = crdtTime - baselineTime;
final slowdown = runDelayUs / baselineTime * 100;
final baselineDelay = baselineTime.toFormattedDuration();
final crdtDelay = crdtTime.toFormattedDuration();
final runDelay = runDelayUs.toFormattedDuration();
final runDelayPerOperation = (runDelayUs / rowCount).toFormattedDuration();
print(' Time: $baselineDelay --> $crdtDelay ($runDelay)');
print(' CRDT overhead: ${formatter2.format(slowdown)}% slower');
print(
' Delay per ${benchmarkResults.operation.name}: $runDelayPerOperation',
);
if (runningInCI) print('```');
}
void printStorageImpact(
BenchmarkResults benchmarkResults, {
required int rowCount,
bool runningInCI = false,
}) {
print('${runningInCI ? '```' : ''}\n💽 Storage impact:');
final (_, baselineSize) = benchmarkResults.baseline;
final (_, crdtSize) = benchmarkResults.crdt;
final storageIncrease = crdtSize - baselineSize;
final storageIncPercent = storageIncrease / baselineSize * 100;
final extraStoragePerRow = storageIncrease / rowCount;
final storageIncreaseVolume = storageIncPercent > 100
? '(x${formatter2.format(storageIncPercent / 100)})'
: '(+${(crdtSize - baselineSize).toFormattedStorageSize()})';
print(
' Storage size: ${baselineSize.toFormattedStorageSize()} '
'--> ${crdtSize.toFormattedStorageSize()} $storageIncreaseVolume',
);
print(' CRDT overhead: ${formatter2.format(storageIncPercent)}% increase');
print(
' Extra storage per row: ${extraStoragePerRow.toFormattedStorageSize()}',
);
if (runningInCI) print('```');
}
class BenchmarkResults {
const BenchmarkResults({
required this.operation,
required this.baseline,
required this.crdt,
});
final Operation operation;
final (double, int) baseline;
final (double, int) crdt;
}

View file

@ -0,0 +1,20 @@
// Progress-style logging for the benchmark CLI.
Future<T> runWithProgress<T>(
String message,
Future<T> Function() runner, {
bool Function(T result)? validator,
bool skipProgress = false,
}) async {
if (!skipProgress) {
print('$message…');
}
final result = await runner();
final ok = validator?.call(result) ?? true;
if (!skipProgress) {
print(
ok ? ' done.' : ' failed validation (CRDT not slower than baseline).',
);
}
return result;
}

View file

@ -0,0 +1,31 @@
// Keeps CRDT scope aligned with integration tests plus the benchmark table.
import 'package:serverpod_database/serverpod_database.dart';
import 'package:serverpod_offline_sync_test_client/serverpod_offline_sync_test_client.dart';
/// [Types] is benchmark-only; the rest mirrors `client_session.dart` sync scope.
List<Table> get benchmarkSyncTables => [
Address.t,
City.t,
Company.t,
Organization.t,
Person.t,
Town.t,
Types.t,
Unique.t,
UniqueUuid.t,
];
Future<void> clearUserTables(DatabaseSession session) async {
await session.db.unsafeExecute('PRAGMA foreign_keys = OFF');
final result = await session.db.unsafeQuery('''
SELECT name
FROM sqlite_master
WHERE (type = 'table') AND (name NOT LIKE 'serverpod_%')
''');
for (final row in result) {
final tableName = row[0] as String;
await session.db.unsafeExecute('DELETE FROM "$tableName"');
}
await session.db.unsafeExecute('PRAGMA foreign_keys = ON');
}

View file

@ -4,28 +4,23 @@ part of 'database.dart';
// ignore_for_file: type=lint // ignore_for_file: type=lint
class $TableWithEveryColumnTypeTable extends TableWithEveryColumnType class $TableWithEveryColumnTypeTable extends TableWithEveryColumnType
with with TableInfo<$TableWithEveryColumnTypeTable, TableWithEveryColumnTypeData> {
TableInfo<
$TableWithEveryColumnTypeTable,
TableWithEveryColumnTypeData
> {
@override @override
final GeneratedDatabase attachedDatabase; final GeneratedDatabase attachedDatabase;
final String? _alias; final String? _alias;
$TableWithEveryColumnTypeTable(this.attachedDatabase, [this._alias]); $TableWithEveryColumnTypeTable(this.attachedDatabase, [this._alias]);
@override @override
late final GeneratedColumnWithTypeConverter<RowId, int> id = late final GeneratedColumnWithTypeConverter<RowId, int> id = GeneratedColumn<int>(
GeneratedColumn<int>( 'id',
'id', aliasedName,
aliasedName, false,
false, hasAutoIncrement: true,
hasAutoIncrement: true, type: DriftSqlType.int,
type: DriftSqlType.int, requiredDuringInsert: false,
requiredDuringInsert: false, defaultConstraints: GeneratedColumn.constraintIsAlways(
defaultConstraints: GeneratedColumn.constraintIsAlways( 'PRIMARY KEY AUTOINCREMENT',
'PRIMARY KEY AUTOINCREMENT', ),
), ).withConverter<RowId>($TableWithEveryColumnTypeTable.$converterid);
).withConverter<RowId>($TableWithEveryColumnTypeTable.$converterid);
static const VerificationMeta _aBoolMeta = const VerificationMeta('aBool'); static const VerificationMeta _aBoolMeta = const VerificationMeta('aBool');
@override @override
late final GeneratedColumn<bool> aBool = GeneratedColumn<bool>( late final GeneratedColumn<bool> aBool = GeneratedColumn<bool>(
@ -255,8 +250,7 @@ class $TableWithEveryColumnTypeTable extends TableWithEveryColumnType
data['${effectivePrefix}an_int_enum'], data['${effectivePrefix}an_int_enum'],
), ),
), ),
aTextWithConverter: $TableWithEveryColumnTypeTable aTextWithConverter: $TableWithEveryColumnTypeTable.$converteraTextWithConvertern
.$converteraTextWithConvertern
.fromSql( .fromSql(
attachedDatabase.typeMapping.read( attachedDatabase.typeMapping.read(
DriftSqlType.string, DriftSqlType.string,
@ -365,36 +359,22 @@ class TableWithEveryColumnTypeData extends DataClass
TableWithEveryColumnTypeCompanion toCompanion(bool nullToAbsent) { TableWithEveryColumnTypeCompanion toCompanion(bool nullToAbsent) {
return TableWithEveryColumnTypeCompanion( return TableWithEveryColumnTypeCompanion(
id: Value(id), id: Value(id),
aBool: aBool == null && nullToAbsent aBool: aBool == null && nullToAbsent ? const Value.absent() : Value(aBool),
? const Value.absent()
: Value(aBool),
aDateTime: aDateTime == null && nullToAbsent aDateTime: aDateTime == null && nullToAbsent
? const Value.absent() ? const Value.absent()
: Value(aDateTime), : Value(aDateTime),
aText: aText == null && nullToAbsent aText: aText == null && nullToAbsent ? const Value.absent() : Value(aText),
? const Value.absent() anInt: anInt == null && nullToAbsent ? const Value.absent() : Value(anInt),
: Value(aText), anInt64: anInt64 == null && nullToAbsent ? const Value.absent() : Value(anInt64),
anInt: anInt == null && nullToAbsent aReal: aReal == null && nullToAbsent ? const Value.absent() : Value(aReal),
? const Value.absent() aBlob: aBlob == null && nullToAbsent ? const Value.absent() : Value(aBlob),
: Value(anInt),
anInt64: anInt64 == null && nullToAbsent
? const Value.absent()
: Value(anInt64),
aReal: aReal == null && nullToAbsent
? const Value.absent()
: Value(aReal),
aBlob: aBlob == null && nullToAbsent
? const Value.absent()
: Value(aBlob),
anIntEnum: anIntEnum == null && nullToAbsent anIntEnum: anIntEnum == null && nullToAbsent
? const Value.absent() ? const Value.absent()
: Value(anIntEnum), : Value(anIntEnum),
aTextWithConverter: aTextWithConverter == null && nullToAbsent aTextWithConverter: aTextWithConverter == null && nullToAbsent
? const Value.absent() ? const Value.absent()
: Value(aTextWithConverter), : Value(aTextWithConverter),
aUuid: aUuid == null && nullToAbsent aUuid: aUuid == null && nullToAbsent ? const Value.absent() : Value(aUuid),
? const Value.absent()
: Value(aUuid),
); );
} }
@ -417,8 +397,7 @@ class TableWithEveryColumnTypeData extends DataClass
anIntEnum: $TableWithEveryColumnTypeTable.$converteranIntEnumn.fromJson( anIntEnum: $TableWithEveryColumnTypeTable.$converteranIntEnumn.fromJson(
serializer.fromJson<int?>(json['an_int_enum']), serializer.fromJson<int?>(json['an_int_enum']),
), ),
aTextWithConverter: $TableWithEveryColumnTypeTable aTextWithConverter: $TableWithEveryColumnTypeTable.$converteraTextWithConvertern
.$converteraTextWithConvertern
.fromJson( .fromJson(
serializer.fromJson<Map<dynamic, dynamic>?>(json['insert']), serializer.fromJson<Map<dynamic, dynamic>?>(json['insert']),
), ),
@ -712,8 +691,7 @@ class TableWithEveryColumnTypeCompanion
abstract class _$CrdtBenchmarkDatabase extends GeneratedDatabase { abstract class _$CrdtBenchmarkDatabase extends GeneratedDatabase {
_$CrdtBenchmarkDatabase(QueryExecutor e) : super(e); _$CrdtBenchmarkDatabase(QueryExecutor e) : super(e);
$CrdtBenchmarkDatabaseManager get managers => $CrdtBenchmarkDatabaseManager get managers => $CrdtBenchmarkDatabaseManager(this);
$CrdtBenchmarkDatabaseManager(this);
late final $TableWithEveryColumnTypeTable tableWithEveryColumnType = late final $TableWithEveryColumnTypeTable tableWithEveryColumnType =
$TableWithEveryColumnTypeTable(this); $TableWithEveryColumnTypeTable(this);
@override @override
@ -766,11 +744,10 @@ class $$TableWithEveryColumnTypeTableFilterComposer
super.$addJoinBuilderToRootComposer, super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer, super.$removeJoinBuilderFromRootComposer,
}); });
ColumnWithTypeConverterFilters<RowId, RowId, int> get id => ColumnWithTypeConverterFilters<RowId, RowId, int> get id => $composableBuilder(
$composableBuilder( column: $table.id,
column: $table.id, builder: (column) => ColumnWithTypeConverterFilters(column),
builder: (column) => ColumnWithTypeConverterFilters(column), );
);
ColumnFilters<bool> get aBool => $composableBuilder( ColumnFilters<bool> get aBool => $composableBuilder(
column: $table.aBool, column: $table.aBool,
@ -926,11 +903,11 @@ class $$TableWithEveryColumnTypeTableAnnotationComposer
GeneratedColumnWithTypeConverter<TodoStatus?, int> get anIntEnum => GeneratedColumnWithTypeConverter<TodoStatus?, int> get anIntEnum =>
$composableBuilder(column: $table.anIntEnum, builder: (column) => column); $composableBuilder(column: $table.anIntEnum, builder: (column) => column);
GeneratedColumnWithTypeConverter<MyCustomObject?, String> GeneratedColumnWithTypeConverter<MyCustomObject?, String> get aTextWithConverter =>
get aTextWithConverter => $composableBuilder( $composableBuilder(
column: $table.aTextWithConverter, column: $table.aTextWithConverter,
builder: (column) => column, builder: (column) => column,
); );
GeneratedColumn<UuidValue> get aUuid => GeneratedColumn<UuidValue> get aUuid =>
$composableBuilder(column: $table.aUuid, builder: (column) => column); $composableBuilder(column: $table.aUuid, builder: (column) => column);
@ -965,16 +942,14 @@ class $$TableWithEveryColumnTypeTableTableManager
TableManagerState( TableManagerState(
db: db, db: db,
table: table, table: table,
createFilteringComposer: () => createFilteringComposer: () => $$TableWithEveryColumnTypeTableFilterComposer(
$$TableWithEveryColumnTypeTableFilterComposer( $db: db,
$db: db, $table: table,
$table: table, ),
), createOrderingComposer: () => $$TableWithEveryColumnTypeTableOrderingComposer(
createOrderingComposer: () => $db: db,
$$TableWithEveryColumnTypeTableOrderingComposer( $table: table,
$db: db, ),
$table: table,
),
createComputedFieldComposer: () => createComputedFieldComposer: () =>
$$TableWithEveryColumnTypeTableAnnotationComposer( $$TableWithEveryColumnTypeTableAnnotationComposer(
$db: db, $db: db,
@ -991,8 +966,7 @@ class $$TableWithEveryColumnTypeTableTableManager
Value<double?> aReal = const Value.absent(), Value<double?> aReal = const Value.absent(),
Value<Uint8List?> aBlob = const Value.absent(), Value<Uint8List?> aBlob = const Value.absent(),
Value<TodoStatus?> anIntEnum = const Value.absent(), Value<TodoStatus?> anIntEnum = const Value.absent(),
Value<MyCustomObject?> aTextWithConverter = Value<MyCustomObject?> aTextWithConverter = const Value.absent(),
const Value.absent(),
Value<UuidValue?> aUuid = const Value.absent(), Value<UuidValue?> aUuid = const Value.absent(),
}) => TableWithEveryColumnTypeCompanion( }) => TableWithEveryColumnTypeCompanion(
id: id, id: id,
@ -1018,8 +992,7 @@ class $$TableWithEveryColumnTypeTableTableManager
Value<double?> aReal = const Value.absent(), Value<double?> aReal = const Value.absent(),
Value<Uint8List?> aBlob = const Value.absent(), Value<Uint8List?> aBlob = const Value.absent(),
Value<TodoStatus?> anIntEnum = const Value.absent(), Value<TodoStatus?> anIntEnum = const Value.absent(),
Value<MyCustomObject?> aTextWithConverter = Value<MyCustomObject?> aTextWithConverter = const Value.absent(),
const Value.absent(),
Value<UuidValue?> aUuid = const Value.absent(), Value<UuidValue?> aUuid = const Value.absent(),
}) => TableWithEveryColumnTypeCompanion.insert( }) => TableWithEveryColumnTypeCompanion.insert(
id: id, id: id,

View file

@ -281,9 +281,7 @@ class CrdtDataEntry extends DataClass implements Insertable<CrdtDataEntry> {
return CrdtDataEntry( return CrdtDataEntry(
userId: data.userId.present ? data.userId.value : this.userId, userId: data.userId.present ? data.userId.value : this.userId,
tblName: data.tblName.present ? data.tblName.value : this.tblName, tblName: data.tblName.present ? data.tblName.value : this.tblName,
columnName: data.columnName.present columnName: data.columnName.present ? data.columnName.value : this.columnName,
? data.columnName.value
: this.columnName,
rowId: data.rowId.present ? data.rowId.value : this.rowId, rowId: data.rowId.present ? data.rowId.value : this.rowId,
hlcTimestamp: data.hlcTimestamp.present hlcTimestamp: data.hlcTimestamp.present
? data.hlcTimestamp.value ? data.hlcTimestamp.value
@ -781,16 +779,12 @@ class CrdtNormalizedDataEntry extends DataClass
return CrdtNormalizedDataEntry( return CrdtNormalizedDataEntry(
userId: data.userId.present ? data.userId.value : this.userId, userId: data.userId.present ? data.userId.value : this.userId,
tblName: data.tblName.present ? data.tblName.value : this.tblName, tblName: data.tblName.present ? data.tblName.value : this.tblName,
columnName: data.columnName.present columnName: data.columnName.present ? data.columnName.value : this.columnName,
? data.columnName.value
: this.columnName,
rowId: data.rowId.present ? data.rowId.value : this.rowId, rowId: data.rowId.present ? data.rowId.value : this.rowId,
hlcTimestamp: data.hlcTimestamp.present hlcTimestamp: data.hlcTimestamp.present
? data.hlcTimestamp.value ? data.hlcTimestamp.value
: this.hlcTimestamp, : this.hlcTimestamp,
hlcCounter: data.hlcCounter.present hlcCounter: data.hlcCounter.present ? data.hlcCounter.value : this.hlcCounter,
? data.hlcCounter.value
: this.hlcCounter,
hlcNodeId: data.hlcNodeId.present ? data.hlcNodeId.value : this.hlcNodeId, hlcNodeId: data.hlcNodeId.present ? data.hlcNodeId.value : this.hlcNodeId,
rawValue: data.rawValue.present ? data.rawValue.value : this.rawValue, rawValue: data.rawValue.present ? data.rawValue.value : this.rawValue,
); );
@ -1133,14 +1127,11 @@ class $CrdtControlTableTable extends CrdtControlTable
return $CrdtControlTableTable(attachedDatabase, alias); return $CrdtControlTableTable(attachedDatabase, alias);
} }
static TypeConverter<Hlc?, String?> $converterlastSyncHlc = static TypeConverter<Hlc?, String?> $converterlastSyncHlc = nullableHlcConverter;
nullableHlcConverter; static TypeConverter<Hlc?, String?> $converterlastApplyHlc = nullableHlcConverter;
static TypeConverter<Hlc?, String?> $converterlastApplyHlc =
nullableHlcConverter;
} }
class CrdtControlEntry extends DataClass class CrdtControlEntry extends DataClass implements Insertable<CrdtControlEntry> {
implements Insertable<CrdtControlEntry> {
/// Identifier for the user or client. /// Identifier for the user or client.
final String userId; final String userId;
@ -1253,9 +1244,7 @@ class CrdtControlEntry extends DataClass
schemaVersion: data.schemaVersion.present schemaVersion: data.schemaVersion.present
? data.schemaVersion.value ? data.schemaVersion.value
: this.schemaVersion, : this.schemaVersion,
lastSyncHlc: data.lastSyncHlc.present lastSyncHlc: data.lastSyncHlc.present ? data.lastSyncHlc.value : this.lastSyncHlc,
? data.lastSyncHlc.value
: this.lastSyncHlc,
lastApplyHlc: data.lastApplyHlc.present lastApplyHlc: data.lastApplyHlc.present
? data.lastApplyHlc.value ? data.lastApplyHlc.value
: this.lastApplyHlc, : this.lastApplyHlc,
@ -1764,13 +1753,12 @@ class $CrdtMergeHlcTableTable extends CrdtMergeHlcTable
DriftSqlType.string, DriftSqlType.string,
data['${effectivePrefix}node_id'], data['${effectivePrefix}node_id'],
)!, )!,
lastReceivedHlc: $CrdtMergeHlcTableTable.$converterlastReceivedHlc lastReceivedHlc: $CrdtMergeHlcTableTable.$converterlastReceivedHlc.fromSql(
.fromSql( attachedDatabase.typeMapping.read(
attachedDatabase.typeMapping.read( DriftSqlType.string,
DriftSqlType.string, data['${effectivePrefix}last_received_hlc'],
data['${effectivePrefix}last_received_hlc'], )!,
)!, ),
),
); );
} }
@ -1782,8 +1770,7 @@ class $CrdtMergeHlcTableTable extends CrdtMergeHlcTable
static TypeConverter<Hlc, String> $converterlastReceivedHlc = hlcConverter; static TypeConverter<Hlc, String> $converterlastReceivedHlc = hlcConverter;
} }
class CrdtMergeHlcEntry extends DataClass class CrdtMergeHlcEntry extends DataClass implements Insertable<CrdtMergeHlcEntry> {
implements Insertable<CrdtMergeHlcEntry> {
/// Identifier for the user or client. /// Identifier for the user or client.
final String userId; final String userId;
@ -1971,10 +1958,8 @@ abstract class _$CrdtDatabase extends GeneratedDatabase {
late final $CrdtControlTableTable crdtControlTable = $CrdtControlTableTable( late final $CrdtControlTableTable crdtControlTable = $CrdtControlTableTable(
this, this,
); );
late final $CrdtHlcStateTableTable crdtHlcStateTable = late final $CrdtHlcStateTableTable crdtHlcStateTable = $CrdtHlcStateTableTable(this);
$CrdtHlcStateTableTable(this); late final $CrdtMergeHlcTableTable crdtMergeHlcTable = $CrdtMergeHlcTableTable(this);
late final $CrdtMergeHlcTableTable crdtMergeHlcTable =
$CrdtMergeHlcTableTable(this);
@override @override
Iterable<TableInfo<Table, Object?>> get allTables => Iterable<TableInfo<Table, Object?>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>(); allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@ -2114,11 +2099,10 @@ class $$CrdtDataTableTableAnnotationComposer
GeneratedColumn<String> get rowId => GeneratedColumn<String> get rowId =>
$composableBuilder(column: $table.rowId, builder: (column) => column); $composableBuilder(column: $table.rowId, builder: (column) => column);
GeneratedColumnWithTypeConverter<Hlc, String> get hlcTimestamp => GeneratedColumnWithTypeConverter<Hlc, String> get hlcTimestamp => $composableBuilder(
$composableBuilder( column: $table.hlcTimestamp,
column: $table.hlcTimestamp, builder: (column) => column,
builder: (column) => column, );
);
GeneratedColumn<DriftAny> get rawValue => GeneratedColumn<DriftAny> get rawValue =>
$composableBuilder(column: $table.rawValue, builder: (column) => column); $composableBuilder(column: $table.rawValue, builder: (column) => column);
@ -2402,16 +2386,14 @@ class $$CrdtNormalizedDataTableTableTableManager
TableManagerState( TableManagerState(
db: db, db: db,
table: table, table: table,
createFilteringComposer: () => createFilteringComposer: () => $$CrdtNormalizedDataTableTableFilterComposer(
$$CrdtNormalizedDataTableTableFilterComposer( $db: db,
$db: db, $table: table,
$table: table, ),
), createOrderingComposer: () => $$CrdtNormalizedDataTableTableOrderingComposer(
createOrderingComposer: () => $db: db,
$$CrdtNormalizedDataTableTableOrderingComposer( $table: table,
$db: db, ),
$table: table,
),
createComputedFieldComposer: () => createComputedFieldComposer: () =>
$$CrdtNormalizedDataTableTableAnnotationComposer( $$CrdtNormalizedDataTableTableAnnotationComposer(
$db: db, $db: db,
@ -2614,17 +2596,15 @@ class $$CrdtControlTableTableAnnotationComposer
builder: (column) => column, builder: (column) => column,
); );
GeneratedColumnWithTypeConverter<Hlc?, String> get lastSyncHlc => GeneratedColumnWithTypeConverter<Hlc?, String> get lastSyncHlc => $composableBuilder(
$composableBuilder( column: $table.lastSyncHlc,
column: $table.lastSyncHlc, builder: (column) => column,
builder: (column) => column, );
);
GeneratedColumnWithTypeConverter<Hlc?, String> get lastApplyHlc => GeneratedColumnWithTypeConverter<Hlc?, String> get lastApplyHlc => $composableBuilder(
$composableBuilder( column: $table.lastApplyHlc,
column: $table.lastApplyHlc, builder: (column) => column,
builder: (column) => column, );
);
} }
class $$CrdtControlTableTableTableManager class $$CrdtControlTableTableTableManager
@ -2640,11 +2620,7 @@ class $$CrdtControlTableTableTableManager
$$CrdtControlTableTableUpdateCompanionBuilder, $$CrdtControlTableTableUpdateCompanionBuilder,
( (
CrdtControlEntry, CrdtControlEntry,
BaseReferences< BaseReferences<_$CrdtDatabase, $CrdtControlTableTable, CrdtControlEntry>,
_$CrdtDatabase,
$CrdtControlTableTable,
CrdtControlEntry
>,
), ),
CrdtControlEntry, CrdtControlEntry,
PrefetchHooks Function() PrefetchHooks Function()
@ -2718,11 +2694,7 @@ typedef $$CrdtControlTableTableProcessedTableManager =
$$CrdtControlTableTableUpdateCompanionBuilder, $$CrdtControlTableTableUpdateCompanionBuilder,
( (
CrdtControlEntry, CrdtControlEntry,
BaseReferences< BaseReferences<_$CrdtDatabase, $CrdtControlTableTable, CrdtControlEntry>,
_$CrdtDatabase,
$CrdtControlTableTable,
CrdtControlEntry
>,
), ),
CrdtControlEntry, CrdtControlEntry,
PrefetchHooks Function() PrefetchHooks Function()
@ -2826,11 +2798,7 @@ class $$CrdtHlcStateTableTableTableManager
$$CrdtHlcStateTableTableUpdateCompanionBuilder, $$CrdtHlcStateTableTableUpdateCompanionBuilder,
( (
CrdtHlcEntry, CrdtHlcEntry,
BaseReferences< BaseReferences<_$CrdtDatabase, $CrdtHlcStateTableTable, CrdtHlcEntry>,
_$CrdtDatabase,
$CrdtHlcStateTableTable,
CrdtHlcEntry
>,
), ),
CrdtHlcEntry, CrdtHlcEntry,
PrefetchHooks Function() PrefetchHooks Function()
@ -2846,11 +2814,10 @@ class $$CrdtHlcStateTableTableTableManager
$$CrdtHlcStateTableTableFilterComposer($db: db, $table: table), $$CrdtHlcStateTableTableFilterComposer($db: db, $table: table),
createOrderingComposer: () => createOrderingComposer: () =>
$$CrdtHlcStateTableTableOrderingComposer($db: db, $table: table), $$CrdtHlcStateTableTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () => createComputedFieldComposer: () => $$CrdtHlcStateTableTableAnnotationComposer(
$$CrdtHlcStateTableTableAnnotationComposer( $db: db,
$db: db, $table: table,
$table: table, ),
),
updateCompanionCallback: updateCompanionCallback:
({ ({
Value<String> userId = const Value.absent(), Value<String> userId = const Value.absent(),
@ -3001,11 +2968,7 @@ class $$CrdtMergeHlcTableTableTableManager
$$CrdtMergeHlcTableTableUpdateCompanionBuilder, $$CrdtMergeHlcTableTableUpdateCompanionBuilder,
( (
CrdtMergeHlcEntry, CrdtMergeHlcEntry,
BaseReferences< BaseReferences<_$CrdtDatabase, $CrdtMergeHlcTableTable, CrdtMergeHlcEntry>,
_$CrdtDatabase,
$CrdtMergeHlcTableTable,
CrdtMergeHlcEntry
>,
), ),
CrdtMergeHlcEntry, CrdtMergeHlcEntry,
PrefetchHooks Function() PrefetchHooks Function()
@ -3021,11 +2984,10 @@ class $$CrdtMergeHlcTableTableTableManager
$$CrdtMergeHlcTableTableFilterComposer($db: db, $table: table), $$CrdtMergeHlcTableTableFilterComposer($db: db, $table: table),
createOrderingComposer: () => createOrderingComposer: () =>
$$CrdtMergeHlcTableTableOrderingComposer($db: db, $table: table), $$CrdtMergeHlcTableTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () => createComputedFieldComposer: () => $$CrdtMergeHlcTableTableAnnotationComposer(
$$CrdtMergeHlcTableTableAnnotationComposer( $db: db,
$db: db, $table: table,
$table: table, ),
),
updateCompanionCallback: updateCompanionCallback:
({ ({
Value<String> userId = const Value.absent(), Value<String> userId = const Value.absent(),
@ -3070,11 +3032,7 @@ typedef $$CrdtMergeHlcTableTableProcessedTableManager =
$$CrdtMergeHlcTableTableUpdateCompanionBuilder, $$CrdtMergeHlcTableTableUpdateCompanionBuilder,
( (
CrdtMergeHlcEntry, CrdtMergeHlcEntry,
BaseReferences< BaseReferences<_$CrdtDatabase, $CrdtMergeHlcTableTable, CrdtMergeHlcEntry>,
_$CrdtDatabase,
$CrdtMergeHlcTableTable,
CrdtMergeHlcEntry
>,
), ),
CrdtMergeHlcEntry, CrdtMergeHlcEntry,
PrefetchHooks Function() PrefetchHooks Function()

File diff suppressed because it is too large Load diff

View file

@ -3,25 +3,23 @@
part of 'migration.dart'; part of 'migration.dart';
// ignore_for_file: type=lint // ignore_for_file: type=lint
class $CategoriesTable extends Categories class $CategoriesTable extends Categories with TableInfo<$CategoriesTable, Category> {
with TableInfo<$CategoriesTable, Category> {
@override @override
final GeneratedDatabase attachedDatabase; final GeneratedDatabase attachedDatabase;
final String? _alias; final String? _alias;
$CategoriesTable(this.attachedDatabase, [this._alias]); $CategoriesTable(this.attachedDatabase, [this._alias]);
@override @override
late final GeneratedColumnWithTypeConverter<RowId, int> id = late final GeneratedColumnWithTypeConverter<RowId, int> id = GeneratedColumn<int>(
GeneratedColumn<int>( 'id',
'id', aliasedName,
aliasedName, false,
false, hasAutoIncrement: true,
hasAutoIncrement: true, type: DriftSqlType.int,
type: DriftSqlType.int, requiredDuringInsert: false,
requiredDuringInsert: false, defaultConstraints: GeneratedColumn.constraintIsAlways(
defaultConstraints: GeneratedColumn.constraintIsAlways( 'PRIMARY KEY AUTOINCREMENT',
'PRIMARY KEY AUTOINCREMENT', ),
), ).withConverter<RowId>($CategoriesTable.$converterid);
).withConverter<RowId>($CategoriesTable.$converterid);
static const VerificationMeta _descriptionMeta = const VerificationMeta( static const VerificationMeta _descriptionMeta = const VerificationMeta(
'description', 'description',
); );
@ -44,21 +42,21 @@ class $CategoriesTable extends Categories
requiredDuringInsert: false, requiredDuringInsert: false,
defaultValue: const Constant(0), defaultValue: const Constant(0),
).withConverter<CategoryPriority>($CategoriesTable.$converterpriority); ).withConverter<CategoryPriority>($CategoriesTable.$converterpriority);
static const VerificationMeta _descriptionInUpperCaseMeta = static const VerificationMeta _descriptionInUpperCaseMeta = const VerificationMeta(
const VerificationMeta('descriptionInUpperCase'); 'descriptionInUpperCase',
);
@override @override
late final GeneratedColumn<String> descriptionInUpperCase = late final GeneratedColumn<String> descriptionInUpperCase = GeneratedColumn<String>(
GeneratedColumn<String>( 'description_in_upper_case',
'description_in_upper_case', aliasedName,
aliasedName, false,
false, generatedAs: GeneratedAs(
generatedAs: GeneratedAs( StringExpressionOperators(description).upper(),
StringExpressionOperators(description).upper(), false,
false, ),
), type: DriftSqlType.string,
type: DriftSqlType.string, requiredDuringInsert: false,
requiredDuringInsert: false, );
);
@override @override
List<GeneratedColumn> get $columns => [ List<GeneratedColumn> get $columns => [
id, id,
@ -214,8 +212,7 @@ class Category extends DataClass implements Insertable<Category> {
id: id ?? this.id, id: id ?? this.id,
description: description ?? this.description, description: description ?? this.description,
priority: priority ?? this.priority, priority: priority ?? this.priority,
descriptionInUpperCase: descriptionInUpperCase: descriptionInUpperCase ?? this.descriptionInUpperCase,
descriptionInUpperCase ?? this.descriptionInUpperCase,
); );
@override @override
String toString() { String toString() {
@ -229,8 +226,7 @@ class Category extends DataClass implements Insertable<Category> {
} }
@override @override
int get hashCode => int get hashCode => Object.hash(id, description, priority, descriptionInUpperCase);
Object.hash(id, description, priority, descriptionInUpperCase);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
@ -307,25 +303,23 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
} }
} }
class $TodosTableTable extends TodosTable class $TodosTableTable extends TodosTable with TableInfo<$TodosTableTable, TodoEntry> {
with TableInfo<$TodosTableTable, TodoEntry> {
@override @override
final GeneratedDatabase attachedDatabase; final GeneratedDatabase attachedDatabase;
final String? _alias; final String? _alias;
$TodosTableTable(this.attachedDatabase, [this._alias]); $TodosTableTable(this.attachedDatabase, [this._alias]);
@override @override
late final GeneratedColumnWithTypeConverter<RowId, int> id = late final GeneratedColumnWithTypeConverter<RowId, int> id = GeneratedColumn<int>(
GeneratedColumn<int>( 'id',
'id', aliasedName,
aliasedName, false,
false, hasAutoIncrement: true,
hasAutoIncrement: true, type: DriftSqlType.int,
type: DriftSqlType.int, requiredDuringInsert: false,
requiredDuringInsert: false, defaultConstraints: GeneratedColumn.constraintIsAlways(
defaultConstraints: GeneratedColumn.constraintIsAlways( 'PRIMARY KEY AUTOINCREMENT',
'PRIMARY KEY AUTOINCREMENT', ),
), ).withConverter<RowId>($TodosTableTable.$converterid);
).withConverter<RowId>($TodosTableTable.$converterid);
static const VerificationMeta _titleMeta = const VerificationMeta('title'); static const VerificationMeta _titleMeta = const VerificationMeta('title');
@override @override
late final GeneratedColumn<String> title = GeneratedColumn<String>( late final GeneratedColumn<String> title = GeneratedColumn<String>(
@ -532,9 +526,7 @@ class TodoEntry extends DataClass implements Insertable<TodoEntry> {
TodosTableCompanion toCompanion(bool nullToAbsent) { TodosTableCompanion toCompanion(bool nullToAbsent) {
return TodosTableCompanion( return TodosTableCompanion(
id: Value(id), id: Value(id),
title: title == null && nullToAbsent title: title == null && nullToAbsent ? const Value.absent() : Value(title),
? const Value.absent()
: Value(title),
content: Value(content), content: Value(content),
targetDate: targetDate == null && nullToAbsent targetDate: targetDate == null && nullToAbsent
? const Value.absent() ? const Value.absent()
@ -542,9 +534,7 @@ class TodoEntry extends DataClass implements Insertable<TodoEntry> {
category: category == null && nullToAbsent category: category == null && nullToAbsent
? const Value.absent() ? const Value.absent()
: Value(category), : Value(category),
status: status == null && nullToAbsent status: status == null && nullToAbsent ? const Value.absent() : Value(status),
? const Value.absent()
: Value(status),
); );
} }
@ -605,9 +595,7 @@ class TodoEntry extends DataClass implements Insertable<TodoEntry> {
id: data.id.present ? data.id.value : this.id, id: data.id.present ? data.id.value : this.id,
title: data.title.present ? data.title.value : this.title, title: data.title.present ? data.title.value : this.title,
content: data.content.present ? data.content.value : this.content, content: data.content.present ? data.content.value : this.content,
targetDate: data.targetDate.present targetDate: data.targetDate.present ? data.targetDate.value : this.targetDate,
? data.targetDate.value
: this.targetDate,
category: data.category.present ? data.category.value : this.category, category: data.category.present ? data.category.value : this.category,
status: data.status.present ? data.status.value : this.status, status: data.status.present ? data.status.value : this.status,
); );
@ -627,8 +615,7 @@ class TodoEntry extends DataClass implements Insertable<TodoEntry> {
} }
@override @override
int get hashCode => int get hashCode => Object.hash(id, title, content, targetDate, category, status);
Object.hash(id, title, content, targetDate, category, status);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
@ -794,8 +781,7 @@ final class $$CategoriesTableReferences
} }
} }
class $$CategoriesTableFilterComposer class $$CategoriesTableFilterComposer extends Composer<_$FirstDb, $CategoriesTable> {
extends Composer<_$FirstDb, $CategoriesTable> {
$$CategoriesTableFilterComposer({ $$CategoriesTableFilterComposer({
required super.$db, required super.$db,
required super.$table, required super.$table,
@ -803,11 +789,10 @@ class $$CategoriesTableFilterComposer
super.$addJoinBuilderToRootComposer, super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer, super.$removeJoinBuilderFromRootComposer,
}); });
ColumnWithTypeConverterFilters<RowId, RowId, int> get id => ColumnWithTypeConverterFilters<RowId, RowId, int> get id => $composableBuilder(
$composableBuilder( column: $table.id,
column: $table.id, builder: (column) => ColumnWithTypeConverterFilters(column),
builder: (column) => ColumnWithTypeConverterFilters(column), );
);
ColumnFilters<String> get description => $composableBuilder( ColumnFilters<String> get description => $composableBuilder(
column: $table.description, column: $table.description,
@ -843,16 +828,14 @@ class $$CategoriesTableFilterComposer
$table: $db.todosTable, $table: $db.todosTable,
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder, joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer,
$removeJoinBuilderFromRootComposer,
), ),
); );
return f(composer); return f(composer);
} }
} }
class $$CategoriesTableOrderingComposer class $$CategoriesTableOrderingComposer extends Composer<_$FirstDb, $CategoriesTable> {
extends Composer<_$FirstDb, $CategoriesTable> {
$$CategoriesTableOrderingComposer({ $$CategoriesTableOrderingComposer({
required super.$db, required super.$db,
required super.$table, required super.$table,
@ -924,8 +907,7 @@ class $$CategoriesTableAnnotationComposer
$table: $db.todosTable, $table: $db.todosTable,
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder, joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer,
$removeJoinBuilderFromRootComposer,
), ),
); );
return f(composer); return f(composer);
@ -994,11 +976,7 @@ class $$CategoriesTableTableManager
getPrefetchedDataCallback: (items) async { getPrefetchedDataCallback: (items) async {
return [ return [
if (todos) if (todos)
await $_getPrefetchedData< await $_getPrefetchedData<Category, $CategoriesTable, TodoEntry>(
Category,
$CategoriesTable,
TodoEntry
>(
currentTable: table, currentTable: table,
referencedTable: $$CategoriesTableReferences._todosTable( referencedTable: $$CategoriesTableReferences._todosTable(
db, db,
@ -1054,10 +1032,9 @@ final class $$TodosTableTableReferences
extends BaseReferences<_$FirstDb, $TodosTableTable, TodoEntry> { extends BaseReferences<_$FirstDb, $TodosTableTable, TodoEntry> {
$$TodosTableTableReferences(super.$_db, super.$_table, super.$_typedResult); $$TodosTableTableReferences(super.$_db, super.$_table, super.$_typedResult);
static $CategoriesTable _categoryTable(_$FirstDb db) => static $CategoriesTable _categoryTable(_$FirstDb db) => db.categories.createAlias(
db.categories.createAlias( $_aliasNameGenerator(db.todosTable.category, db.categories.id),
$_aliasNameGenerator(db.todosTable.category, db.categories.id), );
);
$$CategoriesTableProcessedTableManager? get category { $$CategoriesTableProcessedTableManager? get category {
final $_column = $_itemColumn<int>('category'); final $_column = $_itemColumn<int>('category');
@ -1074,8 +1051,7 @@ final class $$TodosTableTableReferences
} }
} }
class $$TodosTableTableFilterComposer class $$TodosTableTableFilterComposer extends Composer<_$FirstDb, $TodosTableTable> {
extends Composer<_$FirstDb, $TodosTableTable> {
$$TodosTableTableFilterComposer({ $$TodosTableTableFilterComposer({
required super.$db, required super.$db,
required super.$table, required super.$table,
@ -1083,11 +1059,10 @@ class $$TodosTableTableFilterComposer
super.$addJoinBuilderToRootComposer, super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer, super.$removeJoinBuilderFromRootComposer,
}); });
ColumnWithTypeConverterFilters<RowId, RowId, int> get id => ColumnWithTypeConverterFilters<RowId, RowId, int> get id => $composableBuilder(
$composableBuilder( column: $table.id,
column: $table.id, builder: (column) => ColumnWithTypeConverterFilters(column),
builder: (column) => ColumnWithTypeConverterFilters(column), );
);
ColumnFilters<String> get title => $composableBuilder( ColumnFilters<String> get title => $composableBuilder(
column: $table.title, column: $table.title,
@ -1126,16 +1101,14 @@ class $$TodosTableTableFilterComposer
$table: $db.categories, $table: $db.categories,
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder, joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer,
$removeJoinBuilderFromRootComposer,
), ),
); );
return composer; return composer;
} }
} }
class $$TodosTableTableOrderingComposer class $$TodosTableTableOrderingComposer extends Composer<_$FirstDb, $TodosTableTable> {
extends Composer<_$FirstDb, $TodosTableTable> {
$$TodosTableTableOrderingComposer({ $$TodosTableTableOrderingComposer({
required super.$db, required super.$db,
required super.$table, required super.$table,
@ -1184,8 +1157,7 @@ class $$TodosTableTableOrderingComposer
$table: $db.categories, $table: $db.categories,
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder, joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer,
$removeJoinBuilderFromRootComposer,
), ),
); );
return composer; return composer;
@ -1234,8 +1206,7 @@ class $$TodosTableTableAnnotationComposer
$table: $db.categories, $table: $db.categories,
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder, joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer: $removeJoinBuilderFromRootComposer,
$removeJoinBuilderFromRootComposer,
), ),
); );
return composer; return composer;
@ -1383,18 +1354,17 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
final String? _alias; final String? _alias;
$UsersTable(this.attachedDatabase, [this._alias]); $UsersTable(this.attachedDatabase, [this._alias]);
@override @override
late final GeneratedColumnWithTypeConverter<RowId, int> id = late final GeneratedColumnWithTypeConverter<RowId, int> id = GeneratedColumn<int>(
GeneratedColumn<int>( 'id',
'id', aliasedName,
aliasedName, false,
false, hasAutoIncrement: true,
hasAutoIncrement: true, type: DriftSqlType.int,
type: DriftSqlType.int, requiredDuringInsert: false,
requiredDuringInsert: false, defaultConstraints: GeneratedColumn.constraintIsAlways(
defaultConstraints: GeneratedColumn.constraintIsAlways( 'PRIMARY KEY AUTOINCREMENT',
'PRIMARY KEY AUTOINCREMENT', ),
), ).withConverter<RowId>($UsersTable.$converterid);
).withConverter<RowId>($UsersTable.$converterid);
static const VerificationMeta _nameMeta = const VerificationMeta('name'); static const VerificationMeta _nameMeta = const VerificationMeta('name');
@override @override
late final GeneratedColumn<String> name = GeneratedColumn<String>( late final GeneratedColumn<String> name = GeneratedColumn<String>(
@ -1429,14 +1399,13 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
'profilePicture', 'profilePicture',
); );
@override @override
late final GeneratedColumn<Uint8List> profilePicture = late final GeneratedColumn<Uint8List> profilePicture = GeneratedColumn<Uint8List>(
GeneratedColumn<Uint8List>( 'profile_picture',
'profile_picture', aliasedName,
aliasedName, false,
false, type: DriftSqlType.blob,
type: DriftSqlType.blob, requiredDuringInsert: true,
requiredDuringInsert: true, );
);
static const VerificationMeta _creationTimeMeta = const VerificationMeta( static const VerificationMeta _creationTimeMeta = const VerificationMeta(
'creationTime', 'creationTime',
); );
@ -1798,11 +1767,10 @@ class $$UsersTableFilterComposer extends Composer<_$SecondDb, $UsersTable> {
super.$addJoinBuilderToRootComposer, super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer, super.$removeJoinBuilderFromRootComposer,
}); });
ColumnWithTypeConverterFilters<RowId, RowId, int> get id => ColumnWithTypeConverterFilters<RowId, RowId, int> get id => $composableBuilder(
$composableBuilder( column: $table.id,
column: $table.id, builder: (column) => ColumnWithTypeConverterFilters(column),
builder: (column) => ColumnWithTypeConverterFilters(column), );
);
ColumnFilters<String> get name => $composableBuilder( ColumnFilters<String> get name => $composableBuilder(
column: $table.name, column: $table.name,
@ -1967,6 +1935,5 @@ typedef $$UsersTableProcessedTableManager =
class $SecondDbManager { class $SecondDbManager {
final _$SecondDb _db; final _$SecondDb _db;
$SecondDbManager(this._db); $SecondDbManager(this._db);
$$UsersTableTableManager get users => $$UsersTableTableManager get users => $$UsersTableTableManager(_db, _db.users);
$$UsersTableTableManager(_db, _db.users);
} }

View file

@ -0,0 +1,16 @@
# Files and directories created by pub
.dart_tool/
.packages
# Omit committing pubspec.lock for library packages:
# https://dart.dev/guides/libraries/private-files#pubspeclock
pubspec.lock
# Conventional directory for build outputs
build/
# Directory created by dartdoc
doc/api/
# Migrations do not need to be committed, as they are only for testing
lib/migrations/

View file

@ -0,0 +1,3 @@
# serverpod_offline_sync_client
Client package for the Serverpod Offline Sync project.

View file

@ -0,0 +1,8 @@
include: ../../analysis_options.yaml
analyzer:
exclude:
- lib/src/protocol/**
formatter:
trailing_commas: preserve

View file

@ -0,0 +1,5 @@
dartdoc:
categories:
"Endpoint":
markdown: doc/endpoint.md
name: Endpoint

View file

@ -0,0 +1,23 @@
# Callable endpoints
Each class contains callable methods that will call a method on the server side. The classes are accessible via the Serverpod client you have created in your Flutter app. The name of the module is defined in your `config/generator.yaml` file in the server project.
```yaml
modules:
<module_name>:
nickname: <nickname>
```
The name "EndpointClass" where Class is your class name will have the "Endpoint" part stripped when the client is code generated. When accessing you can simply use the endpoint name in lowercase.
Example usage:
```dart
// Authenticate with email.
client.modules.auth.email.authenticate(email, password)
// Generic format.
client.modules.<nickname>.<endpoint>.<method>(...)
```
Please see the full official documentation [here](https://docs.serverpod.dev)

Some files were not shown because too many files have changed in this diff Show more