valuesTests method
void
valuesTests()
Implementation
void valuesTests() {
group('Values', () {
late Cursor cursor;
setUp(() async {
connection = await connector.connect(_initDb);
cursor = await connection.cursor();
});
tearDown(() async {
await connection.close();
});
group('query on different types', () {
group('equality', () {
test('basic values', () async {
await insertRow(
connection,
"1",
name: "Christopher Schwartz",
age: 56,
height: 1.81,
isStaff: true,
createdAt: DateTime.utc(2025, 4, 2, 13, 23),
);
final testCases = [
(property: "name", value: StringValue("Christopher Schwartz")),
(property: "age", value: NumericValue(56)),
(property: "height", value: NumericValue(1.81)),
(property: "isStaff", value: BooleanValue(true)),
(
property: "createdAt",
value: DateTimeValue(DateTime.utc(2025, 4, 2, 13, 23))
),
(property: "profilePicture", value: NullValue()),
];
for (final testcase in testCases) {
await cursor.execute(
Query(
from: schema,
where: SingleFilter(
left: Property(testcase.property),
operator: Operator.equals,
right: testcase.value,
),
),
);
final res = await cursor.fetchall();
expect(res, hasLength(1),
reason: "Failed equality comparison on $testcase");
}
});
});
group('inequality', () {
test('basic values', () async {
await insertRow(
connection,
"1",
name: "Christopher Schwartz",
age: 56,
height: 1.81,
isStaff: true,
createdAt: DateTime.utc(2025, 4, 2, 13, 23),
);
final testCases = [
(property: "name", value: StringValue("Christopher Schwartz")),
(property: "age", value: NumericValue(56)),
(property: "height", value: NumericValue(1.81)),
(property: "isStaff", value: BooleanValue(true)),
(
property: "createdAt",
value: DateTimeValue(DateTime.utc(2025, 4, 2, 13, 23))
),
(property: "profilePicture", value: NullValue()),
];
for (final testcase in testCases) {
await cursor.execute(
Query(
from: schema,
where: SingleFilter(
left: Property(testcase.property),
operator: Operator.notEquals,
right: testcase.value,
),
),
);
final res = await cursor.fetchall();
expect(res, isEmpty,
reason: "Failed equality comparison on $testcase");
}
});
});
group('greater than', () {
test('basic values', () async {
await insertRow(
connection,
"1",
name: "Christopher Schwartz",
age: 56,
height: 1.81,
isStaff: true,
createdAt: DateTime.utc(2025, 4, 2, 13, 23),
);
final testCases = [
(property: "name", value: StringValue("Bhristopher Schwartz")),
(property: "age", value: NumericValue(-1)),
(property: "height", value: NumericValue(1.80)),
(
property: "createdAt",
value: DateTimeValue(DateTime.utc(2025, 4, 2, 13, 22)),
),
];
for (final testcase in testCases) {
await cursor.execute(
Query(
from: schema,
where: SingleFilter(
left: Property(testcase.property),
operator: Operator.greaterThan,
right: testcase.value,
),
),
);
final res = await cursor.fetchall();
expect(res, hasLength(1),
reason: "Failed equality comparison on $testcase");
}
});
});
group('list operations', () {
test('in list', () async {
await insertRow(
connection,
"1",
name: "Christopher Schwartz",
age: 56,
height: 1.81,
isStaff: true,
createdAt: DateTime.utc(2025, 4, 2, 13, 23),
);
final testCases = [
(
property: "name",
value: ListValue(
[
StringValue("Bhristopher Schwartz"),
StringValue("Christopher Schwartz")
],
)
),
(
property: "age",
value: ListValue(
[
NumericValue(56),
NumericValue(-1),
NumericValue(86),
],
),
),
(
property: "height",
value: ListValue([
NumericValue(1),
NumericValue(1.01),
NumericValue(1.81),
]),
),
];
for (final testcase in testCases) {
await cursor.execute(
Query(
from: schema,
where: SingleFilter(
left: Property(testcase.property),
operator: Operator.isIn,
right: testcase.value,
),
),
);
var res = await cursor.fetchall();
expect(res, hasLength(1),
reason: "Failed 'in' comparison on $testcase");
}
});
test('not in list', () async {
await insertRow(
connection,
"1",
name: "Christopher Schwartz",
age: 56,
height: 1.81,
isStaff: true,
createdAt: DateTime.utc(2025, 4, 2, 13, 23),
);
final testCases = [
(
property: "name",
value: ListValue(
[
StringValue("Bhristopher Schwartz"),
StringValue("Christopher Schwartz")
],
)
),
(
property: "age",
value: ListValue(
[
NumericValue(56),
NumericValue(-1),
NumericValue(86),
],
),
),
(
property: "height",
value: ListValue([
NumericValue(1),
NumericValue(1.01),
NumericValue(1.81),
]),
),
];
for (final testcase in testCases) {
await cursor.execute(
Query(
from: schema,
where: SingleFilter(
left: Property(testcase.property),
operator: Operator.isNotIn,
right: testcase.value,
),
),
);
var res = await cursor.fetchall();
expect(res, isEmpty,
reason: "Failed 'in' comparison on $testcase");
}
});
});
// What is the correct semantics of this?
// In indexeddb, checking <= boolean is ok, and actually
// needed as we transform a != true to a < true || a > true, which
// then becomes a < 1 || a > 1 - which is completely legit.
test('illegal operations', () async {
await insertRow(
connection,
"1",
name: "Christopher Schwartz",
age: 56,
height: 1.81,
isStaff: true,
createdAt: DateTime.utc(2025, 4, 2, 13, 23),
);
final testCases = [
(
property: "isStaff",
value: BooleanValue(false),
operator: Operator.greaterThan
),
(
property: "isStaff",
value: BooleanValue(false),
operator: Operator.greaterThanOrEqual
),
(
property: "isStaff",
value: BooleanValue(false),
operator: Operator.lessThan
),
(
property: "isStaff",
value: BooleanValue(false),
operator: Operator.lessThanOrEqual
),
(
property: "isStaff",
value: BooleanValue(false),
operator: Operator.isIn
),
(
property: "isStaff",
value: BooleanValue(false),
operator: Operator.isNotIn
),
(
property: "profilePicture",
value: NullValue(),
operator: Operator.greaterThan
),
(
property: "profilePicture",
value: NullValue(),
operator: Operator.greaterThanOrEqual
),
(
property: "profilePicture",
value: NullValue(),
operator: Operator.lessThan
),
(
property: "profilePicture",
value: NullValue(),
operator: Operator.lessThanOrEqual
),
(
property: "profilePicture",
value: NullValue(),
operator: Operator.isIn
),
(
property: "profilePicture",
value: NullValue(),
operator: Operator.isNotIn
),
];
for (final testcase in testCases) {
expect(
() => cursor.execute(
Query(
from: schema,
where: SingleFilter(
left: Property(testcase.property),
operator: testcase.operator,
right: testcase.value,
),
),
),
throwsA(
isA<ProgrammingError>(),
),
reason: "Operation did not fail: $testcase");
}
}, skip: "Skipped as the semantics here are unclear");
});
group('basic types', () {
test('null values', () async {
await insertRow(connection, "1");
await cursor.execute(Query(from: schema));
final res = await cursor.fetchall();
expect(res[0], {
"id": "1",
"name": null,
"age": null,
"height": null,
"isStaff": null,
"createdAt": null,
"profilePicture": null,
});
});
test('non-null values', () async {
final picture = ByteData(100);
final bytesList = List.generate(100, (i) => i % 10);
picture.buffer.asUint8List().setAll(0, bytesList);
await insertRow(
connection,
"1",
name: "Christopher Schwartz",
age: 56,
height: 1.81,
isStaff: true,
createdAt: DateTime.utc(2025, 4, 2, 13, 23),
profilePicture: picture,
);
await cursor.execute(Query(from: schema));
final res = await cursor.fetchall();
expect((res[0]["profilePicture"] as ByteData).buffer.asUint8List(),
bytesList);
res[0].remove("profilePicture");
expect(res[0], {
"id": "1",
"name": "Christopher Schwartz",
"age": 56,
"height": 1.81,
"isStaff": true,
"createdAt": DateTime.utc(2025, 4, 2, 13, 23),
});
});
test('insert fails if value of the wrong type', () async {
expect(
() => cursor.execute(Insert(schema, [
{
"id": 1,
"name": 23,
"age": null,
"height": null,
"isStaff": null,
"createdAt": null,
"profilePicture": null,
}
])),
throwsA(isA<DataError>()));
});
test('Query returns null if value cannot be converted', () async {
await insertRow(
connection,
"1",
name: "Tomas Chippendale",
);
final wrongSchema = schema.copyWith(
properties: [
PropertySchema(
"id",
type: PropertyType.text,
primaryKey: true,
nullable: false,
),
// pretend "name" is a DateTime
PropertySchema("name", type: PropertyType.datetime),
PropertySchema("age", type: PropertyType.integer),
PropertySchema("height", type: PropertyType.double),
PropertySchema("isStaff", type: PropertyType.boolean),
PropertySchema("createdAt", type: PropertyType.datetime),
PropertySchema("profilePicture", type: PropertyType.blob),
],
);
await cursor.execute(Query(from: wrongSchema));
final res = await cursor.fetchone();
expect(res!['name'], isNull);
});
test('Query returns unconverted value if not in schema', () async {
await insertRow(
connection,
"1",
name: "Tomas Chippendale",
createdAt: DateTime(1982, 9, 1),
);
final wrongSchema = schema.copyWith(
properties: [
PropertySchema(
"id",
type: PropertyType.text,
primaryKey: true,
nullable: false,
),
PropertySchema("name", type: PropertyType.text),
PropertySchema("age", type: PropertyType.integer),
PropertySchema("height", type: PropertyType.double),
PropertySchema("isStaff", type: PropertyType.boolean),
// "createdAt" has been removed from schema after insert
// PropertySchema("createdAt", type: PropertyType.datetime),
PropertySchema("profilePicture", type: PropertyType.blob),
],
);
await cursor.execute(Query(from: wrongSchema));
final res = await cursor.fetchone();
expect(res!['createdAt'], isNotNull);
expect(res['createdAt'], isA<String>());
});
test('DateTimes are converted to UTC', () async {
await insertRow(
connection,
"1",
createdAt: DateTime.parse("2025-04-02T14:23:00+0100"),
);
await cursor.execute(Query(from: schema));
final res = await cursor.fetchall();
expect(res[0], {
"id": "1",
"name": null,
"age": null,
"height": null,
"isStaff": null,
"createdAt": DateTime.utc(2025, 4, 2, 13, 23),
"profilePicture": null,
});
});
});
});
}