mirror of https://github.com/AMT-Cheif/drift.git
Improve testing structure for sally
This commit is contained in:
parent
b2736421d8
commit
b7e37857ec
|
@ -467,13 +467,6 @@
|
|||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="sqlite2">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/sqlite2-0.5.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stack_trace">
|
||||
<value>
|
||||
<list>
|
||||
|
@ -671,7 +664,6 @@
|
|||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-1.1.5/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.8/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.4/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/sqlite2-0.5.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-1.6.8/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_transform-0.0.14+1/lib" />
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/end_to_end_testing/end_to_end_testing.iml" filepath="$PROJECT_DIR$/end_to_end_testing/end_to_end_testing.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/sally/sally.iml" filepath="$PROJECT_DIR$/sally/sally.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/sally_flutter/sally_flutter.iml" filepath="$PROJECT_DIR$/sally_flutter/sally_flutter.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/sally_generator/sally_generator.iml" filepath="$PROJECT_DIR$/sally_generator/sally_generator.iml" />
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
sqflite=/home/simon/Android/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.1.0/
|
|
@ -11,14 +11,16 @@ import 'package:sally/src/runtime/statements/update.dart';
|
|||
abstract class GeneratedDatabase {
|
||||
final SqlTypeSystem typeSystem;
|
||||
final QueryExecutor executor;
|
||||
final StreamQueryStore streamQueries = StreamQueryStore();
|
||||
@visibleForTesting
|
||||
StreamQueryStore streamQueries;
|
||||
|
||||
int get schemaVersion;
|
||||
MigrationStrategy get migration;
|
||||
|
||||
List<TableInfo> get allTables;
|
||||
|
||||
GeneratedDatabase(this.typeSystem, this.executor);
|
||||
GeneratedDatabase(this.typeSystem, this.executor,
|
||||
{this.streamQueries = const StreamQueryStore()});
|
||||
|
||||
/// Creates a migrator with the provided query executor. We sometimes can't
|
||||
/// use the regular [GeneratedDatabase.executor] because migration happens
|
||||
|
@ -29,6 +31,9 @@ abstract class GeneratedDatabase {
|
|||
streamQueries.handleTableUpdates(tableName);
|
||||
}
|
||||
|
||||
Stream<List<T>> createStream<T>(SelectStatement<dynamic, T> stmt) =>
|
||||
streamQueries.registerStream(stmt);
|
||||
|
||||
Future<void> handleDatabaseCreation({@required SqlExecutor executor}) {
|
||||
final migrator = _createMigrator(executor);
|
||||
return migration.onCreate(migrator);
|
||||
|
|
|
@ -3,7 +3,9 @@ import 'dart:async';
|
|||
import 'package:sally/sally.dart';
|
||||
|
||||
class StreamQueryStore {
|
||||
final List<_QueryStream> _activeStreams = [];
|
||||
final List<_QueryStream> _activeStreams = const [];
|
||||
|
||||
const StreamQueryStore();
|
||||
|
||||
Stream<List<T>> registerStream<T>(SelectStatement<dynamic, T> statement) {
|
||||
final stream = _QueryStream(statement, this);
|
||||
|
|
|
@ -24,6 +24,6 @@ class SelectStatement<T, D> extends Query<T, D> {
|
|||
/// Creates an auto-updating stream that emits new items whenever this table
|
||||
/// changes.
|
||||
Stream<List<D>> watch() {
|
||||
return database.streamQueries.registerStream(this);
|
||||
return database.createStream(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,5 @@
|
|||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
<orderEntry type="library" name="Flutter Plugins" level="project" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,54 @@
|
|||
import 'package:sally/sally.dart';
|
||||
import 'package:test_api/test_api.dart';
|
||||
|
||||
import 'tables/todos.dart';
|
||||
import 'utils/mocks.dart';
|
||||
|
||||
void main() {
|
||||
TodoDb db;
|
||||
MockExecutor executor;
|
||||
MockStreamQueries streamQueries;
|
||||
|
||||
setUp(() {
|
||||
executor = MockExecutor();
|
||||
streamQueries = MockStreamQueries();
|
||||
db = TodoDb(executor)..streamQueries = streamQueries;
|
||||
});
|
||||
|
||||
group('Generates DELETE statements', () {
|
||||
test('without any constraints', () async {
|
||||
await db.delete(db.users).go();
|
||||
|
||||
verify(executor.runDelete('DELETE FROM users;', argThat(isEmpty)));
|
||||
});
|
||||
|
||||
test('for complex components', () async {
|
||||
await (db.delete(db.users)
|
||||
..where((u) => or(not(u.isAwesome), u.id.isSmallerThan(100)))
|
||||
..limit(10, offset: 100))
|
||||
.go();
|
||||
|
||||
verify(executor.runDelete(
|
||||
'DELETE FROM users WHERE (NOT (is_awesome = 1)) OR (id < ?) LIMIT 10, 100;',
|
||||
[100]));
|
||||
});
|
||||
});
|
||||
|
||||
group('Table updates for delete statements', () {
|
||||
test('are issued when data was changed', () async {
|
||||
when(executor.runDelete(any, any)).thenAnswer((_) => Future.value(3));
|
||||
|
||||
await db.delete(db.users).go();
|
||||
|
||||
verify(streamQueries.handleTableUpdates('users'));
|
||||
});
|
||||
|
||||
test('are not issues when no data was changed', () async {
|
||||
when(executor.runDelete(any, any)).thenAnswer((_) => Future.value(0));
|
||||
|
||||
await db.delete(db.users).go();
|
||||
|
||||
verifyNever(streamQueries.handleTableUpdates(any));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
import 'package:sally/sally.dart';
|
||||
import 'package:sally/src/runtime/migration.dart';
|
||||
|
||||
class Users extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get name => text().withLength(min: 6, max: 32)();
|
||||
BoolColumn get isAwesome => boolean()();
|
||||
}
|
||||
|
||||
// Example tables and data classes, these would be generated by sally_generator
|
||||
// in a real project
|
||||
class UserDataObject {
|
||||
final int id;
|
||||
final String name;
|
||||
UserDataObject(this.id, this.name);
|
||||
}
|
||||
|
||||
class GeneratedUsersTable extends Users with TableInfo<Users, UserDataObject> {
|
||||
final GeneratedDatabase db;
|
||||
|
||||
GeneratedUsersTable(this.db);
|
||||
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => Set()..add(id);
|
||||
@override
|
||||
GeneratedIntColumn id = GeneratedIntColumn('id', false);
|
||||
@override
|
||||
GeneratedTextColumn name = GeneratedTextColumn('name', false);
|
||||
@override
|
||||
GeneratedBoolColumn isAwesome = GeneratedBoolColumn('is_awesome', true);
|
||||
@override
|
||||
List<GeneratedColumn<dynamic, SqlType>> get $columns => [id, name, isAwesome];
|
||||
@override
|
||||
String get $tableName => 'users';
|
||||
@override
|
||||
Users get asDslTable => this;
|
||||
@override
|
||||
UserDataObject map(Map<String, dynamic> data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(UserDataObject d) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.name != null) {
|
||||
map['name'] = Variable<String, StringType>(d.name);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
class TestDatabase extends GeneratedDatabase {
|
||||
TestDatabase(QueryExecutor executor)
|
||||
: super(const SqlTypeSystem.withDefaults(), executor);
|
||||
|
||||
GeneratedUsersTable get users => GeneratedUsersTable(this);
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration => MigrationStrategy();
|
||||
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
|
||||
@override
|
||||
List<TableInfo> get allTables => [users];
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
import 'package:mockito/mockito.dart';
|
||||
import 'package:sally/sally.dart';
|
||||
import 'package:test_api/test_api.dart';
|
||||
|
||||
import 'generated_tables.dart';
|
||||
|
||||
// used so that we can mock the SqlExecutor typedef
|
||||
abstract class SqlExecutorAsClass {
|
||||
Future<void> call(String sql);
|
||||
}
|
||||
|
||||
class MockQueryExecutor extends Mock implements SqlExecutorAsClass {}
|
||||
|
||||
void main() {
|
||||
Migrator migrator;
|
||||
TestDatabase db;
|
||||
MockQueryExecutor executor;
|
||||
|
||||
setUp(() {
|
||||
executor = MockQueryExecutor();
|
||||
db = TestDatabase(null);
|
||||
migrator = Migrator(db, executor);
|
||||
});
|
||||
|
||||
test('generates CREATE TABLE statements', () {
|
||||
migrator.createAllTables();
|
||||
|
||||
verify(executor.call(
|
||||
'CREATE TABLE IF NOT EXISTS users (id INTEGER NOT NULL , name VARCHAR NOT NULL , is_awesome BOOLEAN NULL CHECK (is_awesome in (0, 1)))'));
|
||||
});
|
||||
|
||||
test('generates DROP TABLE statements', () {
|
||||
migrator.deleteTable('users');
|
||||
|
||||
verify(executor.call('DROP TABLE IF EXISTS users'));
|
||||
});
|
||||
|
||||
test('generates ALTER TABLE statements to add columns', () {
|
||||
migrator.addColumn(db.users, db.users.isAwesome);
|
||||
|
||||
verify(executor.call(
|
||||
'ALTER TABLE users ADD COLUMN is_awesome BOOLEAN NULL CHECK (is_awesome in (0, 1))'));
|
||||
});
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
import 'package:sally/sally.dart';
|
||||
import 'package:test_api/test_api.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'generated_tables.dart';
|
||||
|
||||
class MockExecutor extends Mock implements QueryExecutor {}
|
||||
|
||||
void main() {
|
||||
TestDatabase db;
|
||||
MockExecutor executor;
|
||||
|
||||
setUp(() {
|
||||
executor = MockExecutor();
|
||||
db = TestDatabase(executor);
|
||||
|
||||
when(executor.runSelect(any, any)).thenAnswer((_) => Future.value([]));
|
||||
when(executor.runUpdate(any, any)).thenAnswer((_) => Future.value(0));
|
||||
when(executor.runDelete(any, any)).thenAnswer((_) => Future.value(0));
|
||||
when(executor.runInsert(any, any)).thenAnswer((_) => Future.value(0));
|
||||
});
|
||||
|
||||
group('Generates SELECT statements', () {
|
||||
test('generates simple statements', () {
|
||||
db.select(db.users).get();
|
||||
verify(executor.runSelect('SELECT * FROM users;', argThat(isEmpty)));
|
||||
});
|
||||
|
||||
test('generates limit statements', () {
|
||||
(db.select(db.users)..limit(10)).get();
|
||||
verify(executor.runSelect(
|
||||
'SELECT * FROM users LIMIT 10;', argThat(isEmpty)));
|
||||
});
|
||||
|
||||
test('generates like expressions', () {
|
||||
(db.select(db.users)..where((u) => u.name.like('Dash%'))).get();
|
||||
verify(executor
|
||||
.runSelect('SELECT * FROM users WHERE name LIKE ?;', ['Dash%']));
|
||||
});
|
||||
|
||||
test('generates complex predicates', () {
|
||||
(db.select(db.users)
|
||||
..where((u) =>
|
||||
and(not(u.name.equals('Dash')), (u.id.isBiggerThan(12)))))
|
||||
.get();
|
||||
|
||||
verify(executor.runSelect(
|
||||
'SELECT * FROM users WHERE (NOT name = ?) AND (id > ?);',
|
||||
['Dash', 12]));
|
||||
});
|
||||
|
||||
test('generates expressions from boolean columns', () {
|
||||
(db.select(db.users)..where((u) => u.isAwesome)).get();
|
||||
|
||||
verify(executor.runSelect(
|
||||
'SELECT * FROM users WHERE (is_awesome = 1);', argThat(isEmpty)));
|
||||
});
|
||||
});
|
||||
|
||||
group('Streams for queries', () {
|
||||
test('update correctly', () {
|
||||
final stream = db.select(db.users).watch();
|
||||
stream.listen((_) => null);
|
||||
|
||||
db.markTableUpdated('users');
|
||||
|
||||
verify(executor.runSelect('SELECT * FROM users;', argThat(isEmpty))).called(2);
|
||||
});
|
||||
});
|
||||
|
||||
group('Generates DELETE statements', () {
|
||||
test('without any constraints', () {
|
||||
db.delete(db.users).go();
|
||||
|
||||
verify(executor.runDelete('DELETE FROM users;', argThat(isEmpty)));
|
||||
});
|
||||
|
||||
test('for complex components', () {
|
||||
(db.delete(db.users)
|
||||
..where((u) => or(not(u.isAwesome), u.id.isSmallerThan(100)))
|
||||
..limit(10, offset: 100))
|
||||
.go();
|
||||
|
||||
verify(executor.runDelete(
|
||||
'DELETE FROM users WHERE (NOT (is_awesome = 1)) OR (id < ?) LIMIT 10, 100;',
|
||||
[100]));
|
||||
});
|
||||
});
|
||||
|
||||
group('Generates INSERT statements', () {
|
||||
test('with full data', () {
|
||||
db.into(db.users).insert(UserDataObject(10, 'User'));
|
||||
|
||||
verify(executor.runInsert(
|
||||
'INSERT INTO users (id, name) VALUES (?, ?)', [10, 'User']));
|
||||
});
|
||||
|
||||
// todo verify auto-increment and default values
|
||||
});
|
||||
|
||||
group('Generates UPDATE statements', () {
|
||||
test('without constraints', () {
|
||||
db.update(db.users).write(UserDataObject(3, 'User'));
|
||||
|
||||
verify(
|
||||
executor.runUpdate('UPDATE users SET id = ? name = ?;', [3, 'User']));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
import 'package:sally/sally.dart';
|
||||
import 'package:test_api/test_api.dart';
|
||||
|
||||
import 'tables/todos.dart';
|
||||
import 'utils/mocks.dart';
|
||||
|
||||
void main() {
|
||||
TodoDb db;
|
||||
MockExecutor executor;
|
||||
|
||||
setUp(() {
|
||||
executor = MockExecutor();
|
||||
db = TodoDb(executor);
|
||||
});
|
||||
|
||||
group('SELECT statements are generated', () {
|
||||
test('for simple statements', () {
|
||||
db.select(db.users).get();
|
||||
verify(executor.runSelect('SELECT * FROM users;', argThat(isEmpty)));
|
||||
});
|
||||
|
||||
test('with limit statements', () {
|
||||
(db.select(db.users)..limit(10)).get();
|
||||
verify(executor.runSelect(
|
||||
'SELECT * FROM users LIMIT 10;', argThat(isEmpty)));
|
||||
});
|
||||
|
||||
test('with like expressions', () {
|
||||
(db.select(db.users)..where((u) => u.name.like('Dash%'))).get();
|
||||
verify(executor
|
||||
.runSelect('SELECT * FROM users WHERE name LIKE ?;', ['Dash%']));
|
||||
});
|
||||
|
||||
test('with complex predicates', () {
|
||||
(db.select(db.users)
|
||||
..where((u) =>
|
||||
and(not(u.name.equals('Dash')), (u.id.isBiggerThan(12)))))
|
||||
.get();
|
||||
|
||||
verify(executor.runSelect(
|
||||
'SELECT * FROM users WHERE (NOT name = ?) AND (id > ?);',
|
||||
['Dash', 12]));
|
||||
});
|
||||
|
||||
test('with expressions from boolean columns', () {
|
||||
(db.select(db.users)..where((u) => u.isAwesome)).get();
|
||||
|
||||
verify(executor.runSelect(
|
||||
'SELECT * FROM users WHERE (is_awesome = 1);', argThat(isEmpty)));
|
||||
});
|
||||
});
|
||||
|
||||
group('SELECT results are parsed', () {
|
||||
test('when all fields are non-null', () {
|
||||
final data = [
|
||||
{
|
||||
'id': 10,
|
||||
'title': 'A todo title',
|
||||
'content': 'Content',
|
||||
'category': 3
|
||||
}
|
||||
];
|
||||
final resolved = TodoEntry(
|
||||
id: 10,
|
||||
title: 'A todo title',
|
||||
content: 'Content',
|
||||
category: 3,
|
||||
);
|
||||
|
||||
when(executor.runSelect('SELECT * FROM todos;', any))
|
||||
.thenAnswer((_) => Future.value(data));
|
||||
|
||||
expect(db.select(db.todosTable).get(), completion([resolved]));
|
||||
});
|
||||
|
||||
test('when some fields are null', () {
|
||||
final data = [
|
||||
{
|
||||
'id': 10,
|
||||
'title': null,
|
||||
'content': 'Content',
|
||||
'category': null,
|
||||
}
|
||||
];
|
||||
final resolved = TodoEntry(
|
||||
id: 10,
|
||||
title: null,
|
||||
content: 'Content',
|
||||
category: null,
|
||||
);
|
||||
|
||||
when(executor.runSelect('SELECT * FROM todos;', any))
|
||||
.thenAnswer((_) => Future.value(data));
|
||||
|
||||
expect(db.select(db.todosTable).get(), completion([resolved]));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,10 +1,43 @@
|
|||
import 'package:sally/sally.dart';
|
||||
|
||||
part 'todos.g.dart';
|
||||
|
||||
@DataClassName('TodoEntry')
|
||||
class TodosTable extends Table {
|
||||
|
||||
@override
|
||||
String get tableName => 'todos';
|
||||
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get title => text().withLength(min: 4, max: 6)();
|
||||
TextColumn get title => text().withLength(min: 4, max: 16).nullable()();
|
||||
TextColumn get content => text()();
|
||||
|
||||
IntColumn get category => integer().nullable()();
|
||||
|
||||
}
|
||||
|
||||
class Users extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get name => text().withLength(min: 6, max: 32)();
|
||||
BoolColumn get isAwesome => boolean()();
|
||||
}
|
||||
|
||||
@DataClassName('Category')
|
||||
class Categories extends Table {
|
||||
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get description => text().named('desc')();
|
||||
|
||||
}
|
||||
|
||||
@UseSally(tables: [TodosTable, Categories, Users])
|
||||
class TodoDb extends _$TodoDb {
|
||||
TodoDb(QueryExecutor e) : super(e);
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration => MigrationStrategy();
|
||||
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'todos.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// SallyGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class TodoEntry {
|
||||
final int id;
|
||||
final String title;
|
||||
final String content;
|
||||
final int category;
|
||||
TodoEntry({this.id, this.title, this.content, this.category});
|
||||
@override
|
||||
int get hashCode =>
|
||||
(((id.hashCode) * 31 + title.hashCode) * 31 + content.hashCode) * 31 +
|
||||
category.hashCode;
|
||||
@override
|
||||
bool operator ==(other) =>
|
||||
identical(this, other) ||
|
||||
(other is TodoEntry &&
|
||||
other.id == id &&
|
||||
other.title == title &&
|
||||
other.content == content &&
|
||||
other.category == category);
|
||||
}
|
||||
|
||||
class _$TodosTableTable extends TodosTable
|
||||
implements TableInfo<TodosTable, TodoEntry> {
|
||||
final GeneratedDatabase _db;
|
||||
_$TodosTableTable(this._db);
|
||||
@override
|
||||
GeneratedIntColumn get id =>
|
||||
GeneratedIntColumn('id', false, hasAutoIncrement: true);
|
||||
@override
|
||||
GeneratedTextColumn get title => GeneratedTextColumn(
|
||||
'title',
|
||||
true,
|
||||
);
|
||||
@override
|
||||
GeneratedTextColumn get content => GeneratedTextColumn(
|
||||
'content',
|
||||
false,
|
||||
);
|
||||
@override
|
||||
GeneratedIntColumn get category => GeneratedIntColumn(
|
||||
'category',
|
||||
true,
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, content, category];
|
||||
@override
|
||||
TodosTable get asDslTable => this;
|
||||
@override
|
||||
String get $tableName => 'todos';
|
||||
@override
|
||||
void validateIntegrity(TodoEntry instance, bool isInserting) =>
|
||||
id.isAcceptableValue(instance.id, isInserting) &&
|
||||
title.isAcceptableValue(instance.title, isInserting) &&
|
||||
content.isAcceptableValue(instance.content, isInserting) &&
|
||||
category.isAcceptableValue(instance.category, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => Set();
|
||||
@override
|
||||
TodoEntry map(Map<String, dynamic> data) {
|
||||
final intType = _db.typeSystem.forDartType<int>();
|
||||
final stringType = _db.typeSystem.forDartType<String>();
|
||||
return TodoEntry(
|
||||
id: intType.mapFromDatabaseResponse(data['id']),
|
||||
title: stringType.mapFromDatabaseResponse(data['title']),
|
||||
content: stringType.mapFromDatabaseResponse(data['content']),
|
||||
category: intType.mapFromDatabaseResponse(data['category']),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(TodoEntry d) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.title != null) {
|
||||
map['title'] = Variable<String, StringType>(d.title);
|
||||
}
|
||||
if (d.content != null) {
|
||||
map['content'] = Variable<String, StringType>(d.content);
|
||||
}
|
||||
if (d.category != null) {
|
||||
map['category'] = Variable<int, IntType>(d.category);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
class Category {
|
||||
final int id;
|
||||
final String description;
|
||||
Category({this.id, this.description});
|
||||
@override
|
||||
int get hashCode => (id.hashCode) * 31 + description.hashCode;
|
||||
@override
|
||||
bool operator ==(other) =>
|
||||
identical(this, other) ||
|
||||
(other is Category && other.id == id && other.description == description);
|
||||
}
|
||||
|
||||
class _$CategoriesTable extends Categories
|
||||
implements TableInfo<Categories, Category> {
|
||||
final GeneratedDatabase _db;
|
||||
_$CategoriesTable(this._db);
|
||||
@override
|
||||
GeneratedIntColumn get id =>
|
||||
GeneratedIntColumn('id', false, hasAutoIncrement: true);
|
||||
@override
|
||||
GeneratedTextColumn get description => GeneratedTextColumn(
|
||||
'`desc`',
|
||||
false,
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, description];
|
||||
@override
|
||||
Categories get asDslTable => this;
|
||||
@override
|
||||
String get $tableName => 'categories';
|
||||
@override
|
||||
void validateIntegrity(Category instance, bool isInserting) =>
|
||||
id.isAcceptableValue(instance.id, isInserting) &&
|
||||
description.isAcceptableValue(instance.description, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => Set();
|
||||
@override
|
||||
Category map(Map<String, dynamic> data) {
|
||||
final intType = _db.typeSystem.forDartType<int>();
|
||||
final stringType = _db.typeSystem.forDartType<String>();
|
||||
return Category(
|
||||
id: intType.mapFromDatabaseResponse(data['id']),
|
||||
description: stringType.mapFromDatabaseResponse(data['`desc`']),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(Category d) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.description != null) {
|
||||
map['`desc`'] = Variable<String, StringType>(d.description);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
class User {
|
||||
final int id;
|
||||
final String name;
|
||||
final bool isAwesome;
|
||||
User({this.id, this.name, this.isAwesome});
|
||||
@override
|
||||
int get hashCode =>
|
||||
((id.hashCode) * 31 + name.hashCode) * 31 + isAwesome.hashCode;
|
||||
@override
|
||||
bool operator ==(other) =>
|
||||
identical(this, other) ||
|
||||
(other is User &&
|
||||
other.id == id &&
|
||||
other.name == name &&
|
||||
other.isAwesome == isAwesome);
|
||||
}
|
||||
|
||||
class _$UsersTable extends Users implements TableInfo<Users, User> {
|
||||
final GeneratedDatabase _db;
|
||||
_$UsersTable(this._db);
|
||||
@override
|
||||
GeneratedIntColumn get id =>
|
||||
GeneratedIntColumn('id', false, hasAutoIncrement: true);
|
||||
@override
|
||||
GeneratedTextColumn get name => GeneratedTextColumn(
|
||||
'name',
|
||||
false,
|
||||
);
|
||||
@override
|
||||
GeneratedBoolColumn get isAwesome => GeneratedBoolColumn(
|
||||
'is_awesome',
|
||||
false,
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, isAwesome];
|
||||
@override
|
||||
Users get asDslTable => this;
|
||||
@override
|
||||
String get $tableName => 'users';
|
||||
@override
|
||||
void validateIntegrity(User instance, bool isInserting) =>
|
||||
id.isAcceptableValue(instance.id, isInserting) &&
|
||||
name.isAcceptableValue(instance.name, isInserting) &&
|
||||
isAwesome.isAcceptableValue(instance.isAwesome, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => Set();
|
||||
@override
|
||||
User map(Map<String, dynamic> data) {
|
||||
final intType = _db.typeSystem.forDartType<int>();
|
||||
final stringType = _db.typeSystem.forDartType<String>();
|
||||
final boolType = _db.typeSystem.forDartType<bool>();
|
||||
return User(
|
||||
id: intType.mapFromDatabaseResponse(data['id']),
|
||||
name: stringType.mapFromDatabaseResponse(data['name']),
|
||||
isAwesome: boolType.mapFromDatabaseResponse(data['is_awesome']),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(User d) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.name != null) {
|
||||
map['name'] = Variable<String, StringType>(d.name);
|
||||
}
|
||||
if (d.isAwesome != null) {
|
||||
map['is_awesome'] = Variable<bool, BoolType>(d.isAwesome);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$TodoDb extends GeneratedDatabase {
|
||||
_$TodoDb(QueryExecutor e) : super(const SqlTypeSystem.withDefaults(), e);
|
||||
_$TodosTableTable get todosTable => _$TodosTableTable(this);
|
||||
_$CategoriesTable get categories => _$CategoriesTable(this);
|
||||
_$UsersTable get users => _$UsersTable(this);
|
||||
@override
|
||||
List<TableInfo> get allTables => [todosTable, categories, users];
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import 'package:mockito/mockito.dart';
|
||||
import 'package:sally/sally.dart';
|
||||
import 'package:sally/src/runtime/executor/stream_queries.dart';
|
||||
|
||||
export 'package:mockito/mockito.dart';
|
||||
|
||||
class MockExecutor extends Mock implements QueryExecutor {
|
||||
|
||||
MockExecutor() {
|
||||
when(runSelect(any, any)).thenAnswer((_) => Future.value([]));
|
||||
when(runUpdate(any, any)).thenAnswer((_) => Future.value(0));
|
||||
when(runDelete(any, any)).thenAnswer((_) => Future.value(0));
|
||||
when(runInsert(any, any)).thenAnswer((_) => Future.value(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MockStreamQueries extends Mock implements StreamQueryStore {}
|
||||
|
||||
// used so that we can mock the SqlExecutor typedef
|
||||
abstract class SqlExecutorAsClass {
|
||||
Future<void> call(String sql);
|
||||
}
|
||||
|
||||
class MockQueryExecutor extends Mock implements SqlExecutorAsClass {}
|
|
@ -36,6 +36,8 @@ class TableParser extends ParserBase {
|
|||
}
|
||||
|
||||
String _parseTableName(ClassElement element) {
|
||||
// todo allow override via a field (final String tableName = '') as well
|
||||
|
||||
final tableNameGetter = element.getGetter('tableName');
|
||||
if (tableNameGetter == null) {
|
||||
// class does not override tableName. So just use the dart class name
|
||||
|
|
Loading…
Reference in New Issue