mirror of
https://github.com/immich-app/drift.git
synced 2026-09-30 13:22:57 +08:00
Fix some bugs in the sql parser, another integration test
This commit is contained in:
@@ -69,6 +69,10 @@ class PreferenceConverter extends TypeConverter<Preferences, String> {
|
||||
'SELECT * FROM users u ORDER BY (SELECT COUNT(*) FROM friendships WHERE first_user = u.id OR second_user = u.id) DESC LIMIT :amount',
|
||||
'amountOfGoodFriends':
|
||||
'SELECT COUNT(*) FROM friendships f WHERE f.really_good_friends AND (f.first_user = :user OR f.second_user = :user)',
|
||||
'friendsOf': '''SELECT u.* FROM friendships f
|
||||
INNER JOIN users u ON u.id IN (f.first_user, f.second_user) AND
|
||||
u.id != :user
|
||||
WHERE (f.first_user = :user OR f.second_user = :user)''',
|
||||
'userCount': 'SELECT COUNT(id) FROM users',
|
||||
'settingsFor': 'SELECT preferences FROM users WHERE id = :user',
|
||||
},
|
||||
|
||||
@@ -147,6 +147,20 @@ class UsersCompanion extends UpdateCompanion<User> {
|
||||
this.profilePicture = const Value.absent(),
|
||||
this.preferences = const Value.absent(),
|
||||
});
|
||||
UsersCompanion copyWith(
|
||||
{Value<int> id,
|
||||
Value<String> name,
|
||||
Value<DateTime> birthDate,
|
||||
Value<Uint8List> profilePicture,
|
||||
Value<Preferences> preferences}) {
|
||||
return UsersCompanion(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
birthDate: birthDate ?? this.birthDate,
|
||||
profilePicture: profilePicture ?? this.profilePicture,
|
||||
preferences: preferences ?? this.preferences,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class $UsersTable extends Users with TableInfo<$UsersTable, User> {
|
||||
@@ -388,6 +402,16 @@ class FriendshipsCompanion extends UpdateCompanion<Friendship> {
|
||||
this.secondUser = const Value.absent(),
|
||||
this.reallyGoodFriends = const Value.absent(),
|
||||
});
|
||||
FriendshipsCompanion copyWith(
|
||||
{Value<int> firstUser,
|
||||
Value<int> secondUser,
|
||||
Value<bool> reallyGoodFriends}) {
|
||||
return FriendshipsCompanion(
|
||||
firstUser: firstUser ?? this.firstUser,
|
||||
secondUser: secondUser ?? this.secondUser,
|
||||
reallyGoodFriends: reallyGoodFriends ?? this.reallyGoodFriends,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class $FriendshipsTable extends Friendships
|
||||
@@ -585,6 +609,29 @@ abstract class _$Database extends GeneratedDatabase {
|
||||
}).map((rows) => rows.map(_rowToAmountOfGoodFriendsResult).toList());
|
||||
}
|
||||
|
||||
Future<List<User>> friendsOf(
|
||||
int user,
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelect(
|
||||
'SELECT u.* FROM friendships f\n INNER JOIN users u ON u.id IN (f.first_user, f.second_user) AND\n u.id != :user\n WHERE (f.first_user = :user OR f.second_user = :user)',
|
||||
variables: [
|
||||
Variable.withInt(user),
|
||||
]).then((rows) => rows.map(_rowToUser).toList());
|
||||
}
|
||||
|
||||
Stream<List<User>> watchFriendsOf(int user) {
|
||||
return customSelectStream(
|
||||
'SELECT u.* FROM friendships f\n INNER JOIN users u ON u.id IN (f.first_user, f.second_user) AND\n u.id != :user\n WHERE (f.first_user = :user OR f.second_user = :user)',
|
||||
variables: [
|
||||
Variable.withInt(user),
|
||||
],
|
||||
readsFrom: {
|
||||
friendships,
|
||||
users
|
||||
}).map((rows) => rows.map(_rowToUser).toList());
|
||||
}
|
||||
|
||||
UserCountResult _rowToUserCountResult(QueryRow row) {
|
||||
return UserCountResult(
|
||||
cOUNTid: row.readInt('COUNT(id)'),
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:test/test.dart';
|
||||
import 'package:tests/database/database.dart';
|
||||
import 'package:tests/suite/suite.dart';
|
||||
|
||||
void crudTests(TestExecutor executor) {
|
||||
test('inserting updates a select stream', () async {
|
||||
final db = Database(executor.createExecutor());
|
||||
final friends = db.watchFriendsOf(1);
|
||||
|
||||
final a = await db.getUserById(1);
|
||||
final b = await db.getUserById(2);
|
||||
|
||||
final expectation = expectLater(
|
||||
friends,
|
||||
emitsInOrder(
|
||||
[
|
||||
isEmpty, // initial state without friendships
|
||||
[b] // after we called makeFriends(a,b)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await db.makeFriends(a, b);
|
||||
await expectation;
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:moor/moor.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:tests/suite/crud_tests.dart';
|
||||
import 'package:tests/suite/transactions.dart';
|
||||
|
||||
import 'custom_objects.dart';
|
||||
@@ -17,6 +18,7 @@ void runAllTests(TestExecutor executor) {
|
||||
await executor.deleteData();
|
||||
});
|
||||
|
||||
crudTests(executor);
|
||||
migrationTests(executor);
|
||||
customObjectTests(executor);
|
||||
transactionTests(executor);
|
||||
|
||||
@@ -23,3 +23,5 @@ dependency_overrides:
|
||||
path: ../../../moor
|
||||
moor_generator:
|
||||
path: ../../../moor_generator
|
||||
sqlparser:
|
||||
path: ../../../sqlparser
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:analyzer/dart/constant/value.dart';
|
||||
import 'package:build/build.dart';
|
||||
import 'package:moor_generator/src/state/errors.dart';
|
||||
import 'package:moor_generator/src/model/specified_table.dart';
|
||||
import 'package:moor_generator/src/model/sql_query.dart';
|
||||
@@ -49,8 +50,8 @@ class SqlParser {
|
||||
|
||||
try {
|
||||
foundQueries.add(QueryHandler(name, context, _mapper).handle());
|
||||
} catch (e) {
|
||||
print('Error while generating APIs for ${context.sql}: $e');
|
||||
} catch (e, s) {
|
||||
log.warning('Error while generating APIs for ${context.sql}', e, s);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# We use netlify to deploy the documentation.
|
||||
|
||||
[build]
|
||||
base = "docs/"
|
||||
base = "docs"
|
||||
publish = "docs/public"
|
||||
command = 'git submodule update --init --recursive && HUGO_ENV="production" hugo'
|
||||
|
||||
|
||||
@@ -136,7 +136,9 @@ class TypeResolver {
|
||||
if (sqlParameters is ExprFunctionParameters) {
|
||||
return sqlParameters.parameters;
|
||||
} else if (sqlParameters is StarFunctionParameter) {
|
||||
return call.scope.availableColumns;
|
||||
// if * is used as a parameter, it refers to all columns in all tables
|
||||
// that are available in the current scope.
|
||||
return call.scope.availableColumns.whereType<TableColumn>().toList();
|
||||
}
|
||||
throw ArgumentError('Unknown parameters: $sqlParameters');
|
||||
}
|
||||
|
||||
@@ -95,6 +95,11 @@ class Scanner {
|
||||
_addToken(TokenType.more);
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
if (_match('=')) {
|
||||
_addToken(TokenType.exclamationEqual);
|
||||
}
|
||||
break;
|
||||
case '=':
|
||||
_addToken(_match('=') ? TokenType.doubleEqual : TokenType.equal);
|
||||
break;
|
||||
@@ -138,8 +143,7 @@ class Scanner {
|
||||
} else if (canStartColumnName(char)) {
|
||||
_identifier();
|
||||
} else {
|
||||
errors.add(TokenizerError(
|
||||
'Unexpected character.', SourceLocation(_currentOffset)));
|
||||
errors.add(TokenizerError('Unexpected character.', _currentLocation));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ Map<String, TokenType> testCases = {
|
||||
'<': TokenType.less,
|
||||
'>=': TokenType.moreEqual,
|
||||
'>': TokenType.more,
|
||||
'!=': TokenType.exclamationEqual,
|
||||
"'hello there'": TokenType.stringLiteral,
|
||||
'1.123': TokenType.numberLiteral,
|
||||
'1.32e5': TokenType.numberLiteral,
|
||||
|
||||
Reference in New Issue
Block a user