fix: Add proper suppor to the noReturn parameter on the ORM (#92)

This commit is contained in:
Marcelo Mendonça Soares 2026-07-03 14:03:44 -03:00 • committed by GitHub
commit 65832eda0a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 308 additions and 9 deletions

View file

@ -56,6 +56,62 @@ void main() {
expect(deletedPerson.scopeId, isNull);
});
});
group('when deleting the Person with delete and noReturn,', () {
late List<Person> deleted;
setUp(() async {
deleted = await session.db.transactionForUser(
testCrdtUserId,
(tx) => Person.db.delete(
session,
[person],
transaction: tx,
noReturn: true,
),
);
});
test('then an empty list is returned.', () async {
expect(deleted, isEmpty);
});
test('then a CRDT tombstone is created for the row.', () async {
final tombstone = await CrdtDataDeleted.db.findFirstRow(
session,
where: (t) => t.row.uuidRowId.equals(person.id),
);
expect(tombstone?.isDeleted, isTrue);
});
});
group('when deleting the Person with deleteWhere and noReturn,', () {
late List<Person> deleted;
setUp(() async {
deleted = await session.db.transactionForUser(
testCrdtUserId,
(tx) => Person.db.deleteWhere(
session,
where: (t) => t.id.equals(person.id),
transaction: tx,
noReturn: true,
),
);
});
test('then an empty list is returned.', () async {
expect(deleted, isEmpty);
});
test('then a CRDT tombstone is created for the row.', () async {
final tombstone = await CrdtDataDeleted.db.findFirstRow(
session,
where: (t) => t.row.uuidRowId.equals(person.id),
);
expect(tombstone?.isDeleted, isTrue);
});
});
});
group('Given a person table with a deleted row,', () {

View file

@ -172,6 +172,79 @@ void main() {
expect(crdt.map((e) => e.uuidRowId).toSet(), insertedIds);
});
});
group('when inserting a Person with a caller-provided id and noReturn,', () {
late UuidValue id;
late List<Person> inserted;
setUp(() async {
id = const Uuid().v7obj();
inserted = await session.db.transactionForUser(
testCrdtUserId,
(tx) => Person.db.insert(
session,
[Person(id: id, name: 'fixed')],
transaction: tx,
noReturn: true,
),
);
});
test('then an empty list is returned.', () async {
expect(inserted, isEmpty);
});
test('then the row exists in the person table.', () async {
final row = await Person.db.findById(session, id);
expect(row?.name, 'fixed');
});
test('then CRDT metadata is recorded for the row.', () async {
final crdtRow = await CrdtDataRow.db.findFirstRow(
session,
where: (t) => t.uuidRowId.equals(id),
);
expect(crdtRow, isNotNull);
});
});
group('when inserting a Person without a caller-provided id and noReturn,', () {
late List<Person> inserted;
late Person? row;
setUp(() async {
inserted = await session.db.transactionForUser(
testCrdtUserId,
(tx) => Person.db.insert(
session,
[Person(name: 'generated')],
transaction: tx,
noReturn: true,
),
);
row = await Person.db.findFirstRow(
session,
where: (t) => t.name.equals('generated'),
);
});
test('then an empty list is returned.', () async {
expect(inserted, isEmpty);
});
test('then the row exists in the person table.', () async {
expect(row, isNotNull);
});
test('then CRDT metadata is recorded for the row.', () async {
final crdtRow = await CrdtDataRow.db.findFirstRow(
session,
where: (t) => t.uuidRowId.equals(row!.id),
);
expect(crdtRow, isNotNull);
});
});
});
group('Given a person row with a fixed id,', () {

View file

@ -194,6 +194,67 @@ void main() {
);
},
);
group('when updating the Person with update and noReturn,', () {
late List<Person> updated;
setUp(() async {
updated = await session.db.transactionForUser(
testCrdtUserId,
(tx) => Person.db.update(
session,
[person.copyWith(name: 'updated')],
columns: (t) => [t.name],
transaction: tx,
noReturn: true,
),
);
});
test('then an empty list is returned.', () async {
expect(updated, isEmpty);
});
test('then the person row reflects the new values.', () async {
final row = await Person.db.findById(session, person.id!);
expect(row?.name, 'updated');
});
test('then a CRDT field is created for the name column.', () async {
final field = await CrdtDataField.db.findFirstRow(
session,
where: (t) => t.row.uuidRowId.equals(person.id),
include: CrdtDataField.include(column: CrdtSchemaColumn.include()),
);
expect(field?.column?.name, 'name');
});
});
group('when updating the Person with updateWhere and noReturn,', () {
late List<Person> updated;
setUp(() async {
updated = await session.db.transactionForUser(
testCrdtUserId,
(tx) => Person.db.updateWhere(
session,
columnValues: (t) => [t.name('updated')],
where: (t) => t.id.equals(person.id),
transaction: tx,
noReturn: true,
),
);
});
test('then an empty list is returned.', () async {
expect(updated, isEmpty);
});
test('then the person row reflects the new values.', () async {
final row = await Person.db.findById(session, person.id!);
expect(row?.name, 'updated');
});
});
});
group('Given a person table with a deleted row,', () {
@ -513,4 +574,73 @@ void main() {
});
});
});
group('Given a row on a table not tracked by CRDT,', () {
late CrdtSyncIntegrityViolation violation;
setUp(() async {
violation = await CrdtSyncIntegrityViolation.db.insertRow(
session,
CrdtSyncIntegrityViolation(
type: CrdtSyncViolationType.ownershipCollision,
domainTableName: Person.t.tableName,
uuidRowId: const Uuid().v7obj(),
incomingScopeUuid: testCrdtUserId,
operation: CrdtSyncViolationOperation.mergeInsert,
firstSeenAt: DateTime.now(),
lastSeenAt: DateTime.now(),
occurrences: 1,
),
);
});
group('when updating the row with update and noReturn,', () {
late List<CrdtSyncIntegrityViolation> updated;
setUp(() async {
updated = await CrdtSyncIntegrityViolation.db.update(
session,
[violation.copyWith(occurrences: 2)],
noReturn: true,
);
});
test('then an empty list is returned.', () async {
expect(updated, isEmpty);
});
test('then the row reflects the new values.', () async {
final row = await CrdtSyncIntegrityViolation.db.findById(
session,
violation.id!,
);
expect(row?.occurrences, 2);
});
});
group('when updating the row with updateWhere and noReturn,', () {
late List<CrdtSyncIntegrityViolation> updated;
setUp(() async {
updated = await CrdtSyncIntegrityViolation.db.updateWhere(
session,
columnValues: (t) => [t.occurrences(3)],
where: (t) => t.id.equals(violation.id),
noReturn: true,
);
});
test('then an empty list is returned.', () async {
expect(updated, isEmpty);
});
test('then the row reflects the new values.', () async {
final row = await CrdtSyncIntegrityViolation.db.findById(
session,
violation.id!,
);
expect(row?.occurrences, 3);
});
});
});
}