From 6ba8ed65d662c8b253cbc0e013980d2a980b94ba Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Thu, 6 Jul 2023 15:10:02 +0600 Subject: [PATCH 01/24] feat(orm): initial package update --- .gitignore | 1 + packages/dartseid_orm/.gitignore | 7 ++++ packages/dartseid_orm/CHANGELOG.md | 3 ++ packages/dartseid_orm/README.md | 39 +++++++++++++++++++ packages/dartseid_orm/analysis_options.yaml | 1 + packages/dartseid_orm/lib/dartseid_orm.dart | 1 + .../lib/src/dartseid_orm_base.dart | 1 + packages/dartseid_orm/pubspec.yaml | 15 +++++++ .../dartseid_orm/test/dartseid_orm_test.dart | 16 ++++++++ 9 files changed, 84 insertions(+) create mode 100644 packages/dartseid_orm/.gitignore create mode 100644 packages/dartseid_orm/CHANGELOG.md create mode 100644 packages/dartseid_orm/README.md create mode 100644 packages/dartseid_orm/analysis_options.yaml create mode 100644 packages/dartseid_orm/lib/dartseid_orm.dart create mode 100644 packages/dartseid_orm/lib/src/dartseid_orm_base.dart create mode 100644 packages/dartseid_orm/pubspec.yaml create mode 100644 packages/dartseid_orm/test/dartseid_orm_test.dart diff --git a/.gitignore b/.gitignore index 7b8c15e..1750d2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .dart_tool/ .idea +.nvimrc pubspec_overrides.yaml melos_dartseid.iml diff --git a/packages/dartseid_orm/.gitignore b/packages/dartseid_orm/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/dartseid_orm/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/packages/dartseid_orm/CHANGELOG.md b/packages/dartseid_orm/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/dartseid_orm/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/dartseid_orm/README.md b/packages/dartseid_orm/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/dartseid_orm/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/dartseid_orm/analysis_options.yaml b/packages/dartseid_orm/analysis_options.yaml new file mode 100644 index 0000000..55309e9 --- /dev/null +++ b/packages/dartseid_orm/analysis_options.yaml @@ -0,0 +1 @@ +include: package:lint/analysis_options.yaml diff --git a/packages/dartseid_orm/lib/dartseid_orm.dart b/packages/dartseid_orm/lib/dartseid_orm.dart new file mode 100644 index 0000000..cb77ed2 --- /dev/null +++ b/packages/dartseid_orm/lib/dartseid_orm.dart @@ -0,0 +1 @@ +export 'src/dartseid_orm_base.dart'; diff --git a/packages/dartseid_orm/lib/src/dartseid_orm_base.dart b/packages/dartseid_orm/lib/src/dartseid_orm_base.dart new file mode 100644 index 0000000..095f0a8 --- /dev/null +++ b/packages/dartseid_orm/lib/src/dartseid_orm_base.dart @@ -0,0 +1 @@ +class Dorm {} diff --git a/packages/dartseid_orm/pubspec.yaml b/packages/dartseid_orm/pubspec.yaml new file mode 100644 index 0000000..eee0472 --- /dev/null +++ b/packages/dartseid_orm/pubspec.yaml @@ -0,0 +1,15 @@ +name: dartseid_orm +description: A starting point for Dart libraries or applications. +version: 0.0.1 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: ^3.0.5 + +# Add regular dependencies here. +dependencies: + # path: ^1.8.0 + +dev_dependencies: + lint: ^2.1.2 + test: ^1.21.0 diff --git a/packages/dartseid_orm/test/dartseid_orm_test.dart b/packages/dartseid_orm/test/dartseid_orm_test.dart new file mode 100644 index 0000000..aad3e7d --- /dev/null +++ b/packages/dartseid_orm/test/dartseid_orm_test.dart @@ -0,0 +1,16 @@ +import 'package:dartseid_orm/dartseid_orm.dart'; +import 'package:test/test.dart'; + +void main() { + group('A group of tests', () { + final awesome = Awesome(); + + setUp(() { + // Additional setup goes here. + }); + + test('First Test', () { + expect(awesome.isAwesome, isTrue); + }); + }); +} From 1dc065fe22f03da20f6fb2b3039d10ee80ccc9d6 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Sat, 8 Jul 2023 01:50:33 +0600 Subject: [PATCH 02/24] feat(orm): orm structure --- packages/dartseid/.gitignore | 1 + packages/dartseid_orm/.gitignore | 2 + .../lib/src/dartseid_orm_base.dart | 332 +++++++++++++++++- .../dartseid_orm_sqlite_adapter/.gitignore | 9 + .../dartseid_orm_sqlite_adapter/CHANGELOG.md | 3 + .../dartseid_orm_sqlite_adapter/README.md | 39 ++ .../analysis_options.yaml | 1 + .../lib/dartseid_orm.dart | 1 + .../lib/src/dartseid_orm_base.dart | 1 + .../dartseid_orm_sqlite_adapter/pubspec.yaml | 15 + .../test/dartseid_orm_test.dart | 16 + 11 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 packages/dartseid_orm_sqlite_adapter/.gitignore create mode 100644 packages/dartseid_orm_sqlite_adapter/CHANGELOG.md create mode 100644 packages/dartseid_orm_sqlite_adapter/README.md create mode 100644 packages/dartseid_orm_sqlite_adapter/analysis_options.yaml create mode 100644 packages/dartseid_orm_sqlite_adapter/lib/dartseid_orm.dart create mode 100644 packages/dartseid_orm_sqlite_adapter/lib/src/dartseid_orm_base.dart create mode 100644 packages/dartseid_orm_sqlite_adapter/pubspec.yaml create mode 100644 packages/dartseid_orm_sqlite_adapter/test/dartseid_orm_test.dart diff --git a/packages/dartseid/.gitignore b/packages/dartseid/.gitignore index f0c1008..4b5a957 100644 --- a/packages/dartseid/.gitignore +++ b/packages/dartseid/.gitignore @@ -8,5 +8,6 @@ pubspec.lock .idea/ +melos_dartseid.iml # Generated files in example example/**/*.g.dart diff --git a/packages/dartseid_orm/.gitignore b/packages/dartseid_orm/.gitignore index 3cceda5..cd66d81 100644 --- a/packages/dartseid_orm/.gitignore +++ b/packages/dartseid_orm/.gitignore @@ -5,3 +5,5 @@ # Avoid committing pubspec.lock for library packages; see # https://dart.dev/guides/libraries/private-files#pubspeclock. pubspec.lock + +melos_dartseid_orm.iml diff --git a/packages/dartseid_orm/lib/src/dartseid_orm_base.dart b/packages/dartseid_orm/lib/src/dartseid_orm_base.dart index 095f0a8..ef577c0 100644 --- a/packages/dartseid_orm/lib/src/dartseid_orm_base.dart +++ b/packages/dartseid_orm/lib/src/dartseid_orm_base.dart @@ -1 +1,331 @@ -class Dorm {} +import 'dart:async'; + +// This will be initialized with dart orm class after init method is called +final Map _dorms = {}; + +Dorm getDormInstance([String? name]) { + final dorm = _dorms[name ?? "__default"]; + if (dorm == null) { + throw StateError( + 'Dartseid orm is not initialized. Please run Dorm.init', + ); + } + return dorm; +} + +class Dorm with DormTable { + final DormAdapterBase adapter; + + Dorm._({required this.adapter, String? name}) { + this.name = name ?? "__default"; + _dorms[this.name] = this; + } + + static Future init({ + required DormAdapterBase adapter, + String? name, + }) async { + await adapter.init(); + return Dorm._(adapter: adapter, name: name); + } + + DormTransaction transaction() { + return adapter.transaction(); + } +} + +typedef DormTableConverter = ({ + FutureOr Function(Map json) fromJson, + FutureOr> Function() toJson, +}); + +typedef DormTableFromConverter = ({ + FutureOr Function(Map json) fromJson, +}); + +mixin DormTable { + late String name; + final List _tables = []; + + late final Dorm _dorm = getDormInstance(name); + + DormTableSchema table( + String name, + Map schema, { + required DormTableConverter converter, + }) { + final schema = + DormTableSchema(dorm: _dorm, name: name, baseConverter: converter); + _dorm._tables.add(schema); + return schema; + } + + DormTableSchema getTable(String name) { + try { + return _tables.firstWhere((element) => element.name == name); + } catch (e) { + throw StateError( + "Table ($name) not found. Please make sure table schema is initialized", + ); + } + } +} + +class DormTableSchema { + final Dorm dorm; + final String name; + final DormTableConverter baseConverter; + + DormTableSchema({ + required this.dorm, + required this.name, + required this.baseConverter, + }); + + DormTransaction transaction() { + return dorm.transaction(); + } + + void index(Map config, {({bool? unique})? options}) {} + + DormTableOperator _getTableOperator({ + required TableOperator operator, + DormTransaction? transaction, + }) { + return DormTableOperator( + dorm: dorm, + operator: operator, + baseConverter: baseConverter, + transaction: transaction, + ); + } + + DormTableOperator findOne({DormTransaction? transaction}) { + return _getTableOperator( + operator: TableOperator.findOne, + transaction: transaction, + ); + } + + DormTableOperator findMany({DormTransaction? transaction}) { + return _getTableOperator( + operator: TableOperator.findMany, + transaction: transaction, + ); + } + + DormTableOperator create({DormTransaction? transaction}) { + return _getTableOperator( + operator: TableOperator.create, + transaction: transaction, + ); + } + + DormTableOperator update({DormTransaction? transaction}) { + return _getTableOperator( + operator: TableOperator.update, + transaction: transaction, + ); + } + + DormTableOperator delete({DormTransaction? transaction}) { + return _getTableOperator( + operator: TableOperator.delete, + transaction: transaction, + ); + } +} + +sealed class ExecResult {} + +class ExecResultData extends ExecResult { + final T data; + + ExecResultData(this.data); +} + +class ExecResultFailure extends ExecResult { + final DormException exception; + + ExecResultFailure(this.exception); +} + +class DormTableOperator { + final Dorm _dorm; + final TableOperator _operator; + final DormTableConverter _baseConverter; + final DormTransaction? _transaction; + + final List> createWithParams = []; + final List> updateWithParams = []; + final List> whereParams = []; + final List> includeParams = []; + final List> selectParams = []; + + DormTableOperator({ + required Dorm dorm, + required TableOperator operator, + required ({ + FutureOr Function(Map) fromJson, + FutureOr> Function() toJson + }) baseConverter, + DormTransaction? transaction, + }) : _transaction = transaction, + _baseConverter = baseConverter, + _operator = operator, + _dorm = dorm; + + void createWith() {} + void updateWith() {} + void where() {} + void include() {} + void select() {} + + Future exec({ + DormTableFromConverter? converter, + }) async { + try { + final execConverter = + converter != null ? converter.fromJson : _baseConverter.fromJson; + + final data = await _dorm.adapter.operate(operator: _operator); + + final convertedData = await execConverter(data); + + return ExecResultData(convertedData); + } on DormException catch (e) { + return ExecResultFailure(e); + } catch (e) { + return ExecResultFailure( + DormException(originalError: e, message: "Unknown Error"), + ); + } + } +} + +enum TableOperator { + findOne, + findMany, + create, + update, + delete, +} + +class DormException implements Exception { + final Object? originalError; + final String message; + + DormException({required this.message, required this.originalError}); +} + +abstract class DormTransaction { + Future start(); + Future commit(); + Future rollback(); + Future callback( + FutureOr Function(DormTransaction trx) callback, + ) async { + try { + await start(); + final data = await callback(this); + await commit(); + return data; + } catch (e) { + await rollback(); + rethrow; + } + } +} + +abstract interface class DormAdapterBase { + final dynamic connection; + + DormAdapterBase({ + required this.connection, + }); + + Future init(); + Future> operate({required TableOperator operator}); + DormTransaction transaction(); +} + +class DormMockAdapter implements DormAdapterBase { + @override + final dynamic connection; + + DormMockAdapter({ + required this.connection, + }); + + @override + Future init() { + // TODO: implement init + throw UnimplementedError(); + } + + @override + Future> operate({required TableOperator operator}) { + print(operator); + throw UnimplementedError(); + } + + @override + DormTransaction transaction() { + // TODO: implement transaction + throw UnimplementedError(); + } + + @override + String a() { + // TODO: implement a + throw UnimplementedError(); + } +} + +Future dorming() async { + final a = await Dorm.init( + adapter: DormMockAdapter(connection: ""), + ); + + final t = a.table( + "users", + { + "id": "", // Have a columnmeta class object + "name": "", + }, + converter: ( + fromJson: (Map j) {}, + toJson: () => {}, + ), + ); + + t.index({"id": 1, "name": 1}); + + final trx = t.transaction(); + + final x = t.create(); + + final data = await trx.callback((trx) async { + final r = t.findOne(transaction: trx) + ..where() + ..select() + ..include(); + + Future fromJsonFn(Map j) async { + return ""; + } + + final result = await r.exec(converter: (fromJson: fromJsonFn)); + + return switch (result) { + ExecResultData(data: final data) => data, + ExecResultFailure(exception: final _) => await () async { + await trx.rollback(); + throw Exception("I am basic"); + }() + }; + }); + + // more dorming + return data; +} diff --git a/packages/dartseid_orm_sqlite_adapter/.gitignore b/packages/dartseid_orm_sqlite_adapter/.gitignore new file mode 100644 index 0000000..473386d --- /dev/null +++ b/packages/dartseid_orm_sqlite_adapter/.gitignore @@ -0,0 +1,9 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock + +melos_dartseid_orm_sqlite_adapter.iml diff --git a/packages/dartseid_orm_sqlite_adapter/CHANGELOG.md b/packages/dartseid_orm_sqlite_adapter/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/dartseid_orm_sqlite_adapter/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/dartseid_orm_sqlite_adapter/README.md b/packages/dartseid_orm_sqlite_adapter/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/dartseid_orm_sqlite_adapter/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/dartseid_orm_sqlite_adapter/analysis_options.yaml b/packages/dartseid_orm_sqlite_adapter/analysis_options.yaml new file mode 100644 index 0000000..55309e9 --- /dev/null +++ b/packages/dartseid_orm_sqlite_adapter/analysis_options.yaml @@ -0,0 +1 @@ +include: package:lint/analysis_options.yaml diff --git a/packages/dartseid_orm_sqlite_adapter/lib/dartseid_orm.dart b/packages/dartseid_orm_sqlite_adapter/lib/dartseid_orm.dart new file mode 100644 index 0000000..cb77ed2 --- /dev/null +++ b/packages/dartseid_orm_sqlite_adapter/lib/dartseid_orm.dart @@ -0,0 +1 @@ +export 'src/dartseid_orm_base.dart'; diff --git a/packages/dartseid_orm_sqlite_adapter/lib/src/dartseid_orm_base.dart b/packages/dartseid_orm_sqlite_adapter/lib/src/dartseid_orm_base.dart new file mode 100644 index 0000000..095f0a8 --- /dev/null +++ b/packages/dartseid_orm_sqlite_adapter/lib/src/dartseid_orm_base.dart @@ -0,0 +1 @@ +class Dorm {} diff --git a/packages/dartseid_orm_sqlite_adapter/pubspec.yaml b/packages/dartseid_orm_sqlite_adapter/pubspec.yaml new file mode 100644 index 0000000..f06e52c --- /dev/null +++ b/packages/dartseid_orm_sqlite_adapter/pubspec.yaml @@ -0,0 +1,15 @@ +name: dartseid_orm_sqlite_adapter +description: A starting point for Dart libraries or applications. +version: 0.0.1 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: ^3.0.5 + +# Add regular dependencies here. +dependencies: + dartseid_orm: ^0.0.1 + +dev_dependencies: + lint: ^2.1.2 + test: ^1.21.0 diff --git a/packages/dartseid_orm_sqlite_adapter/test/dartseid_orm_test.dart b/packages/dartseid_orm_sqlite_adapter/test/dartseid_orm_test.dart new file mode 100644 index 0000000..aad3e7d --- /dev/null +++ b/packages/dartseid_orm_sqlite_adapter/test/dartseid_orm_test.dart @@ -0,0 +1,16 @@ +import 'package:dartseid_orm/dartseid_orm.dart'; +import 'package:test/test.dart'; + +void main() { + group('A group of tests', () { + final awesome = Awesome(); + + setUp(() { + // Additional setup goes here. + }); + + test('First Test', () { + expect(awesome.isAwesome, isTrue); + }); + }); +} From 9a6c65280f5dbc62594a4d176a230451f8c50f90 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Sun, 9 Jul 2023 01:42:10 +0600 Subject: [PATCH 03/24] feat(orm): updated api structure and dir structure --- packages/dartseid_orm/example/api/basic.dart | 127 ++++ packages/dartseid_orm/lib/dartseid_orm.dart | 5 +- packages/dartseid_orm/lib/src/adapter.dart | 110 +++ packages/dartseid_orm/lib/src/core.dart | 45 ++ .../lib/src/dartseid_orm_base.dart | 331 --------- packages/dartseid_orm/lib/src/query.dart | 656 ++++++++++++++++++ packages/dartseid_orm/lib/src/table.dart | 165 +++++ 7 files changed, 1107 insertions(+), 332 deletions(-) create mode 100644 packages/dartseid_orm/example/api/basic.dart create mode 100644 packages/dartseid_orm/lib/src/adapter.dart create mode 100644 packages/dartseid_orm/lib/src/core.dart delete mode 100644 packages/dartseid_orm/lib/src/dartseid_orm_base.dart create mode 100644 packages/dartseid_orm/lib/src/query.dart create mode 100644 packages/dartseid_orm/lib/src/table.dart diff --git a/packages/dartseid_orm/example/api/basic.dart b/packages/dartseid_orm/example/api/basic.dart new file mode 100644 index 0000000..246c0a9 --- /dev/null +++ b/packages/dartseid_orm/example/api/basic.dart @@ -0,0 +1,127 @@ +import 'package:dartseid_orm/dartseid_orm.dart'; + +class DormMockAdapter implements DormAdapterBase { + final dynamic _connection; + + DormMockAdapter({ + required dynamic connection, + }) : _connection = connection; + + @override + Future init() { + // TODO: implement init + throw UnimplementedError(); + } + + @override + Future> operate({ + required TableOperator operator, + required DormTransaction? transaction, + required bool isExplain, + String? rawSql, + Map? rawNoSql, + List> whereParams = const [], + List> havingParams = const [], + List> selectParams = const [], + List includeParams = const [], + List groupParams = const [], + List> sortParams = const [], + List> updateWithParams = const [], + List> createWithParams = const [], + int? limit, + int? skip, + }) { + throw UnimplementedError(); + } + + @override + DormTransaction transaction() { + // TODO: implement transaction + throw UnimplementedError(); + } +} + +Future dorming() async { + final a = await Dorm.init( + adapter: DormMockAdapter(connection: ""), + ); + + final t = a.table( + "users", + { + "id": ColumnInt(), + "name": ColumnString(), + }, + converter: ( + fromJson: (Map j) {}, + toJson: () => {}, + ), + ); + + t.index({"id": 1, "name": 1}); + + // final trx = t.transaction(); + // final b = await trx.start(); + // trx.commit(); + // trx.rollback(); + + final data = await t.transaction().start( + (trx) async { + final r = t.findOne(transaction: trx) + ..where( + and([ + { + "name": like("%aa"), + "id": array([1, 2, 4]), + }, + {"name": eq("2")} + ]), + ) + ..where( + or([ + { + "name": like("%aa"), + "id": between(1, 200), + } + ]), + ) + ..select({ + "id": show(), + "_id": hide(), + "nom": field("name"), + "avg": avg("name"), + "count": count("name"), + "countD": count("DISTINCT(name)"), + "x": distinct("name"), + "max": max("name"), + }) + ..include( + "profile", + on: "profileId", + where: and([ + {"bio": notEq(null)}, + {"bio": notEq("")}, + ]), + joinType: JoinOperation.left, + ) + ..limit(10) + ..skip(0); + + Future fromJsonFn(Map j) async { + return ""; + } + + final result = await r.exec(converter: (fromJson: fromJsonFn)); + + return switch (result) { + ExecResultData(data: final data) => data, + ExecResultFailure(exception: final _) => await () async { + throw Exception("I am basic"); + }() + }; + }, + ); + + // more dorming + return data; +} diff --git a/packages/dartseid_orm/lib/dartseid_orm.dart b/packages/dartseid_orm/lib/dartseid_orm.dart index cb77ed2..531e433 100644 --- a/packages/dartseid_orm/lib/dartseid_orm.dart +++ b/packages/dartseid_orm/lib/dartseid_orm.dart @@ -1 +1,4 @@ -export 'src/dartseid_orm_base.dart'; +export 'src/adapter.dart'; +export 'src/core.dart'; +export 'src/query.dart'; +export 'src/table.dart'; diff --git a/packages/dartseid_orm/lib/src/adapter.dart b/packages/dartseid_orm/lib/src/adapter.dart new file mode 100644 index 0000000..65952ec --- /dev/null +++ b/packages/dartseid_orm/lib/src/adapter.dart @@ -0,0 +1,110 @@ +import 'dart:async'; + +import 'package:dartseid_orm/src/core.dart'; +import 'package:dartseid_orm/src/query.dart'; + +abstract interface class DormAdapterBase { + final dynamic _connection; + + DormAdapterBase({ + required dynamic connection, + }) : _connection = connection; + + Future init(); + Future> operate({ + required TableOperator operator, + required DormTransaction? transaction, + required bool isExplain, + String? rawSql, + Map? rawNoSql, + List> whereParams = const [], + List> havingParams = const [], + List> selectParams = const [], + List includeParams = const [], + List groupParams = const [], + List> sortParams = const [], + List> updateWithParams = const [], + List> createWithParams = const [], + int? limit, + int? skip, + }); + DormTransaction transaction(); +} + +abstract class DormTransaction { + bool isStarted = false; + bool isCommitted = false; + bool isRolledBack = false; + + Future commit() async { + if (!isStarted) { + throw DormException( + message: "Cannot Commit a transaction that has not been started", + originalError: null, + ); + } + if (isCommitted) { + throw DormException( + message: "Cannot Commit a transaction that is already committed", + originalError: null, + ); + } + if (isRolledBack) { + throw DormException( + message: "Cannot Commit a transaction that has been rolled back", + originalError: null, + ); + } + await _commit(); + isCommitted = true; + } + + Future rollback() async { + if (!isStarted) { + throw DormException( + message: "Cannot Rollback a transaction that has not been started", + originalError: null, + ); + } + if (isCommitted) { + throw DormException( + message: "Cannot Rollback a transaction that is already committed", + originalError: null, + ); + } + if (isRolledBack) { + throw DormException( + message: "Cannot Rollback a transaction that is already rolled back", + originalError: null, + ); + } + await _rollback(); + isRolledBack = true; + } + + Future start([ + FutureOr Function(DormTransaction trx)? callback, + ]) async { + try { + await _start(); + isStarted = true; + if (callback == null) { + return null; + } + final data = await callback(this); + await commit(); + return data; + } catch (e) { + if (callback != null) { + await rollback(); + } + rethrow; + } + } + + Future _commit(); + + Future _rollback(); + + Future _start(); +} diff --git a/packages/dartseid_orm/lib/src/core.dart b/packages/dartseid_orm/lib/src/core.dart new file mode 100644 index 0000000..cf3145a --- /dev/null +++ b/packages/dartseid_orm/lib/src/core.dart @@ -0,0 +1,45 @@ +import 'dart:async'; + +import 'package:dartseid_orm/src/adapter.dart'; +import 'package:dartseid_orm/src/table.dart'; + +// This will be initialized with dart orm class after init method is called +final Map _dorms = {}; + +Dorm getDormInstance([String? name]) { + final dorm = _dorms[name ?? "__default"]; + if (dorm == null) { + throw StateError( + 'Dartseid orm is not initialized. Please run Dorm.init', + ); + } + return dorm; +} + +class Dorm with DormTable { + final DormAdapterBase adapter; + + Dorm._({required this.adapter, String? name}) { + this.name = name ?? "__default"; + _dorms[this.name] = this; + } + + DormTransaction transaction() { + return adapter.transaction(); + } + + static Future init({ + required DormAdapterBase adapter, + String? name, + }) async { + await adapter.init(); + return Dorm._(adapter: adapter, name: name); + } +} + +class DormException implements Exception { + final Object? originalError; + final String message; + + DormException({required this.message, required this.originalError}); +} diff --git a/packages/dartseid_orm/lib/src/dartseid_orm_base.dart b/packages/dartseid_orm/lib/src/dartseid_orm_base.dart deleted file mode 100644 index ef577c0..0000000 --- a/packages/dartseid_orm/lib/src/dartseid_orm_base.dart +++ /dev/null @@ -1,331 +0,0 @@ -import 'dart:async'; - -// This will be initialized with dart orm class after init method is called -final Map _dorms = {}; - -Dorm getDormInstance([String? name]) { - final dorm = _dorms[name ?? "__default"]; - if (dorm == null) { - throw StateError( - 'Dartseid orm is not initialized. Please run Dorm.init', - ); - } - return dorm; -} - -class Dorm with DormTable { - final DormAdapterBase adapter; - - Dorm._({required this.adapter, String? name}) { - this.name = name ?? "__default"; - _dorms[this.name] = this; - } - - static Future init({ - required DormAdapterBase adapter, - String? name, - }) async { - await adapter.init(); - return Dorm._(adapter: adapter, name: name); - } - - DormTransaction transaction() { - return adapter.transaction(); - } -} - -typedef DormTableConverter = ({ - FutureOr Function(Map json) fromJson, - FutureOr> Function() toJson, -}); - -typedef DormTableFromConverter = ({ - FutureOr Function(Map json) fromJson, -}); - -mixin DormTable { - late String name; - final List _tables = []; - - late final Dorm _dorm = getDormInstance(name); - - DormTableSchema table( - String name, - Map schema, { - required DormTableConverter converter, - }) { - final schema = - DormTableSchema(dorm: _dorm, name: name, baseConverter: converter); - _dorm._tables.add(schema); - return schema; - } - - DormTableSchema getTable(String name) { - try { - return _tables.firstWhere((element) => element.name == name); - } catch (e) { - throw StateError( - "Table ($name) not found. Please make sure table schema is initialized", - ); - } - } -} - -class DormTableSchema { - final Dorm dorm; - final String name; - final DormTableConverter baseConverter; - - DormTableSchema({ - required this.dorm, - required this.name, - required this.baseConverter, - }); - - DormTransaction transaction() { - return dorm.transaction(); - } - - void index(Map config, {({bool? unique})? options}) {} - - DormTableOperator _getTableOperator({ - required TableOperator operator, - DormTransaction? transaction, - }) { - return DormTableOperator( - dorm: dorm, - operator: operator, - baseConverter: baseConverter, - transaction: transaction, - ); - } - - DormTableOperator findOne({DormTransaction? transaction}) { - return _getTableOperator( - operator: TableOperator.findOne, - transaction: transaction, - ); - } - - DormTableOperator findMany({DormTransaction? transaction}) { - return _getTableOperator( - operator: TableOperator.findMany, - transaction: transaction, - ); - } - - DormTableOperator create({DormTransaction? transaction}) { - return _getTableOperator( - operator: TableOperator.create, - transaction: transaction, - ); - } - - DormTableOperator update({DormTransaction? transaction}) { - return _getTableOperator( - operator: TableOperator.update, - transaction: transaction, - ); - } - - DormTableOperator delete({DormTransaction? transaction}) { - return _getTableOperator( - operator: TableOperator.delete, - transaction: transaction, - ); - } -} - -sealed class ExecResult {} - -class ExecResultData extends ExecResult { - final T data; - - ExecResultData(this.data); -} - -class ExecResultFailure extends ExecResult { - final DormException exception; - - ExecResultFailure(this.exception); -} - -class DormTableOperator { - final Dorm _dorm; - final TableOperator _operator; - final DormTableConverter _baseConverter; - final DormTransaction? _transaction; - - final List> createWithParams = []; - final List> updateWithParams = []; - final List> whereParams = []; - final List> includeParams = []; - final List> selectParams = []; - - DormTableOperator({ - required Dorm dorm, - required TableOperator operator, - required ({ - FutureOr Function(Map) fromJson, - FutureOr> Function() toJson - }) baseConverter, - DormTransaction? transaction, - }) : _transaction = transaction, - _baseConverter = baseConverter, - _operator = operator, - _dorm = dorm; - - void createWith() {} - void updateWith() {} - void where() {} - void include() {} - void select() {} - - Future exec({ - DormTableFromConverter? converter, - }) async { - try { - final execConverter = - converter != null ? converter.fromJson : _baseConverter.fromJson; - - final data = await _dorm.adapter.operate(operator: _operator); - - final convertedData = await execConverter(data); - - return ExecResultData(convertedData); - } on DormException catch (e) { - return ExecResultFailure(e); - } catch (e) { - return ExecResultFailure( - DormException(originalError: e, message: "Unknown Error"), - ); - } - } -} - -enum TableOperator { - findOne, - findMany, - create, - update, - delete, -} - -class DormException implements Exception { - final Object? originalError; - final String message; - - DormException({required this.message, required this.originalError}); -} - -abstract class DormTransaction { - Future start(); - Future commit(); - Future rollback(); - Future callback( - FutureOr Function(DormTransaction trx) callback, - ) async { - try { - await start(); - final data = await callback(this); - await commit(); - return data; - } catch (e) { - await rollback(); - rethrow; - } - } -} - -abstract interface class DormAdapterBase { - final dynamic connection; - - DormAdapterBase({ - required this.connection, - }); - - Future init(); - Future> operate({required TableOperator operator}); - DormTransaction transaction(); -} - -class DormMockAdapter implements DormAdapterBase { - @override - final dynamic connection; - - DormMockAdapter({ - required this.connection, - }); - - @override - Future init() { - // TODO: implement init - throw UnimplementedError(); - } - - @override - Future> operate({required TableOperator operator}) { - print(operator); - throw UnimplementedError(); - } - - @override - DormTransaction transaction() { - // TODO: implement transaction - throw UnimplementedError(); - } - - @override - String a() { - // TODO: implement a - throw UnimplementedError(); - } -} - -Future dorming() async { - final a = await Dorm.init( - adapter: DormMockAdapter(connection: ""), - ); - - final t = a.table( - "users", - { - "id": "", // Have a columnmeta class object - "name": "", - }, - converter: ( - fromJson: (Map j) {}, - toJson: () => {}, - ), - ); - - t.index({"id": 1, "name": 1}); - - final trx = t.transaction(); - - final x = t.create(); - - final data = await trx.callback((trx) async { - final r = t.findOne(transaction: trx) - ..where() - ..select() - ..include(); - - Future fromJsonFn(Map j) async { - return ""; - } - - final result = await r.exec(converter: (fromJson: fromJsonFn)); - - return switch (result) { - ExecResultData(data: final data) => data, - ExecResultFailure(exception: final _) => await () async { - await trx.rollback(); - throw Exception("I am basic"); - }() - }; - }); - - // more dorming - return data; -} diff --git a/packages/dartseid_orm/lib/src/query.dart b/packages/dartseid_orm/lib/src/query.dart new file mode 100644 index 0000000..1037d58 --- /dev/null +++ b/packages/dartseid_orm/lib/src/query.dart @@ -0,0 +1,656 @@ +import 'dart:async'; + +import 'package:dartseid_orm/src/adapter.dart'; +import 'package:dartseid_orm/src/core.dart'; +import 'package:dartseid_orm/src/table.dart'; + +Map and(List> value) { + final Map mergedMap = {}; + for (final element in value) { + element.forEach((key, _) { + element[key]?.isAnd = true; + }); + mergedMap.addAll(element); + } + return mergedMap; +} + +Map or(List> value) { + final Map mergedMap = {}; + for (final element in value) { + element.forEach((key, _) { + element[key]?.isOr = true; + }); + mergedMap.addAll(element); + } + return mergedMap; +} + +WhereParam array(T value) { + return WhereParam( + operator: WhereOperator.array, + value: value, + ); +} + +SelectParam avg(String value) { + return SelectParam( + operator: SelectAggregationOperator.avg, + fieldAs: value, + ); +} + +WhereParam between(T start, T end) { + return WhereParam( + operator: WhereOperator.between, + start: start, + end: end, + ); +} + +SelectParam count(String value) { + return SelectParam( + operator: SelectAggregationOperator.count, + fieldAs: value, + ); +} + +SelectParam countDistinct(String value) { + return SelectParam( + operator: SelectAggregationOperator.countDistinct, + fieldAs: value, + ); +} + +SelectParam distinct(String value) { + return SelectParam( + operator: SelectAggregationOperator.distinct, + fieldAs: value, + ); +} + +WhereParam eq(T value) { + return WhereParam( + operator: WhereOperator.eq, + value: value, + ); +} + +SelectParam field(String value) { + return SelectParam( + operator: SelectAggregationOperator.show, + fieldAs: value, + ); +} + +WhereParam gt(T value) { + return WhereParam( + operator: WhereOperator.gt, + value: value, + ); +} + +WhereParam gte(T value) { + return WhereParam( + operator: WhereOperator.gte, + value: value, + ); +} + +SelectParam hide() { + return SelectParam( + operator: SelectAggregationOperator.hide, + ); +} + +WhereParam like(String value) { + return WhereParam( + operator: WhereOperator.like, + value: value, + ); +} + +WhereParam lt(T value) { + return WhereParam( + operator: WhereOperator.lt, + value: value, + ); +} + +WhereParam lte(T value) { + return WhereParam( + operator: WhereOperator.lte, + value: value, + ); +} + +SelectParam max(String value) { + return SelectParam( + operator: SelectAggregationOperator.max, + fieldAs: value, + ); +} + +SelectParam min(String value) { + return SelectParam( + operator: SelectAggregationOperator.min, + fieldAs: value, + ); +} + +WhereParam notEq(T value) { + return WhereParam( + operator: WhereOperator.notEq, + value: value, + ); +} + +WhereParam notInArray(T value) { + return WhereParam( + operator: WhereOperator.notInArray, + value: value, + ); +} + +SelectParam show() { + return SelectParam( + operator: SelectAggregationOperator.show, + ); +} + +SelectParam sum(String value) { + return SelectParam( + operator: SelectAggregationOperator.sum, + fieldAs: value, + ); +} + +class DormTableCreateOperator { + final Dorm _dorm; + final TableOperator _operator; + final DormTableConverter _baseConverter; + final DormTransaction? _transaction; + + final List> _createWithParams = []; + + bool _isExplain = false; + + DormTableCreateOperator({ + required Dorm dorm, + required TableOperator operator, + required ({ + FutureOr Function(Map) fromJson, + FutureOr> Function() toJson + }) baseConverter, + DormTransaction? transaction, + }) : _transaction = transaction, + _baseConverter = baseConverter, + _operator = operator, + _dorm = dorm; + + void createWith(Map value) { + _createWithParams.add(value); + } + + Future exec({ + DormTableFromConverter? converter, + }) async { + try { + final execConverter = + converter != null ? converter.fromJson : _baseConverter.fromJson; + + final data = await _dorm.adapter.operate( + isExplain: _isExplain, + operator: _operator, + transaction: _transaction, + createWithParams: _createWithParams, + ); + + final convertedData = await execConverter(data); + + return ExecResultData(convertedData); + } on DormException catch (e) { + return ExecResultFailure(e); + } catch (e) { + return ExecResultFailure( + DormException(originalError: e, message: "Unknown Error"), + ); + } + } + + void explain() { + _isExplain = true; + } +} + +class DormTableDeleteOperator { + final Dorm _dorm; + final TableOperator _operator; + final DormTableConverter _baseConverter; + final DormTransaction? _transaction; + + final List> _whereParams = []; + final List _includeParams = []; + + bool _isExplain = false; + + DormTableDeleteOperator({ + required Dorm dorm, + required TableOperator operator, + required ({ + FutureOr Function(Map) fromJson, + FutureOr> Function() toJson + }) baseConverter, + DormTransaction? transaction, + }) : _transaction = transaction, + _baseConverter = baseConverter, + _operator = operator, + _dorm = dorm; + + Future exec({ + DormTableFromConverter? converter, + }) async { + try { + final execConverter = + converter != null ? converter.fromJson : _baseConverter.fromJson; + + final data = await _dorm.adapter.operate( + isExplain: _isExplain, + operator: _operator, + transaction: _transaction, + whereParams: _whereParams, + includeParams: _includeParams, + ); + + final convertedData = await execConverter(data); + + return ExecResultData(convertedData); + } on DormException catch (e) { + return ExecResultFailure(e); + } catch (e) { + return ExecResultFailure( + DormException(originalError: e, message: "Unknown Error"), + ); + } + } + + void explain() { + _isExplain = true; + } + + void include( + String tableName, { + String? on, + Map? where, + JoinOperation joinType = JoinOperation.inner, + }) { + _includeParams.add( + IncludeParam( + tableName, + on: on, + where: where, + joinType: joinType, + ), + ); + } + + void where(Map value) { + _whereParams.add(value); + } +} + +class DormTableFindOperator { + final Dorm _dorm; + final TableOperator _operator; + final DormTableConverter _baseConverter; + final DormTransaction? _transaction; + + final List> _whereParams = []; + final List> _havingParams = []; + final List _includeParams = []; + final List _groupParams = []; + final List> _sortParams = []; + final List> _selectParams = []; + + int? _limit; + int? _skip; + + bool _isExplain = false; + + DormTableFindOperator({ + required Dorm dorm, + required TableOperator operator, + required ({ + FutureOr Function(Map) fromJson, + FutureOr> Function() toJson + }) baseConverter, + DormTransaction? transaction, + }) : _transaction = transaction, + _baseConverter = baseConverter, + _operator = operator, + _dorm = dorm; + + Future exec({ + DormTableFromConverter? converter, + }) async { + try { + final execConverter = + converter != null ? converter.fromJson : _baseConverter.fromJson; + + final data = await _dorm.adapter.operate( + isExplain: _isExplain, + operator: _operator, + transaction: _transaction, + whereParams: _whereParams, + includeParams: _includeParams, + selectParams: _selectParams, + havingParams: _havingParams, + groupParams: _groupParams, + sortParams: _sortParams, + limit: _limit, + skip: _skip, + ); + + final convertedData = await execConverter(data); + + return ExecResultData(convertedData); + } on DormException catch (e) { + return ExecResultFailure(e); + } catch (e) { + return ExecResultFailure( + DormException(originalError: e, message: "Unknown Error"), + ); + } + } + + void explain() { + _isExplain = true; + } + + void group(String column) { + _groupParams.add(column); + } + + void having(Map value) { + _havingParams.add(value); + } + + void include( + String tableName, { + String? on, + Map? where, + JoinOperation joinType = JoinOperation.inner, + }) { + _includeParams.add( + IncludeParam( + tableName, + on: on, + where: where, + joinType: joinType, + ), + ); + } + + /// Set the number of results to return. Cannot be less than 1. + void limit(int limit) { + if (limit <= 0) { + throw DormException( + message: "limit cannot be less then 1", + originalError: null, + ); + } + _limit = limit; + } + + void select(Map value) { + _selectParams.add(value); + } + + /// Set the number of results skipped. Cannot be less than 0. + void skip(int skip) { + if (skip < 0) { + throw DormException( + message: "skip cannot be less then 0", + originalError: null, + ); + } + _skip = skip; + } + + void sort(Map sortBy) { + final Map sortValue = + sortBy.map((key, value) => MapEntry(key, value > 0 ? 1 : -1)); + _sortParams.add(sortValue); + } + + void where(Map value) { + _whereParams.add(value); + } +} + +class DormTableRawOperator { + final Dorm _dorm; + final TableOperator _operator; + final DormTableConverter _baseConverter; + final DormTransaction? _transaction; + + bool _isExplain = false; + + String? _rawSql; + Map? _rawNoSql; + + DormTableRawOperator({ + required Dorm dorm, + required TableOperator operator, + required ({ + FutureOr Function(Map) fromJson, + FutureOr> Function() toJson + }) baseConverter, + DormTransaction? transaction, + }) : _transaction = transaction, + _baseConverter = baseConverter, + _operator = operator, + _dorm = dorm; + + Future exec({ + DormTableFromConverter? converter, + }) async { + try { + final execConverter = + converter != null ? converter.fromJson : _baseConverter.fromJson; + + final data = await _dorm.adapter.operate( + isExplain: _isExplain, + rawSql: _rawSql, + rawNoSql: _rawNoSql, + operator: _operator, + transaction: _transaction, + ); + + final convertedData = await execConverter(data); + + return ExecResultData(convertedData); + } on DormException catch (e) { + return ExecResultFailure(e); + } catch (e) { + return ExecResultFailure( + DormException(originalError: e, message: "Unknown Error"), + ); + } + } + + void explain() { + _isExplain = true; + } + + // ignore: use_setters_to_change_properties + void noSql(Map query) { + _rawNoSql = query; + } + + // ignore: use_setters_to_change_properties + void sql(String query) { + _rawSql = query; + } +} + +class DormTableUpdateOperator { + final Dorm _dorm; + final TableOperator _operator; + final DormTableConverter _baseConverter; + final DormTransaction? _transaction; + + final List> _updateWithParams = []; + final List> _whereParams = []; + + bool _isExplain = false; + + DormTableUpdateOperator({ + required Dorm dorm, + required TableOperator operator, + required ({ + FutureOr Function(Map) fromJson, + FutureOr> Function() toJson + }) baseConverter, + DormTransaction? transaction, + }) : _transaction = transaction, + _baseConverter = baseConverter, + _operator = operator, + _dorm = dorm; + + Future exec({ + DormTableFromConverter? converter, + }) async { + try { + final execConverter = + converter != null ? converter.fromJson : _baseConverter.fromJson; + + final data = await _dorm.adapter.operate( + isExplain: _isExplain, + operator: _operator, + transaction: _transaction, + whereParams: _whereParams, + updateWithParams: _updateWithParams, + ); + + final convertedData = await execConverter(data); + + return ExecResultData(convertedData); + } on DormException catch (e) { + return ExecResultFailure(e); + } catch (e) { + return ExecResultFailure( + DormException(originalError: e, message: "Unknown Error"), + ); + } + } + + void explain() { + _isExplain = true; + } + + void updateWith(Map value) { + _updateWithParams.add(value); + } + + void where(Map value) { + _whereParams.add(value); + } +} + +sealed class ExecResult {} + +class ExecResultData extends ExecResult { + final T data; + + ExecResultData(this.data); +} + +class ExecResultFailure extends ExecResult { + final DormException exception; + + ExecResultFailure(this.exception); +} + +class IncludeParam { + final String tableName; + final String? on; + final JoinOperation joinType; + Map? where; + IncludeParam( + this.tableName, { + this.on, + this.where, + this.joinType = JoinOperation.inner, + }); +} + +enum JoinOperation { + inner, + left, + right, + cross, +} + +enum SelectAggregationOperator { + show, + hide, + count, + sum, + avg, + min, + max, + distinct, + countDistinct, +} + +class SelectParam { + String? fieldAs; + final SelectAggregationOperator operator; + + SelectParam({ + required this.operator, + this.fieldAs, + }); +} + +enum TableOperator { + raw, + count, + findOne, + findMany, + create, + update, + delete, +} + +enum WhereOperator { + eq, + gt, + gte, + lt, + lte, + between, + notEq, + like, + array, + notInArray, + and, + or, +} + +class WhereParam { + final WhereOperator operator; + final T? value; + final T? start; + final T? end; + bool isAnd = true; + bool isOr = false; + + WhereParam({ + required this.operator, + this.value, + this.start, + this.end, + }); +} diff --git a/packages/dartseid_orm/lib/src/table.dart b/packages/dartseid_orm/lib/src/table.dart new file mode 100644 index 0000000..fe9933b --- /dev/null +++ b/packages/dartseid_orm/lib/src/table.dart @@ -0,0 +1,165 @@ +import 'dart:async'; + +import 'package:dartseid_orm/src/adapter.dart'; +import 'package:dartseid_orm/src/core.dart'; +import 'package:dartseid_orm/src/query.dart'; + +typedef DormTableConverter = ({ + FutureOr Function(Map json) fromJson, + FutureOr> Function() toJson, +}); + +typedef DormTableFromConverter = ({ + FutureOr Function(Map json) fromJson, +}); + +mixin DormTable { + late String name; + final List _tables = []; + + late final Dorm _dorm = getDormInstance(name); + + DormTableSchema table( + String name, + Map schema, { + required DormTableConverter converter, + }) { + final schema = + DormTableSchema(dorm: _dorm, name: name, baseConverter: converter); + _dorm._tables.add(schema); + return schema; + } + + DormTableSchema getTable(String name) { + try { + return _tables.firstWhere((element) => element.name == name); + } catch (e) { + throw StateError( + "Table ($name) not found. Please make sure table schema is initialized", + ); + } + } +} + +class DormTableSchema { + final Dorm dorm; + final String name; + final DormTableConverter baseConverter; + + DormTableSchema({ + required this.dorm, + required this.name, + required this.baseConverter, + }); + + DormTransaction transaction() { + return dorm.transaction(); + } + + void index(Map config, {({bool? unique})? options}) {} + + DormTableRawOperator raw({DormTransaction? transaction}) { + return DormTableRawOperator( + dorm: dorm, + operator: TableOperator.raw, + baseConverter: baseConverter, + transaction: transaction, + ); + } + + DormTableFindOperator count({DormTransaction? transaction}) { + return DormTableFindOperator( + dorm: dorm, + operator: TableOperator.count, + baseConverter: baseConverter, + transaction: transaction, + ); + } + + DormTableFindOperator findOne({DormTransaction? transaction}) { + return DormTableFindOperator( + dorm: dorm, + operator: TableOperator.findOne, + baseConverter: baseConverter, + transaction: transaction, + ); + } + + DormTableFindOperator findMany({DormTransaction? transaction}) { + return DormTableFindOperator( + dorm: dorm, + operator: TableOperator.findMany, + baseConverter: baseConverter, + transaction: transaction, + ); + } + + DormTableCreateOperator create({DormTransaction? transaction}) { + return DormTableCreateOperator( + dorm: dorm, + operator: TableOperator.create, + baseConverter: baseConverter, + transaction: transaction, + ); + } + + DormTableUpdateOperator update({DormTransaction? transaction}) { + return DormTableUpdateOperator( + dorm: dorm, + operator: TableOperator.update, + baseConverter: baseConverter, + transaction: transaction, + ); + } + + DormTableDeleteOperator delete({DormTransaction? transaction}) { + return DormTableDeleteOperator( + dorm: dorm, + operator: TableOperator.delete, + baseConverter: baseConverter, + transaction: transaction, + ); + } +} + +abstract class ColumnMeta {} + +class ColumnInt implements ColumnMeta {} + +class ColumnIntRange implements ColumnMeta {} + +class ColumnFloat implements ColumnMeta {} + +class ColumnBool implements ColumnMeta {} + +class ColumnString implements ColumnMeta { + final dynamic search; + + ColumnString({this.search}); +} + +class ColumnStringEnum implements ColumnMeta {} + +class ColumnStringSet implements ColumnMeta {} + +class ColumnBinary implements ColumnMeta {} + +class ColumnDate implements ColumnMeta {} + +class ColumnDateRange implements ColumnMeta {} + +class ColumnJson implements ColumnMeta {} + +class ColumnComposite implements ColumnMeta {} + +class ColumnGeoJson implements ColumnMeta {} + +class ColumnArray implements ColumnMeta {} + +abstract interface class ColumnCustomDomain implements ColumnMeta {} + +class ColumnCustom implements ColumnMeta { + final String raw; + + ColumnCustom({required this.raw}); +} From 328df7e677c9e4639d1f27addc0214dd63b72c3a Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Wed, 12 Jul 2023 01:58:11 +0600 Subject: [PATCH 04/24] feat(orm): updated api structure --- packages/dartseid_orm/example/api/basic.dart | 21 ++++- packages/dartseid_orm/lib/src/adapter.dart | 88 +++++++++++--------- packages/dartseid_orm/lib/src/core.dart | 4 +- packages/dartseid_orm/lib/src/query.dart | 2 + packages/dartseid_orm/lib/src/table.dart | 40 +++++---- packages/dartseid_orm/pubspec.yaml | 1 + 6 files changed, 95 insertions(+), 61 deletions(-) diff --git a/packages/dartseid_orm/example/api/basic.dart b/packages/dartseid_orm/example/api/basic.dart index 246c0a9..ccdd4ae 100644 --- a/packages/dartseid_orm/example/api/basic.dart +++ b/packages/dartseid_orm/example/api/basic.dart @@ -1,11 +1,14 @@ import 'package:dartseid_orm/dartseid_orm.dart'; class DormMockAdapter implements DormAdapterBase { - final dynamic _connection; + @override + late Dorm dorm; + @override + final dynamic connection; DormMockAdapter({ - required dynamic connection, - }) : _connection = connection; + required this.connection, + }); @override Future init() { @@ -39,6 +42,11 @@ class DormMockAdapter implements DormAdapterBase { // TODO: implement transaction throw UnimplementedError(); } + + @override + void setDormInstance(Dorm dorm) { + this.dorm = dorm; + } } Future dorming() async { @@ -49,8 +57,9 @@ Future dorming() async { final t = a.table( "users", { - "id": ColumnInt(), + "id": ColumnInt()..nullable(), "name": ColumnString(), + "json": ColumnJson(), }, converter: ( fromJson: (Map j) {}, @@ -68,6 +77,7 @@ Future dorming() async { final data = await t.transaction().start( (trx) async { final r = t.findOne(transaction: trx) + ..where({"id": eq(10)}) ..where( and([ { @@ -104,6 +114,9 @@ Future dorming() async { ]), joinType: JoinOperation.left, ) + ..group("id") + ..sort({"name": 1}) + ..having(and([])) ..limit(10) ..skip(0); diff --git a/packages/dartseid_orm/lib/src/adapter.dart b/packages/dartseid_orm/lib/src/adapter.dart index 65952ec..c3a646f 100644 --- a/packages/dartseid_orm/lib/src/adapter.dart +++ b/packages/dartseid_orm/lib/src/adapter.dart @@ -2,13 +2,17 @@ import 'dart:async'; import 'package:dartseid_orm/src/core.dart'; import 'package:dartseid_orm/src/query.dart'; +import 'package:meta/meta.dart'; abstract interface class DormAdapterBase { - final dynamic _connection; + @protected + final dynamic connection; + @protected + late Dorm dorm; DormAdapterBase({ - required dynamic connection, - }) : _connection = connection; + required this.connection, + }); Future init(); Future> operate({ @@ -28,6 +32,9 @@ abstract interface class DormAdapterBase { int? limit, int? skip, }); + + void setDormInstance(Dorm dorm); + DormTransaction transaction(); } @@ -37,47 +44,13 @@ abstract class DormTransaction { bool isRolledBack = false; Future commit() async { - if (!isStarted) { - throw DormException( - message: "Cannot Commit a transaction that has not been started", - originalError: null, - ); - } - if (isCommitted) { - throw DormException( - message: "Cannot Commit a transaction that is already committed", - originalError: null, - ); - } - if (isRolledBack) { - throw DormException( - message: "Cannot Commit a transaction that has been rolled back", - originalError: null, - ); - } + _checkPrecondition("Commit"); await _commit(); isCommitted = true; } Future rollback() async { - if (!isStarted) { - throw DormException( - message: "Cannot Rollback a transaction that has not been started", - originalError: null, - ); - } - if (isCommitted) { - throw DormException( - message: "Cannot Rollback a transaction that is already committed", - originalError: null, - ); - } - if (isRolledBack) { - throw DormException( - message: "Cannot Rollback a transaction that is already rolled back", - originalError: null, - ); - } + _checkPrecondition("Rollback"); await _rollback(); isRolledBack = true; } @@ -86,6 +59,7 @@ abstract class DormTransaction { FutureOr Function(DormTransaction trx)? callback, ]) async { try { + _checkStartPreCondition(); await _start(); isStarted = true; if (callback == null) { @@ -107,4 +81,40 @@ abstract class DormTransaction { Future _rollback(); Future _start(); + + void _checkStartPreCondition() { + if (isCommitted) { + throw DormException( + message: "Cannot Start a transaction that is already committed", + originalError: null, + ); + } + if (isRolledBack) { + throw DormException( + message: "Cannot Start a transaction that is already rolled back", + originalError: null, + ); + } + } + + void _checkPrecondition(String op) { + if (!isStarted) { + throw DormException( + message: "Cannot $op a transaction that has not been started", + originalError: null, + ); + } + if (isCommitted) { + throw DormException( + message: "Cannot $op a transaction that is already committed", + originalError: null, + ); + } + if (isRolledBack) { + throw DormException( + message: "Cannot $op a transaction that has been rolled back", + originalError: null, + ); + } + } } diff --git a/packages/dartseid_orm/lib/src/core.dart b/packages/dartseid_orm/lib/src/core.dart index cf3145a..a2cda45 100644 --- a/packages/dartseid_orm/lib/src/core.dart +++ b/packages/dartseid_orm/lib/src/core.dart @@ -33,7 +33,9 @@ class Dorm with DormTable { String? name, }) async { await adapter.init(); - return Dorm._(adapter: adapter, name: name); + final dorm = Dorm._(adapter: adapter, name: name); + adapter.setDormInstance(dorm); + return dorm; } } diff --git a/packages/dartseid_orm/lib/src/query.dart b/packages/dartseid_orm/lib/src/query.dart index 1037d58..e1ed8c9 100644 --- a/packages/dartseid_orm/lib/src/query.dart +++ b/packages/dartseid_orm/lib/src/query.dart @@ -9,6 +9,7 @@ Map and(List> value) { for (final element in value) { element.forEach((key, _) { element[key]?.isAnd = true; + element[key]?.isOr = false; }); mergedMap.addAll(element); } @@ -20,6 +21,7 @@ Map or(List> value) { for (final element in value) { element.forEach((key, _) { element[key]?.isOr = true; + element[key]?.isAnd = false; }); mergedMap.addAll(element); } diff --git a/packages/dartseid_orm/lib/src/table.dart b/packages/dartseid_orm/lib/src/table.dart index fe9933b..97732be 100644 --- a/packages/dartseid_orm/lib/src/table.dart +++ b/packages/dartseid_orm/lib/src/table.dart @@ -122,43 +122,49 @@ class DormTableSchema { } } -abstract class ColumnMeta {} +class ColumnMeta { + void nullable() { + // do something + } +} -class ColumnInt implements ColumnMeta {} +class ColumnInt extends ColumnMeta {} -class ColumnIntRange implements ColumnMeta {} +class ColumnIntRange extends ColumnMeta {} -class ColumnFloat implements ColumnMeta {} +class ColumnFloat extends ColumnMeta {} -class ColumnBool implements ColumnMeta {} +class ColumnBool extends ColumnMeta {} -class ColumnString implements ColumnMeta { +class ColumnString extends ColumnMeta { final dynamic search; ColumnString({this.search}); } -class ColumnStringEnum implements ColumnMeta {} +class ColumnStringEnum extends ColumnMeta {} + +class ColumnStringSet extends ColumnMeta {} -class ColumnStringSet implements ColumnMeta {} +class ColumnBinary extends ColumnMeta {} -class ColumnBinary implements ColumnMeta {} +class ColumnDate extends ColumnMeta {} -class ColumnDate implements ColumnMeta {} +class ColumnDateRange extends ColumnMeta {} -class ColumnDateRange implements ColumnMeta {} +class ColumnJson extends ColumnMeta {} -class ColumnJson implements ColumnMeta {} +class ColumnComposite extends ColumnMeta {} -class ColumnComposite implements ColumnMeta {} +class ColumnGeoJson extends ColumnMeta {} -class ColumnGeoJson implements ColumnMeta {} +class ColumnObjectId extends ColumnMeta {} -class ColumnArray implements ColumnMeta {} +class ColumnArray extends ColumnMeta {} -abstract interface class ColumnCustomDomain implements ColumnMeta {} +abstract interface class ColumnCustomDomain extends ColumnMeta {} -class ColumnCustom implements ColumnMeta { +class ColumnCustom extends ColumnMeta { final String raw; ColumnCustom({required this.raw}); diff --git a/packages/dartseid_orm/pubspec.yaml b/packages/dartseid_orm/pubspec.yaml index eee0472..91dc794 100644 --- a/packages/dartseid_orm/pubspec.yaml +++ b/packages/dartseid_orm/pubspec.yaml @@ -8,6 +8,7 @@ environment: # Add regular dependencies here. dependencies: + meta: ^1.9.1 # path: ^1.8.0 dev_dependencies: From e956febd70bb138317c2e8850ec7b37b44eaeb73 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Wed, 12 Jul 2023 03:01:21 +0600 Subject: [PATCH 05/24] feat(orm): updated where api to take into account and and or --- packages/dartseid_orm/example/api/basic.dart | 4 + packages/dartseid_orm/lib/src/query.dart | 423 +++++++++++-------- 2 files changed, 251 insertions(+), 176 deletions(-) diff --git a/packages/dartseid_orm/example/api/basic.dart b/packages/dartseid_orm/example/api/basic.dart index ccdd4ae..010100d 100644 --- a/packages/dartseid_orm/example/api/basic.dart +++ b/packages/dartseid_orm/example/api/basic.dart @@ -77,6 +77,9 @@ Future dorming() async { final data = await t.transaction().start( (trx) async { final r = t.findOne(transaction: trx) + ..where({ + "id": array([1, 2, 4]) + }) ..where({"id": eq(10)}) ..where( and([ @@ -102,6 +105,7 @@ Future dorming() async { "avg": avg("name"), "count": count("name"), "countD": count("DISTINCT(name)"), + "countD2": countDistinct("name"), "x": distinct("name"), "max": max("name"), }) diff --git a/packages/dartseid_orm/lib/src/query.dart b/packages/dartseid_orm/lib/src/query.dart index e1ed8c9..18562f8 100644 --- a/packages/dartseid_orm/lib/src/query.dart +++ b/packages/dartseid_orm/lib/src/query.dart @@ -4,153 +4,180 @@ import 'package:dartseid_orm/src/adapter.dart'; import 'package:dartseid_orm/src/core.dart'; import 'package:dartseid_orm/src/table.dart'; -Map and(List> value) { - final Map mergedMap = {}; +const dAnd = r'$__AND'; +const dOr = r'$__OR'; + +Map and(List> value) { + final List> whereParamList = []; for (final element in value) { element.forEach((key, _) { - element[key]?.isAnd = true; - element[key]?.isOr = false; + if (element[key] != null) { + element[key]!.param.isAnd = true; + element[key]!.param.isOr = false; + whereParamList.add({key: element[key]!.param}); + } }); - mergedMap.addAll(element); } - return mergedMap; + return {dAnd: MultipleWhereParam(whereParamList)}; } -Map or(List> value) { - final Map mergedMap = {}; +Map or(List> value) { + final List> whereParamList = []; for (final element in value) { element.forEach((key, _) { - element[key]?.isOr = true; - element[key]?.isAnd = false; + if (element[key] != null) { + element[key]!.param.isAnd = false; + element[key]!.param.isOr = true; + whereParamList.add({key: element[key]!.param}); + } }); - mergedMap.addAll(element); } - return mergedMap; + return {dOr: MultipleWhereParam(whereParamList)}; } -WhereParam array(T value) { - return WhereParam( - operator: WhereOperator.array, - value: value, +SingleWhereParam array(T value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.array, + value: value, + ), ); } -SelectParam avg(String value) { - return SelectParam( - operator: SelectAggregationOperator.avg, - fieldAs: value, +SingleWhereParam between(T start, T end) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.between, + start: start, + end: end, + ), ); } -WhereParam between(T start, T end) { - return WhereParam( - operator: WhereOperator.between, - start: start, - end: end, +SingleWhereParam eq(T value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.eq, + value: value, + ), ); } -SelectParam count(String value) { - return SelectParam( - operator: SelectAggregationOperator.count, - fieldAs: value, +SingleWhereParam gt(T value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.gt, + value: value, + ), ); } -SelectParam countDistinct(String value) { - return SelectParam( - operator: SelectAggregationOperator.countDistinct, - fieldAs: value, +SingleWhereParam gte(T value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.gte, + value: value, + ), ); } -SelectParam distinct(String value) { - return SelectParam( - operator: SelectAggregationOperator.distinct, - fieldAs: value, +SingleWhereParam like(String value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.like, + value: value, + ), ); } -WhereParam eq(T value) { - return WhereParam( - operator: WhereOperator.eq, - value: value, +SingleWhereParam lt(T value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.lt, + value: value, + ), ); } -SelectParam field(String value) { - return SelectParam( - operator: SelectAggregationOperator.show, - fieldAs: value, +SingleWhereParam lte(T value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.lte, + value: value, + ), ); } -WhereParam gt(T value) { - return WhereParam( - operator: WhereOperator.gt, - value: value, +SingleWhereParam notInArray(T value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.notInArray, + value: value, + ), ); } -WhereParam gte(T value) { - return WhereParam( - operator: WhereOperator.gte, - value: value, +SingleWhereParam notEq(T value) { + return SingleWhereParam( + WhereParam( + operator: WhereOperator.notEq, + value: value, + ), ); } -SelectParam hide() { +SelectParam avg(String value) { return SelectParam( - operator: SelectAggregationOperator.hide, + operator: SelectAggregationOperator.avg, + fieldAs: value, ); } -WhereParam like(String value) { - return WhereParam( - operator: WhereOperator.like, - value: value, +SelectParam count(String value) { + return SelectParam( + operator: SelectAggregationOperator.count, + fieldAs: value, ); } -WhereParam lt(T value) { - return WhereParam( - operator: WhereOperator.lt, - value: value, +SelectParam countDistinct(String value) { + return SelectParam( + operator: SelectAggregationOperator.countDistinct, + fieldAs: value, ); } -WhereParam lte(T value) { - return WhereParam( - operator: WhereOperator.lte, - value: value, +SelectParam distinct(String value) { + return SelectParam( + operator: SelectAggregationOperator.distinct, + fieldAs: value, ); } -SelectParam max(String value) { +SelectParam field(String value) { return SelectParam( - operator: SelectAggregationOperator.max, + operator: SelectAggregationOperator.show, fieldAs: value, ); } -SelectParam min(String value) { +SelectParam hide() { return SelectParam( - operator: SelectAggregationOperator.min, - fieldAs: value, + operator: SelectAggregationOperator.hide, ); } -WhereParam notEq(T value) { - return WhereParam( - operator: WhereOperator.notEq, - value: value, +SelectParam max(String value) { + return SelectParam( + operator: SelectAggregationOperator.max, + fieldAs: value, ); } -WhereParam notInArray(T value) { - return WhereParam( - operator: WhereOperator.notInArray, - value: value, +SelectParam min(String value) { + return SelectParam( + operator: SelectAggregationOperator.min, + fieldAs: value, ); } @@ -167,17 +194,25 @@ SelectParam sum(String value) { ); } -class DormTableCreateOperator { +class DormTableFindOperator { final Dorm _dorm; final TableOperator _operator; final DormTableConverter _baseConverter; final DormTransaction? _transaction; - final List> _createWithParams = []; + final List> _whereParams = []; + final List> _havingParams = []; + final List _includeParams = []; + final List _groupParams = []; + final List> _sortParams = []; + final List> _selectParams = []; + + int? _limit; + int? _skip; bool _isExplain = false; - DormTableCreateOperator({ + DormTableFindOperator({ required Dorm dorm, required TableOperator operator, required ({ @@ -190,10 +225,6 @@ class DormTableCreateOperator { _operator = operator, _dorm = dorm; - void createWith(Map value) { - _createWithParams.add(value); - } - Future exec({ DormTableFromConverter? converter, }) async { @@ -205,7 +236,14 @@ class DormTableCreateOperator { isExplain: _isExplain, operator: _operator, transaction: _transaction, - createWithParams: _createWithParams, + whereParams: _whereParams, + includeParams: _includeParams, + selectParams: _selectParams, + havingParams: _havingParams, + groupParams: _groupParams, + sortParams: _sortParams, + limit: _limit, + skip: _skip, ); final convertedData = await execConverter(data); @@ -223,20 +261,79 @@ class DormTableCreateOperator { void explain() { _isExplain = true; } + + void group(String column) { + _groupParams.add(column); + } + + void having(Map map) { + _whereParams.add(WhereParam.evaluateWhereParams(map)); + } + + void include( + String tableName, { + String? on, + Map? where, + JoinOperation joinType = JoinOperation.inner, + }) { + _includeParams.add( + IncludeParam( + tableName, + on: on, + where: where, + joinType: joinType, + ), + ); + } + + /// Set the number of results to return. Cannot be less than 1. + void limit(int limit) { + if (limit <= 0) { + throw DormException( + message: "limit cannot be less then 1", + originalError: null, + ); + } + _limit = limit; + } + + void select(Map value) { + _selectParams.add(value); + } + + /// Set the number of results skipped. Cannot be less than 0. + void skip(int skip) { + if (skip < 0) { + throw DormException( + message: "skip cannot be less then 0", + originalError: null, + ); + } + _skip = skip; + } + + void sort(Map sortBy) { + final Map sortValue = + sortBy.map((key, value) => MapEntry(key, value > 0 ? 1 : -1)); + _sortParams.add(sortValue); + } + + void where(Map map) { + _whereParams.add(WhereParam.evaluateWhereParams(map)); + } } -class DormTableDeleteOperator { +class DormTableCreateOperator { final Dorm _dorm; final TableOperator _operator; final DormTableConverter _baseConverter; final DormTransaction? _transaction; - final List> _whereParams = []; - final List _includeParams = []; + final List> _createWithParams = []; bool _isExplain = false; - DormTableDeleteOperator({ + DormTableCreateOperator({ required Dorm dorm, required TableOperator operator, required ({ @@ -249,6 +346,10 @@ class DormTableDeleteOperator { _operator = operator, _dorm = dorm; + void createWith(Map value) { + _createWithParams.add(value); + } + Future exec({ DormTableFromConverter? converter, }) async { @@ -260,8 +361,7 @@ class DormTableDeleteOperator { isExplain: _isExplain, operator: _operator, transaction: _transaction, - whereParams: _whereParams, - includeParams: _includeParams, + createWithParams: _createWithParams, ); final convertedData = await execConverter(data); @@ -279,47 +379,20 @@ class DormTableDeleteOperator { void explain() { _isExplain = true; } - - void include( - String tableName, { - String? on, - Map? where, - JoinOperation joinType = JoinOperation.inner, - }) { - _includeParams.add( - IncludeParam( - tableName, - on: on, - where: where, - joinType: joinType, - ), - ); - } - - void where(Map value) { - _whereParams.add(value); - } } -class DormTableFindOperator { +class DormTableDeleteOperator { final Dorm _dorm; final TableOperator _operator; final DormTableConverter _baseConverter; final DormTransaction? _transaction; final List> _whereParams = []; - final List> _havingParams = []; final List _includeParams = []; - final List _groupParams = []; - final List> _sortParams = []; - final List> _selectParams = []; - - int? _limit; - int? _skip; bool _isExplain = false; - DormTableFindOperator({ + DormTableDeleteOperator({ required Dorm dorm, required TableOperator operator, required ({ @@ -345,12 +418,6 @@ class DormTableFindOperator { transaction: _transaction, whereParams: _whereParams, includeParams: _includeParams, - selectParams: _selectParams, - havingParams: _havingParams, - groupParams: _groupParams, - sortParams: _sortParams, - limit: _limit, - skip: _skip, ); final convertedData = await execConverter(data); @@ -369,18 +436,10 @@ class DormTableFindOperator { _isExplain = true; } - void group(String column) { - _groupParams.add(column); - } - - void having(Map value) { - _havingParams.add(value); - } - void include( String tableName, { String? on, - Map? where, + Map? where, JoinOperation joinType = JoinOperation.inner, }) { _includeParams.add( @@ -393,40 +452,8 @@ class DormTableFindOperator { ); } - /// Set the number of results to return. Cannot be less than 1. - void limit(int limit) { - if (limit <= 0) { - throw DormException( - message: "limit cannot be less then 1", - originalError: null, - ); - } - _limit = limit; - } - - void select(Map value) { - _selectParams.add(value); - } - - /// Set the number of results skipped. Cannot be less than 0. - void skip(int skip) { - if (skip < 0) { - throw DormException( - message: "skip cannot be less then 0", - originalError: null, - ); - } - _skip = skip; - } - - void sort(Map sortBy) { - final Map sortValue = - sortBy.map((key, value) => MapEntry(key, value > 0 ? 1 : -1)); - _sortParams.add(sortValue); - } - - void where(Map value) { - _whereParams.add(value); + void where(Map map) { + _whereParams.add(WhereParam.evaluateWhereParams(map)); } } @@ -555,8 +582,8 @@ class DormTableUpdateOperator { _updateWithParams.add(value); } - void where(Map value) { - _whereParams.add(value); + void where(Map map) { + _whereParams.add(WhereParam.evaluateWhereParams(map)); } } @@ -582,9 +609,15 @@ class IncludeParam { IncludeParam( this.tableName, { this.on, - this.where, this.joinType = JoinOperation.inner, - }); + Map? where, + }) { + Map? value; + if (where != null) { + value = WhereParam.evaluateWhereParams(where); + } + this.where = value; + } } enum JoinOperation { @@ -641,6 +674,20 @@ enum WhereOperator { or, } +sealed class WhereParamBuilder {} + +class SingleWhereParam extends WhereParamBuilder { + final WhereParam param; + + SingleWhereParam(this.param); +} + +class MultipleWhereParam extends WhereParamBuilder { + final List> param; + + MultipleWhereParam(this.param); +} + class WhereParam { final WhereOperator operator; final T? value; @@ -655,4 +702,28 @@ class WhereParam { this.start, this.end, }); + + static Map evaluateWhereParams( + Map map, + ) { + Map value = {}; + + if (map.containsKey(dAnd)) { + final multiple = map[dAnd]! as MultipleWhereParam; + for (final element in multiple.param) { + value = element; + } + } else if (map.containsKey(dOr)) { + final multiple = map[dOr]! as MultipleWhereParam; + for (final element in multiple.param) { + value = element; + } + } else { + value = map.map( + (key, v) => MapEntry(key, (v as SingleWhereParam).param), + ); + } + + return value; + } } From 8123b46fbb65e11226a7293d47bf5c19677032c0 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Wed, 20 Dec 2023 03:52:43 +0600 Subject: [PATCH 06/24] rebase --- .nvim.lua | 2 + melos.yaml | 3 + melos_arcade.iml | 2 +- packages/arcade_cache/lib/arcade_cache.dart | 1 + .../{dartseid_orm => arcade_orm}/.gitignore | 2 +- .../{dartseid_orm => arcade_orm}/CHANGELOG.md | 0 .../{dartseid_orm => arcade_orm}/README.md | 0 .../analysis_options.yaml | 0 .../example/api/basic.dart | 22 +-- .../lib/arcade_orm.dart} | 0 .../lib/src/adapter.dart | 29 ++-- packages/arcade_orm/lib/src/core.dart | 46 +++++++ .../lib/src/query.dart | 130 +++++++++--------- .../lib/src/table.dart | 80 ++++++----- .../{dartseid_orm => arcade_orm}/pubspec.yaml | 2 +- packages/arcade_orm/test/arcade_orm_test.dart | 1 + packages/dartseid_orm/lib/src/core.dart | 47 ------- .../dartseid_orm/test/dartseid_orm_test.dart | 16 --- .../dartseid_orm_sqlite_adapter/.gitignore | 9 -- .../dartseid_orm_sqlite_adapter/CHANGELOG.md | 3 - .../dartseid_orm_sqlite_adapter/README.md | 39 ------ .../analysis_options.yaml | 1 - .../lib/dartseid_orm.dart | 1 - .../lib/src/dartseid_orm_base.dart | 1 - .../dartseid_orm_sqlite_adapter/pubspec.yaml | 15 -- .../test/dartseid_orm_test.dart | 16 --- samples/todo_api/package.json | 4 +- 27 files changed, 186 insertions(+), 286 deletions(-) create mode 100644 .nvim.lua rename packages/{dartseid_orm => arcade_orm}/.gitignore (90%) rename packages/{dartseid_orm => arcade_orm}/CHANGELOG.md (100%) rename packages/{dartseid_orm => arcade_orm}/README.md (100%) rename packages/{dartseid_orm => arcade_orm}/analysis_options.yaml (100%) rename packages/{dartseid_orm => arcade_orm}/example/api/basic.dart (88%) rename packages/{dartseid_orm/lib/dartseid_orm.dart => arcade_orm/lib/arcade_orm.dart} (100%) rename packages/{dartseid_orm => arcade_orm}/lib/src/adapter.dart (81%) create mode 100644 packages/arcade_orm/lib/src/core.dart rename packages/{dartseid_orm => arcade_orm}/lib/src/query.dart (84%) rename packages/{dartseid_orm => arcade_orm}/lib/src/table.dart (60%) rename packages/{dartseid_orm => arcade_orm}/pubspec.yaml (93%) create mode 100644 packages/arcade_orm/test/arcade_orm_test.dart delete mode 100644 packages/dartseid_orm/lib/src/core.dart delete mode 100644 packages/dartseid_orm/test/dartseid_orm_test.dart delete mode 100644 packages/dartseid_orm_sqlite_adapter/.gitignore delete mode 100644 packages/dartseid_orm_sqlite_adapter/CHANGELOG.md delete mode 100644 packages/dartseid_orm_sqlite_adapter/README.md delete mode 100644 packages/dartseid_orm_sqlite_adapter/analysis_options.yaml delete mode 100644 packages/dartseid_orm_sqlite_adapter/lib/dartseid_orm.dart delete mode 100644 packages/dartseid_orm_sqlite_adapter/lib/src/dartseid_orm_base.dart delete mode 100644 packages/dartseid_orm_sqlite_adapter/pubspec.yaml delete mode 100644 packages/dartseid_orm_sqlite_adapter/test/dartseid_orm_test.dart diff --git a/.nvim.lua b/.nvim.lua new file mode 100644 index 0000000..ebe4aff --- /dev/null +++ b/.nvim.lua @@ -0,0 +1,2 @@ +vim.opt.tabstop = 2 +vim.opt.shiftwidth = 2 diff --git a/melos.yaml b/melos.yaml index a127d57..3c5596a 100644 --- a/melos.yaml +++ b/melos.yaml @@ -7,4 +7,7 @@ packages: scripts: analyze: run: dart analyze + + format: + exec: dart format lib diff --git a/melos_arcade.iml b/melos_arcade.iml index 12c768b..ff58f05 100644 --- a/melos_arcade.iml +++ b/melos_arcade.iml @@ -21,4 +21,4 @@ - \ No newline at end of file + diff --git a/packages/arcade_cache/lib/arcade_cache.dart b/packages/arcade_cache/lib/arcade_cache.dart index e69de29..8b13789 100644 --- a/packages/arcade_cache/lib/arcade_cache.dart +++ b/packages/arcade_cache/lib/arcade_cache.dart @@ -0,0 +1 @@ + diff --git a/packages/dartseid_orm/.gitignore b/packages/arcade_orm/.gitignore similarity index 90% rename from packages/dartseid_orm/.gitignore rename to packages/arcade_orm/.gitignore index cd66d81..ad54996 100644 --- a/packages/dartseid_orm/.gitignore +++ b/packages/arcade_orm/.gitignore @@ -6,4 +6,4 @@ # https://dart.dev/guides/libraries/private-files#pubspeclock. pubspec.lock -melos_dartseid_orm.iml +melos_arcade_orm.iml diff --git a/packages/dartseid_orm/CHANGELOG.md b/packages/arcade_orm/CHANGELOG.md similarity index 100% rename from packages/dartseid_orm/CHANGELOG.md rename to packages/arcade_orm/CHANGELOG.md diff --git a/packages/dartseid_orm/README.md b/packages/arcade_orm/README.md similarity index 100% rename from packages/dartseid_orm/README.md rename to packages/arcade_orm/README.md diff --git a/packages/dartseid_orm/analysis_options.yaml b/packages/arcade_orm/analysis_options.yaml similarity index 100% rename from packages/dartseid_orm/analysis_options.yaml rename to packages/arcade_orm/analysis_options.yaml diff --git a/packages/dartseid_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart similarity index 88% rename from packages/dartseid_orm/example/api/basic.dart rename to packages/arcade_orm/example/api/basic.dart index 010100d..a55951e 100644 --- a/packages/dartseid_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -1,12 +1,12 @@ import 'package:dartseid_orm/dartseid_orm.dart'; -class DormMockAdapter implements DormAdapterBase { +class ArcadeOrmMockAdapter implements ArcadeOrmAdapterBase { @override - late Dorm dorm; + late ArcadeOrm orm; @override final dynamic connection; - DormMockAdapter({ + ArcadeOrmMockAdapter({ required this.connection, }); @@ -19,7 +19,7 @@ class DormMockAdapter implements DormAdapterBase { @override Future> operate({ required TableOperator operator, - required DormTransaction? transaction, + required ArcadeOrmTransaction? transaction, required bool isExplain, String? rawSql, Map? rawNoSql, @@ -38,20 +38,20 @@ class DormMockAdapter implements DormAdapterBase { } @override - DormTransaction transaction() { + ArcadeOrmTransaction transaction() { // TODO: implement transaction throw UnimplementedError(); } @override - void setDormInstance(Dorm dorm) { - this.dorm = dorm; + void setArcadeOrmInstance(ArcadeOrm orm) { + this.orm = orm; } } -Future dorming() async { - final a = await Dorm.init( - adapter: DormMockAdapter(connection: ""), +Future orming() async { + final a = await ArcadeOrm.init( + adapter: ArcadeOrmMockAdapter(connection: ""), ); final t = a.table( @@ -139,6 +139,6 @@ Future dorming() async { }, ); - // more dorming + // more orming return data; } diff --git a/packages/dartseid_orm/lib/dartseid_orm.dart b/packages/arcade_orm/lib/arcade_orm.dart similarity index 100% rename from packages/dartseid_orm/lib/dartseid_orm.dart rename to packages/arcade_orm/lib/arcade_orm.dart diff --git a/packages/dartseid_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart similarity index 81% rename from packages/dartseid_orm/lib/src/adapter.dart rename to packages/arcade_orm/lib/src/adapter.dart index c3a646f..c43dde8 100644 --- a/packages/dartseid_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -1,23 +1,22 @@ import 'dart:async'; -import 'package:dartseid_orm/src/core.dart'; -import 'package:dartseid_orm/src/query.dart'; +import 'package:arcade_orm/arcade_orm.dart'; import 'package:meta/meta.dart'; -abstract interface class DormAdapterBase { +abstract interface class ArcadeOrmAdapterBase { @protected final dynamic connection; @protected - late Dorm dorm; + late ArcadeOrm orm; - DormAdapterBase({ + ArcadeOrmAdapterBase({ required this.connection, }); Future init(); Future> operate({ required TableOperator operator, - required DormTransaction? transaction, + required ArcadeOrmTransaction? transaction, required bool isExplain, String? rawSql, Map? rawNoSql, @@ -33,12 +32,12 @@ abstract interface class DormAdapterBase { int? skip, }); - void setDormInstance(Dorm dorm); + void setArcadeOrmInstance(ArcadeOrm orm); - DormTransaction transaction(); + ArcadeOrmTransaction transaction(); } -abstract class DormTransaction { +abstract class ArcadeOrmTransaction { bool isStarted = false; bool isCommitted = false; bool isRolledBack = false; @@ -56,7 +55,7 @@ abstract class DormTransaction { } Future start([ - FutureOr Function(DormTransaction trx)? callback, + FutureOr Function(ArcadeOrmTransaction trx)? callback, ]) async { try { _checkStartPreCondition(); @@ -84,13 +83,13 @@ abstract class DormTransaction { void _checkStartPreCondition() { if (isCommitted) { - throw DormException( + throw ArcadeOrmException( message: "Cannot Start a transaction that is already committed", originalError: null, ); } if (isRolledBack) { - throw DormException( + throw ArcadeOrmException( message: "Cannot Start a transaction that is already rolled back", originalError: null, ); @@ -99,19 +98,19 @@ abstract class DormTransaction { void _checkPrecondition(String op) { if (!isStarted) { - throw DormException( + throw ArcadeOrmException( message: "Cannot $op a transaction that has not been started", originalError: null, ); } if (isCommitted) { - throw DormException( + throw ArcadeOrmException( message: "Cannot $op a transaction that is already committed", originalError: null, ); } if (isRolledBack) { - throw DormException( + throw ArcadeOrmException( message: "Cannot $op a transaction that has been rolled back", originalError: null, ); diff --git a/packages/arcade_orm/lib/src/core.dart b/packages/arcade_orm/lib/src/core.dart new file mode 100644 index 0000000..cb1c78e --- /dev/null +++ b/packages/arcade_orm/lib/src/core.dart @@ -0,0 +1,46 @@ +import 'dart:async'; + +import 'package:arcade_orm/arcade_orm.dart'; + +// This will be initialized with dart orm class after init method is called +final Map _orms = {}; + +ArcadeOrm getArcadeOrmInstance([String? name]) { + final orm = _orms[name ?? "__default"]; + if (orm == null) { + throw StateError( + 'Dartseid orm is not initialized. Please run ArcadeOrm.init', + ); + } + return orm; +} + +class ArcadeOrm with ArcadeOrmTable { + final ArcadeOrmAdapterBase adapter; + + ArcadeOrm._({required this.adapter, String? name}) { + this.name = name ?? "__default"; + _orms[this.name] = this; + } + + ArcadeOrmTransaction transaction() { + return adapter.transaction(); + } + + static Future init({ + required ArcadeOrmAdapterBase adapter, + String? name, + }) async { + await adapter.init(); + final orm = ArcadeOrm._(adapter: adapter, name: name); + adapter.setArcadeOrmInstance(orm); + return orm; + } +} + +class ArcadeOrmException implements Exception { + final Object? originalError; + final String message; + + ArcadeOrmException({required this.message, required this.originalError}); +} diff --git a/packages/dartseid_orm/lib/src/query.dart b/packages/arcade_orm/lib/src/query.dart similarity index 84% rename from packages/dartseid_orm/lib/src/query.dart rename to packages/arcade_orm/lib/src/query.dart index 18562f8..63f688d 100644 --- a/packages/dartseid_orm/lib/src/query.dart +++ b/packages/arcade_orm/lib/src/query.dart @@ -1,8 +1,6 @@ import 'dart:async'; -import 'package:dartseid_orm/src/adapter.dart'; -import 'package:dartseid_orm/src/core.dart'; -import 'package:dartseid_orm/src/table.dart'; +import 'package:arcade_orm/arcade_orm.dart'; const dAnd = r'$__AND'; const dOr = r'$__OR'; @@ -194,11 +192,11 @@ SelectParam sum(String value) { ); } -class DormTableFindOperator { - final Dorm _dorm; +class ArcadeOrmTableFindOperator { + final ArcadeOrm _orm; final TableOperator _operator; - final DormTableConverter _baseConverter; - final DormTransaction? _transaction; + final ArcadeOrmTableConverter _baseConverter; + final ArcadeOrmTransaction? _transaction; final List> _whereParams = []; final List> _havingParams = []; @@ -212,27 +210,27 @@ class DormTableFindOperator { bool _isExplain = false; - DormTableFindOperator({ - required Dorm dorm, + ArcadeOrmTableFindOperator({ + required ArcadeOrm orm, required TableOperator operator, required ({ FutureOr Function(Map) fromJson, FutureOr> Function() toJson }) baseConverter, - DormTransaction? transaction, + ArcadeOrmTransaction? transaction, }) : _transaction = transaction, _baseConverter = baseConverter, _operator = operator, - _dorm = dorm; + _orm = orm; Future exec({ - DormTableFromConverter? converter, + ArcadeOrmTableFromConverter? converter, }) async { try { final execConverter = converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _dorm.adapter.operate( + final data = await _orm.adapter.operate( isExplain: _isExplain, operator: _operator, transaction: _transaction, @@ -249,11 +247,11 @@ class DormTableFindOperator { final convertedData = await execConverter(data); return ExecResultData(convertedData); - } on DormException catch (e) { + } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { return ExecResultFailure( - DormException(originalError: e, message: "Unknown Error"), + ArcadeOrmException(originalError: e, message: "Unknown Error"), ); } } @@ -289,7 +287,7 @@ class DormTableFindOperator { /// Set the number of results to return. Cannot be less than 1. void limit(int limit) { if (limit <= 0) { - throw DormException( + throw ArcadeOrmException( message: "limit cannot be less then 1", originalError: null, ); @@ -304,7 +302,7 @@ class DormTableFindOperator { /// Set the number of results skipped. Cannot be less than 0. void skip(int skip) { if (skip < 0) { - throw DormException( + throw ArcadeOrmException( message: "skip cannot be less then 0", originalError: null, ); @@ -323,41 +321,41 @@ class DormTableFindOperator { } } -class DormTableCreateOperator { - final Dorm _dorm; +class ArcadeOrmTableCreateOperator { + final ArcadeOrm _orm; final TableOperator _operator; - final DormTableConverter _baseConverter; - final DormTransaction? _transaction; + final ArcadeOrmTableConverter _baseConverter; + final ArcadeOrmTransaction? _transaction; final List> _createWithParams = []; bool _isExplain = false; - DormTableCreateOperator({ - required Dorm dorm, + ArcadeOrmTableCreateOperator({ + required ArcadeOrm orm, required TableOperator operator, required ({ FutureOr Function(Map) fromJson, FutureOr> Function() toJson }) baseConverter, - DormTransaction? transaction, + ArcadeOrmTransaction? transaction, }) : _transaction = transaction, _baseConverter = baseConverter, _operator = operator, - _dorm = dorm; + _orm = orm; void createWith(Map value) { _createWithParams.add(value); } Future exec({ - DormTableFromConverter? converter, + ArcadeOrmTableFromConverter? converter, }) async { try { final execConverter = converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _dorm.adapter.operate( + final data = await _orm.adapter.operate( isExplain: _isExplain, operator: _operator, transaction: _transaction, @@ -367,11 +365,11 @@ class DormTableCreateOperator { final convertedData = await execConverter(data); return ExecResultData(convertedData); - } on DormException catch (e) { + } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { return ExecResultFailure( - DormException(originalError: e, message: "Unknown Error"), + ArcadeOrmException(originalError: e, message: "Unknown Error"), ); } } @@ -381,38 +379,38 @@ class DormTableCreateOperator { } } -class DormTableDeleteOperator { - final Dorm _dorm; +class ArcadeOrmTableDeleteOperator { + final ArcadeOrm _orm; final TableOperator _operator; - final DormTableConverter _baseConverter; - final DormTransaction? _transaction; + final ArcadeOrmTableConverter _baseConverter; + final ArcadeOrmTransaction? _transaction; final List> _whereParams = []; final List _includeParams = []; bool _isExplain = false; - DormTableDeleteOperator({ - required Dorm dorm, + ArcadeOrmTableDeleteOperator({ + required ArcadeOrm orm, required TableOperator operator, required ({ FutureOr Function(Map) fromJson, FutureOr> Function() toJson }) baseConverter, - DormTransaction? transaction, + ArcadeOrmTransaction? transaction, }) : _transaction = transaction, _baseConverter = baseConverter, _operator = operator, - _dorm = dorm; + _orm = orm; Future exec({ - DormTableFromConverter? converter, + ArcadeOrmTableFromConverter? converter, }) async { try { final execConverter = converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _dorm.adapter.operate( + final data = await _orm.adapter.operate( isExplain: _isExplain, operator: _operator, transaction: _transaction, @@ -423,11 +421,11 @@ class DormTableDeleteOperator { final convertedData = await execConverter(data); return ExecResultData(convertedData); - } on DormException catch (e) { + } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { return ExecResultFailure( - DormException(originalError: e, message: "Unknown Error"), + ArcadeOrmException(originalError: e, message: "Unknown Error"), ); } } @@ -457,38 +455,38 @@ class DormTableDeleteOperator { } } -class DormTableRawOperator { - final Dorm _dorm; +class ArcadeOrmTableRawOperator { + final ArcadeOrm _orm; final TableOperator _operator; - final DormTableConverter _baseConverter; - final DormTransaction? _transaction; + final ArcadeOrmTableConverter _baseConverter; + final ArcadeOrmTransaction? _transaction; bool _isExplain = false; String? _rawSql; Map? _rawNoSql; - DormTableRawOperator({ - required Dorm dorm, + ArcadeOrmTableRawOperator({ + required ArcadeOrm orm, required TableOperator operator, required ({ FutureOr Function(Map) fromJson, FutureOr> Function() toJson }) baseConverter, - DormTransaction? transaction, + ArcadeOrmTransaction? transaction, }) : _transaction = transaction, _baseConverter = baseConverter, _operator = operator, - _dorm = dorm; + _orm = orm; Future exec({ - DormTableFromConverter? converter, + ArcadeOrmTableFromConverter? converter, }) async { try { final execConverter = converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _dorm.adapter.operate( + final data = await _orm.adapter.operate( isExplain: _isExplain, rawSql: _rawSql, rawNoSql: _rawNoSql, @@ -499,11 +497,11 @@ class DormTableRawOperator { final convertedData = await execConverter(data); return ExecResultData(convertedData); - } on DormException catch (e) { + } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { return ExecResultFailure( - DormException(originalError: e, message: "Unknown Error"), + ArcadeOrmException(originalError: e, message: "Unknown Error"), ); } } @@ -523,38 +521,38 @@ class DormTableRawOperator { } } -class DormTableUpdateOperator { - final Dorm _dorm; +class ArcadeOrmTableUpdateOperator { + final ArcadeOrm _orm; final TableOperator _operator; - final DormTableConverter _baseConverter; - final DormTransaction? _transaction; + final ArcadeOrmTableConverter _baseConverter; + final ArcadeOrmTransaction? _transaction; final List> _updateWithParams = []; final List> _whereParams = []; bool _isExplain = false; - DormTableUpdateOperator({ - required Dorm dorm, + ArcadeOrmTableUpdateOperator({ + required ArcadeOrm orm, required TableOperator operator, required ({ FutureOr Function(Map) fromJson, FutureOr> Function() toJson }) baseConverter, - DormTransaction? transaction, + ArcadeOrmTransaction? transaction, }) : _transaction = transaction, _baseConverter = baseConverter, _operator = operator, - _dorm = dorm; + _orm = orm; Future exec({ - DormTableFromConverter? converter, + ArcadeOrmTableFromConverter? converter, }) async { try { final execConverter = converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _dorm.adapter.operate( + final data = await _orm.adapter.operate( isExplain: _isExplain, operator: _operator, transaction: _transaction, @@ -565,11 +563,11 @@ class DormTableUpdateOperator { final convertedData = await execConverter(data); return ExecResultData(convertedData); - } on DormException catch (e) { + } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { return ExecResultFailure( - DormException(originalError: e, message: "Unknown Error"), + ArcadeOrmException(originalError: e, message: "Unknown Error"), ); } } @@ -596,7 +594,7 @@ class ExecResultData extends ExecResult { } class ExecResultFailure extends ExecResult { - final DormException exception; + final ArcadeOrmException exception; ExecResultFailure(this.exception); } diff --git a/packages/dartseid_orm/lib/src/table.dart b/packages/arcade_orm/lib/src/table.dart similarity index 60% rename from packages/dartseid_orm/lib/src/table.dart rename to packages/arcade_orm/lib/src/table.dart index 97732be..31f4226 100644 --- a/packages/dartseid_orm/lib/src/table.dart +++ b/packages/arcade_orm/lib/src/table.dart @@ -1,36 +1,34 @@ import 'dart:async'; -import 'package:dartseid_orm/src/adapter.dart'; -import 'package:dartseid_orm/src/core.dart'; -import 'package:dartseid_orm/src/query.dart'; +import 'package:arcade_orm/arcade_orm.dart'; -typedef DormTableConverter = ({ +typedef ArcadeOrmTableConverter = ({ FutureOr Function(Map json) fromJson, FutureOr> Function() toJson, }); -typedef DormTableFromConverter = ({ +typedef ArcadeOrmTableFromConverter = ({ FutureOr Function(Map json) fromJson, }); -mixin DormTable { +mixin ArcadeOrmTable { late String name; - final List _tables = []; + final List _tables = []; - late final Dorm _dorm = getDormInstance(name); + late final ArcadeOrm _orm = getArcadeOrmInstance(name); - DormTableSchema table( + ArcadeOrmTableSchema table( String name, Map schema, { - required DormTableConverter converter, + required ArcadeOrmTableConverter converter, }) { final schema = - DormTableSchema(dorm: _dorm, name: name, baseConverter: converter); - _dorm._tables.add(schema); + ArcadeOrmTableSchema(orm: _orm, name: name, baseConverter: converter); + _orm._tables.add(schema); return schema; } - DormTableSchema getTable(String name) { + ArcadeOrmTableSchema getTable(String name) { try { return _tables.firstWhere((element) => element.name == name); } catch (e) { @@ -41,80 +39,80 @@ mixin DormTable { } } -class DormTableSchema { - final Dorm dorm; +class ArcadeOrmTableSchema { + final ArcadeOrm orm; final String name; - final DormTableConverter baseConverter; + final ArcadeOrmTableConverter baseConverter; - DormTableSchema({ - required this.dorm, + ArcadeOrmTableSchema({ + required this.orm, required this.name, required this.baseConverter, }); - DormTransaction transaction() { - return dorm.transaction(); + ArcadeOrmTransaction transaction() { + return orm.transaction(); } void index(Map config, {({bool? unique})? options}) {} - DormTableRawOperator raw({DormTransaction? transaction}) { - return DormTableRawOperator( - dorm: dorm, + ArcadeOrmTableRawOperator raw({ArcadeOrmTransaction? transaction}) { + return ArcadeOrmTableRawOperator( + orm: orm, operator: TableOperator.raw, baseConverter: baseConverter, transaction: transaction, ); } - DormTableFindOperator count({DormTransaction? transaction}) { - return DormTableFindOperator( - dorm: dorm, + ArcadeOrmTableFindOperator count({ArcadeOrmTransaction? transaction}) { + return ArcadeOrmTableFindOperator( + orm: orm, operator: TableOperator.count, baseConverter: baseConverter, transaction: transaction, ); } - DormTableFindOperator findOne({DormTransaction? transaction}) { - return DormTableFindOperator( - dorm: dorm, + ArcadeOrmTableFindOperator findOne({ArcadeOrmTransaction? transaction}) { + return ArcadeOrmTableFindOperator( + orm: orm, operator: TableOperator.findOne, baseConverter: baseConverter, transaction: transaction, ); } - DormTableFindOperator findMany({DormTransaction? transaction}) { - return DormTableFindOperator( - dorm: dorm, + ArcadeOrmTableFindOperator findMany({ArcadeOrmTransaction? transaction}) { + return ArcadeOrmTableFindOperator( + orm: orm, operator: TableOperator.findMany, baseConverter: baseConverter, transaction: transaction, ); } - DormTableCreateOperator create({DormTransaction? transaction}) { - return DormTableCreateOperator( - dorm: dorm, + ArcadeOrmTableCreateOperator create({ArcadeOrmTransaction? transaction}) { + return ArcadeOrmTableCreateOperator( + orm: orm, operator: TableOperator.create, baseConverter: baseConverter, transaction: transaction, ); } - DormTableUpdateOperator update({DormTransaction? transaction}) { - return DormTableUpdateOperator( - dorm: dorm, + ArcadeOrmTableUpdateOperator update({ArcadeOrmTransaction? transaction}) { + return ArcadeOrmTableUpdateOperator( + orm: orm, operator: TableOperator.update, baseConverter: baseConverter, transaction: transaction, ); } - DormTableDeleteOperator delete({DormTransaction? transaction}) { - return DormTableDeleteOperator( - dorm: dorm, + ArcadeOrmTableDeleteOperator delete({ArcadeOrmTransaction? transaction}) { + return ArcadeOrmTableDeleteOperator( + orm: orm, operator: TableOperator.delete, baseConverter: baseConverter, transaction: transaction, diff --git a/packages/dartseid_orm/pubspec.yaml b/packages/arcade_orm/pubspec.yaml similarity index 93% rename from packages/dartseid_orm/pubspec.yaml rename to packages/arcade_orm/pubspec.yaml index 91dc794..5c1918c 100644 --- a/packages/dartseid_orm/pubspec.yaml +++ b/packages/arcade_orm/pubspec.yaml @@ -1,4 +1,4 @@ -name: dartseid_orm +name: arcade_orm description: A starting point for Dart libraries or applications. version: 0.0.1 # repository: https://github.com/my_org/my_repo diff --git a/packages/arcade_orm/test/arcade_orm_test.dart b/packages/arcade_orm/test/arcade_orm_test.dart new file mode 100644 index 0000000..ab73b3a --- /dev/null +++ b/packages/arcade_orm/test/arcade_orm_test.dart @@ -0,0 +1 @@ +void main() {} diff --git a/packages/dartseid_orm/lib/src/core.dart b/packages/dartseid_orm/lib/src/core.dart deleted file mode 100644 index a2cda45..0000000 --- a/packages/dartseid_orm/lib/src/core.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'dart:async'; - -import 'package:dartseid_orm/src/adapter.dart'; -import 'package:dartseid_orm/src/table.dart'; - -// This will be initialized with dart orm class after init method is called -final Map _dorms = {}; - -Dorm getDormInstance([String? name]) { - final dorm = _dorms[name ?? "__default"]; - if (dorm == null) { - throw StateError( - 'Dartseid orm is not initialized. Please run Dorm.init', - ); - } - return dorm; -} - -class Dorm with DormTable { - final DormAdapterBase adapter; - - Dorm._({required this.adapter, String? name}) { - this.name = name ?? "__default"; - _dorms[this.name] = this; - } - - DormTransaction transaction() { - return adapter.transaction(); - } - - static Future init({ - required DormAdapterBase adapter, - String? name, - }) async { - await adapter.init(); - final dorm = Dorm._(adapter: adapter, name: name); - adapter.setDormInstance(dorm); - return dorm; - } -} - -class DormException implements Exception { - final Object? originalError; - final String message; - - DormException({required this.message, required this.originalError}); -} diff --git a/packages/dartseid_orm/test/dartseid_orm_test.dart b/packages/dartseid_orm/test/dartseid_orm_test.dart deleted file mode 100644 index aad3e7d..0000000 --- a/packages/dartseid_orm/test/dartseid_orm_test.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:dartseid_orm/dartseid_orm.dart'; -import 'package:test/test.dart'; - -void main() { - group('A group of tests', () { - final awesome = Awesome(); - - setUp(() { - // Additional setup goes here. - }); - - test('First Test', () { - expect(awesome.isAwesome, isTrue); - }); - }); -} diff --git a/packages/dartseid_orm_sqlite_adapter/.gitignore b/packages/dartseid_orm_sqlite_adapter/.gitignore deleted file mode 100644 index 473386d..0000000 --- a/packages/dartseid_orm_sqlite_adapter/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# https://dart.dev/guides/libraries/private-files -# Created by `dart pub` -.dart_tool/ - -# Avoid committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock - -melos_dartseid_orm_sqlite_adapter.iml diff --git a/packages/dartseid_orm_sqlite_adapter/CHANGELOG.md b/packages/dartseid_orm_sqlite_adapter/CHANGELOG.md deleted file mode 100644 index effe43c..0000000 --- a/packages/dartseid_orm_sqlite_adapter/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 1.0.0 - -- Initial version. diff --git a/packages/dartseid_orm_sqlite_adapter/README.md b/packages/dartseid_orm_sqlite_adapter/README.md deleted file mode 100644 index 8b55e73..0000000 --- a/packages/dartseid_orm_sqlite_adapter/README.md +++ /dev/null @@ -1,39 +0,0 @@ - - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. - -## Features - -TODO: List what your package can do. Maybe include images, gifs, or videos. - -## Getting started - -TODO: List prerequisites and provide or point to information on how to -start using the package. - -## Usage - -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. - -```dart -const like = 'sample'; -``` - -## Additional information - -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. diff --git a/packages/dartseid_orm_sqlite_adapter/analysis_options.yaml b/packages/dartseid_orm_sqlite_adapter/analysis_options.yaml deleted file mode 100644 index 55309e9..0000000 --- a/packages/dartseid_orm_sqlite_adapter/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:lint/analysis_options.yaml diff --git a/packages/dartseid_orm_sqlite_adapter/lib/dartseid_orm.dart b/packages/dartseid_orm_sqlite_adapter/lib/dartseid_orm.dart deleted file mode 100644 index cb77ed2..0000000 --- a/packages/dartseid_orm_sqlite_adapter/lib/dartseid_orm.dart +++ /dev/null @@ -1 +0,0 @@ -export 'src/dartseid_orm_base.dart'; diff --git a/packages/dartseid_orm_sqlite_adapter/lib/src/dartseid_orm_base.dart b/packages/dartseid_orm_sqlite_adapter/lib/src/dartseid_orm_base.dart deleted file mode 100644 index 095f0a8..0000000 --- a/packages/dartseid_orm_sqlite_adapter/lib/src/dartseid_orm_base.dart +++ /dev/null @@ -1 +0,0 @@ -class Dorm {} diff --git a/packages/dartseid_orm_sqlite_adapter/pubspec.yaml b/packages/dartseid_orm_sqlite_adapter/pubspec.yaml deleted file mode 100644 index f06e52c..0000000 --- a/packages/dartseid_orm_sqlite_adapter/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: dartseid_orm_sqlite_adapter -description: A starting point for Dart libraries or applications. -version: 0.0.1 -# repository: https://github.com/my_org/my_repo - -environment: - sdk: ^3.0.5 - -# Add regular dependencies here. -dependencies: - dartseid_orm: ^0.0.1 - -dev_dependencies: - lint: ^2.1.2 - test: ^1.21.0 diff --git a/packages/dartseid_orm_sqlite_adapter/test/dartseid_orm_test.dart b/packages/dartseid_orm_sqlite_adapter/test/dartseid_orm_test.dart deleted file mode 100644 index aad3e7d..0000000 --- a/packages/dartseid_orm_sqlite_adapter/test/dartseid_orm_test.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:dartseid_orm/dartseid_orm.dart'; -import 'package:test/test.dart'; - -void main() { - group('A group of tests', () { - final awesome = Awesome(); - - setUp(() { - // Additional setup goes here. - }); - - test('First Test', () { - expect(awesome.isAwesome, isTrue); - }); - }); -} diff --git a/samples/todo_api/package.json b/samples/todo_api/package.json index f334c71..3ecec89 100644 --- a/samples/todo_api/package.json +++ b/samples/todo_api/package.json @@ -2,10 +2,10 @@ "name": "todo_api", "version": "1.0.0", "description": "A TODO API implemented with Dartseid and Prisma", - "homepage": "https://github.com/exaby73/dartsied/tree/main", + "homepage": "https://github.com/dartarcade/arcade/tree/main", "repository": { "type": "git", - "url": "git+https://github.com/exaby73/dartsied.git#main" + "url": "git+https://github.com/dartarcade/arcade.git#main" }, "author": "exaby73", "license": "MIT", From 65005e5d4f6fac1e6ae7a45a466001f97b512d80 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Fri, 17 Nov 2023 18:50:19 +0530 Subject: [PATCH 07/24] feat: added tests for getArcadeOrmInstance --- packages/arcade/.gitignore | 2 +- packages/arcade/melos_arcade.iml | 16 -------- packages/arcade_orm/example/api/basic.dart | 10 ++++- packages/arcade_orm/lib/src/adapter.dart | 4 +- packages/arcade_orm/lib/src/core.dart | 23 +++++++++-- packages/arcade_orm/pubspec.yaml | 1 + packages/arcade_orm/test/arcade_orm_test.dart | 1 - packages/arcade_orm/test/src/core_test.dart | 38 +++++++++++++++++++ 8 files changed, 72 insertions(+), 23 deletions(-) delete mode 100644 packages/arcade/melos_arcade.iml delete mode 100644 packages/arcade_orm/test/arcade_orm_test.dart create mode 100644 packages/arcade_orm/test/src/core_test.dart diff --git a/packages/arcade/.gitignore b/packages/arcade/.gitignore index 4b5a957..344541d 100644 --- a/packages/arcade/.gitignore +++ b/packages/arcade/.gitignore @@ -8,6 +8,6 @@ pubspec.lock .idea/ -melos_dartseid.iml +melos_arcade.iml # Generated files in example example/**/*.g.dart diff --git a/packages/arcade/melos_arcade.iml b/packages/arcade/melos_arcade.iml deleted file mode 100644 index 389d07a..0000000 --- a/packages/arcade/melos_arcade.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index a55951e..9b988f0 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -1,4 +1,6 @@ -import 'package:dartseid_orm/dartseid_orm.dart'; +import 'dart:async'; + +import 'package:arcade_orm/arcade_orm.dart'; class ArcadeOrmMockAdapter implements ArcadeOrmAdapterBase { @override @@ -47,6 +49,12 @@ class ArcadeOrmMockAdapter implements ArcadeOrmAdapterBase { void setArcadeOrmInstance(ArcadeOrm orm) { this.orm = orm; } + + @override + FutureOr close() { + // TODO: implement close + throw UnimplementedError(); + } } Future orming() async { diff --git a/packages/arcade_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart index c43dde8..32186d1 100644 --- a/packages/arcade_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -13,7 +13,7 @@ abstract interface class ArcadeOrmAdapterBase { required this.connection, }); - Future init(); + FutureOr init(); Future> operate({ required TableOperator operator, required ArcadeOrmTransaction? transaction, @@ -35,6 +35,8 @@ abstract interface class ArcadeOrmAdapterBase { void setArcadeOrmInstance(ArcadeOrm orm); ArcadeOrmTransaction transaction(); + + FutureOr close(); } abstract class ArcadeOrmTransaction { diff --git a/packages/arcade_orm/lib/src/core.dart b/packages/arcade_orm/lib/src/core.dart index cb1c78e..f511a7f 100644 --- a/packages/arcade_orm/lib/src/core.dart +++ b/packages/arcade_orm/lib/src/core.dart @@ -1,15 +1,23 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; +import 'package:meta/meta.dart'; + +@visibleForTesting +void clearOrms() { + _orms.clear(); +} // This will be initialized with dart orm class after init method is called final Map _orms = {}; +/// This will return an instance of ArcadeOrm provided `init` was called ArcadeOrm getArcadeOrmInstance([String? name]) { final orm = _orms[name ?? "__default"]; if (orm == null) { throw StateError( - 'Dartseid orm is not initialized. Please run ArcadeOrm.init', + 'Arcade orm is not initialized. ' + 'Please run ArcadeOrm.init(adapter: ExampleAdapter()${name != null ? ', name: "$name"' : ''})', ); } return orm; @@ -20,6 +28,11 @@ class ArcadeOrm with ArcadeOrmTable { ArcadeOrm._({required this.adapter, String? name}) { this.name = name ?? "__default"; + if (_orms.containsKey(this.name)) { + throw StateError( + 'Arcade ORM with name "${this.name}" is already initialized. Please use another name', + ); + } _orms[this.name] = this; } @@ -27,15 +40,19 @@ class ArcadeOrm with ArcadeOrmTable { return adapter.transaction(); } - static Future init({ + static FutureOr init({ required ArcadeOrmAdapterBase adapter, String? name, }) async { - await adapter.init(); final orm = ArcadeOrm._(adapter: adapter, name: name); + await adapter.init(); adapter.setArcadeOrmInstance(orm); return orm; } + + FutureOr close() async { + await adapter.close(); + } } class ArcadeOrmException implements Exception { diff --git a/packages/arcade_orm/pubspec.yaml b/packages/arcade_orm/pubspec.yaml index 5c1918c..2b9930b 100644 --- a/packages/arcade_orm/pubspec.yaml +++ b/packages/arcade_orm/pubspec.yaml @@ -13,4 +13,5 @@ dependencies: dev_dependencies: lint: ^2.1.2 + mocktail: ^1.0.1 test: ^1.21.0 diff --git a/packages/arcade_orm/test/arcade_orm_test.dart b/packages/arcade_orm/test/arcade_orm_test.dart deleted file mode 100644 index ab73b3a..0000000 --- a/packages/arcade_orm/test/arcade_orm_test.dart +++ /dev/null @@ -1 +0,0 @@ -void main() {} diff --git a/packages/arcade_orm/test/src/core_test.dart b/packages/arcade_orm/test/src/core_test.dart new file mode 100644 index 0000000..cb923b5 --- /dev/null +++ b/packages/arcade_orm/test/src/core_test.dart @@ -0,0 +1,38 @@ +import 'package:arcade_orm/arcade_orm.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class MockAdapter extends Mock implements ArcadeOrmAdapterBase {} + +void main() { + group('getArcadeOrmInstance', () { + tearDown(clearOrms); + + test('should throw error if ArcadeOrm is not initialized', () { + expect(() => getArcadeOrmInstance(), throwsStateError); + }); + + test('should return an instance if init() was called', () async { + final arcadeOrm = await ArcadeOrm.init(adapter: MockAdapter()); + expect(getArcadeOrmInstance(), arcadeOrm); + }); + + test('should return the correct instance if name is provided', () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: MockAdapter(), + name: 'test', + ); + expect(getArcadeOrmInstance('test'), arcadeOrm); + }); + + test('should return correct instance if multiple ORMs exist', () async { + final defaultArcadeOrm = await ArcadeOrm.init(adapter: MockAdapter()); + final namedArcadeOrm = await ArcadeOrm.init( + adapter: MockAdapter(), + name: 'test', + ); + expect(getArcadeOrmInstance(), defaultArcadeOrm); + expect(getArcadeOrmInstance('test'), namedArcadeOrm); + }); + }); +} From 08418cacf382c4d99d3c472c06736fbb7d052d34 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Tue, 21 Nov 2023 15:59:09 +0600 Subject: [PATCH 08/24] feat: updated api for converters and adapter --- .gitignore | 1 + packages/arcade_orm/example/api/basic.dart | 30 +++++---- packages/arcade_orm/lib/src/adapter.dart | 31 +++++---- packages/arcade_orm/lib/src/query.dart | 75 +++++----------------- packages/arcade_orm/lib/src/table.dart | 24 ++----- 5 files changed, 56 insertions(+), 105 deletions(-) diff --git a/.gitignore b/.gitignore index 549abd6..6e04ed1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ pubspec_overrides.yaml melos_dartseid.iml .DS_Store +.fvm diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index 9b988f0..9af78a8 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -2,14 +2,21 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; -class ArcadeOrmMockAdapter implements ArcadeOrmAdapterBase { +typedef OptionsRecord = ({String? name, String? host, int? port}); + +class ArcadeOrmMockAdapter + implements ArcadeOrmAdapterBase { @override late ArcadeOrm orm; @override - final dynamic connection; + final OptionsRecord? options; + + @override + final String connection; ArcadeOrmMockAdapter({ required this.connection, + this.options, }); @override @@ -69,24 +76,21 @@ Future orming() async { "name": ColumnString(), "json": ColumnJson(), }, - converter: ( - fromJson: (Map j) {}, - toJson: () => {}, - ), ); t.index({"id": 1, "name": 1}); - // final trx = t.transaction(); - // final b = await trx.start(); - // trx.commit(); - // trx.rollback(); + final trx = t.transaction(); + await trx.start(); + t.findOne(transaction: trx); + trx.commit(); + trx.rollback(); final data = await t.transaction().start( (trx) async { final r = t.findOne(transaction: trx) ..where({ - "id": array([1, 2, 4]) + "id": array([1, 2, 4]), }) ..where({"id": eq(10)}) ..where( @@ -95,7 +99,7 @@ Future orming() async { "name": like("%aa"), "id": array([1, 2, 4]), }, - {"name": eq("2")} + {"name": eq("2")}, ]), ) ..where( @@ -136,7 +140,7 @@ Future orming() async { return ""; } - final result = await r.exec(converter: (fromJson: fromJsonFn)); + final result = await r.exec(fromJson: fromJsonFn); return switch (result) { ExecResultData(data: final data) => data, diff --git a/packages/arcade_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart index 32186d1..84fb70f 100644 --- a/packages/arcade_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -3,14 +3,17 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; import 'package:meta/meta.dart'; -abstract interface class ArcadeOrmAdapterBase { +abstract interface class ArcadeOrmAdapterBase { @protected - final dynamic connection; + final U connection; + @protected + final T? options; @protected late ArcadeOrm orm; ArcadeOrmAdapterBase({ required this.connection, + this.options, }); FutureOr init(); @@ -35,7 +38,7 @@ abstract interface class ArcadeOrmAdapterBase { void setArcadeOrmInstance(ArcadeOrm orm); ArcadeOrmTransaction transaction(); - + FutureOr close(); } @@ -44,15 +47,15 @@ abstract class ArcadeOrmTransaction { bool isCommitted = false; bool isRolledBack = false; - Future commit() async { + Future _commit() async { _checkPrecondition("Commit"); - await _commit(); + await commit(); isCommitted = true; } - Future rollback() async { + Future _rollback() async { _checkPrecondition("Rollback"); - await _rollback(); + await rollback(); isRolledBack = true; } @@ -61,27 +64,29 @@ abstract class ArcadeOrmTransaction { ]) async { try { _checkStartPreCondition(); - await _start(); + await startTransaction(); isStarted = true; if (callback == null) { return null; } final data = await callback(this); - await commit(); + await _commit(); return data; } catch (e) { if (callback != null) { - await rollback(); + await _rollback(); } rethrow; } } - Future _commit(); + Future commit(); - Future _rollback(); + Future rollback(); - Future _start(); + /// Use [ArcadeOrmTransaction.start] instead + @protected + Future startTransaction(); void _checkStartPreCondition() { if (isCommitted) { diff --git a/packages/arcade_orm/lib/src/query.dart b/packages/arcade_orm/lib/src/query.dart index 63f688d..947dd3c 100644 --- a/packages/arcade_orm/lib/src/query.dart +++ b/packages/arcade_orm/lib/src/query.dart @@ -195,7 +195,6 @@ SelectParam sum(String value) { class ArcadeOrmTableFindOperator { final ArcadeOrm _orm; final TableOperator _operator; - final ArcadeOrmTableConverter _baseConverter; final ArcadeOrmTransaction? _transaction; final List> _whereParams = []; @@ -213,23 +212,15 @@ class ArcadeOrmTableFindOperator { ArcadeOrmTableFindOperator({ required ArcadeOrm orm, required TableOperator operator, - required ({ - FutureOr Function(Map) fromJson, - FutureOr> Function() toJson - }) baseConverter, ArcadeOrmTransaction? transaction, }) : _transaction = transaction, - _baseConverter = baseConverter, _operator = operator, _orm = orm; Future exec({ - ArcadeOrmTableFromConverter? converter, + ArcadeOrmTableFromConverter? fromJson, }) async { try { - final execConverter = - converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _orm.adapter.operate( isExplain: _isExplain, operator: _operator, @@ -244,9 +235,9 @@ class ArcadeOrmTableFindOperator { skip: _skip, ); - final convertedData = await execConverter(data); + final convertedData = await fromJson?.call(data); - return ExecResultData(convertedData); + return ExecResultData(convertedData ?? data); } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { @@ -324,7 +315,6 @@ class ArcadeOrmTableFindOperator { class ArcadeOrmTableCreateOperator { final ArcadeOrm _orm; final TableOperator _operator; - final ArcadeOrmTableConverter _baseConverter; final ArcadeOrmTransaction? _transaction; final List> _createWithParams = []; @@ -334,13 +324,8 @@ class ArcadeOrmTableCreateOperator { ArcadeOrmTableCreateOperator({ required ArcadeOrm orm, required TableOperator operator, - required ({ - FutureOr Function(Map) fromJson, - FutureOr> Function() toJson - }) baseConverter, ArcadeOrmTransaction? transaction, }) : _transaction = transaction, - _baseConverter = baseConverter, _operator = operator, _orm = orm; @@ -349,12 +334,9 @@ class ArcadeOrmTableCreateOperator { } Future exec({ - ArcadeOrmTableFromConverter? converter, + ArcadeOrmTableFromConverter? fromJson, }) async { try { - final execConverter = - converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _orm.adapter.operate( isExplain: _isExplain, operator: _operator, @@ -362,9 +344,9 @@ class ArcadeOrmTableCreateOperator { createWithParams: _createWithParams, ); - final convertedData = await execConverter(data); + final convertedData = await fromJson?.call(data); - return ExecResultData(convertedData); + return ExecResultData(convertedData ?? data); } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { @@ -382,7 +364,6 @@ class ArcadeOrmTableCreateOperator { class ArcadeOrmTableDeleteOperator { final ArcadeOrm _orm; final TableOperator _operator; - final ArcadeOrmTableConverter _baseConverter; final ArcadeOrmTransaction? _transaction; final List> _whereParams = []; @@ -393,23 +374,15 @@ class ArcadeOrmTableDeleteOperator { ArcadeOrmTableDeleteOperator({ required ArcadeOrm orm, required TableOperator operator, - required ({ - FutureOr Function(Map) fromJson, - FutureOr> Function() toJson - }) baseConverter, ArcadeOrmTransaction? transaction, }) : _transaction = transaction, - _baseConverter = baseConverter, _operator = operator, _orm = orm; Future exec({ - ArcadeOrmTableFromConverter? converter, + ArcadeOrmTableFromConverter? fromJson, }) async { try { - final execConverter = - converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _orm.adapter.operate( isExplain: _isExplain, operator: _operator, @@ -418,9 +391,9 @@ class ArcadeOrmTableDeleteOperator { includeParams: _includeParams, ); - final convertedData = await execConverter(data); + final convertedData = await fromJson?.call(data); - return ExecResultData(convertedData); + return ExecResultData(convertedData ?? data); } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { @@ -458,7 +431,6 @@ class ArcadeOrmTableDeleteOperator { class ArcadeOrmTableRawOperator { final ArcadeOrm _orm; final TableOperator _operator; - final ArcadeOrmTableConverter _baseConverter; final ArcadeOrmTransaction? _transaction; bool _isExplain = false; @@ -469,23 +441,15 @@ class ArcadeOrmTableRawOperator { ArcadeOrmTableRawOperator({ required ArcadeOrm orm, required TableOperator operator, - required ({ - FutureOr Function(Map) fromJson, - FutureOr> Function() toJson - }) baseConverter, ArcadeOrmTransaction? transaction, }) : _transaction = transaction, - _baseConverter = baseConverter, _operator = operator, _orm = orm; Future exec({ - ArcadeOrmTableFromConverter? converter, + ArcadeOrmTableFromConverter? fromJson, }) async { try { - final execConverter = - converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _orm.adapter.operate( isExplain: _isExplain, rawSql: _rawSql, @@ -494,9 +458,9 @@ class ArcadeOrmTableRawOperator { transaction: _transaction, ); - final convertedData = await execConverter(data); + final convertedData = await fromJson?.call(data); - return ExecResultData(convertedData); + return ExecResultData(convertedData ?? data); } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { @@ -524,7 +488,6 @@ class ArcadeOrmTableRawOperator { class ArcadeOrmTableUpdateOperator { final ArcadeOrm _orm; final TableOperator _operator; - final ArcadeOrmTableConverter _baseConverter; final ArcadeOrmTransaction? _transaction; final List> _updateWithParams = []; @@ -535,23 +498,15 @@ class ArcadeOrmTableUpdateOperator { ArcadeOrmTableUpdateOperator({ required ArcadeOrm orm, required TableOperator operator, - required ({ - FutureOr Function(Map) fromJson, - FutureOr> Function() toJson - }) baseConverter, ArcadeOrmTransaction? transaction, }) : _transaction = transaction, - _baseConverter = baseConverter, _operator = operator, _orm = orm; Future exec({ - ArcadeOrmTableFromConverter? converter, + ArcadeOrmTableFromConverter? fromJson, }) async { try { - final execConverter = - converter != null ? converter.fromJson : _baseConverter.fromJson; - final data = await _orm.adapter.operate( isExplain: _isExplain, operator: _operator, @@ -560,9 +515,9 @@ class ArcadeOrmTableUpdateOperator { updateWithParams: _updateWithParams, ); - final convertedData = await execConverter(data); + final convertedData = await fromJson?.call(data); - return ExecResultData(convertedData); + return ExecResultData(convertedData ?? data); } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { diff --git a/packages/arcade_orm/lib/src/table.dart b/packages/arcade_orm/lib/src/table.dart index 31f4226..ab74315 100644 --- a/packages/arcade_orm/lib/src/table.dart +++ b/packages/arcade_orm/lib/src/table.dart @@ -7,9 +7,9 @@ typedef ArcadeOrmTableConverter = ({ FutureOr> Function() toJson, }); -typedef ArcadeOrmTableFromConverter = ({ - FutureOr Function(Map json) fromJson, -}); +typedef ArcadeOrmTableFromConverter = FutureOr Function( + Map json, +); mixin ArcadeOrmTable { late String name; @@ -17,13 +17,8 @@ mixin ArcadeOrmTable { late final ArcadeOrm _orm = getArcadeOrmInstance(name); - ArcadeOrmTableSchema table( - String name, - Map schema, { - required ArcadeOrmTableConverter converter, - }) { - final schema = - ArcadeOrmTableSchema(orm: _orm, name: name, baseConverter: converter); + ArcadeOrmTableSchema table(String name, Map schema) { + final schema = ArcadeOrmTableSchema(orm: _orm, name: name); _orm._tables.add(schema); return schema; } @@ -42,12 +37,10 @@ mixin ArcadeOrmTable { class ArcadeOrmTableSchema { final ArcadeOrm orm; final String name; - final ArcadeOrmTableConverter baseConverter; ArcadeOrmTableSchema({ required this.orm, required this.name, - required this.baseConverter, }); ArcadeOrmTransaction transaction() { @@ -60,7 +53,6 @@ class ArcadeOrmTableSchema { return ArcadeOrmTableRawOperator( orm: orm, operator: TableOperator.raw, - baseConverter: baseConverter, transaction: transaction, ); } @@ -69,7 +61,6 @@ class ArcadeOrmTableSchema { return ArcadeOrmTableFindOperator( orm: orm, operator: TableOperator.count, - baseConverter: baseConverter, transaction: transaction, ); } @@ -78,7 +69,6 @@ class ArcadeOrmTableSchema { return ArcadeOrmTableFindOperator( orm: orm, operator: TableOperator.findOne, - baseConverter: baseConverter, transaction: transaction, ); } @@ -87,7 +77,6 @@ class ArcadeOrmTableSchema { return ArcadeOrmTableFindOperator( orm: orm, operator: TableOperator.findMany, - baseConverter: baseConverter, transaction: transaction, ); } @@ -96,7 +85,6 @@ class ArcadeOrmTableSchema { return ArcadeOrmTableCreateOperator( orm: orm, operator: TableOperator.create, - baseConverter: baseConverter, transaction: transaction, ); } @@ -105,7 +93,6 @@ class ArcadeOrmTableSchema { return ArcadeOrmTableUpdateOperator( orm: orm, operator: TableOperator.update, - baseConverter: baseConverter, transaction: transaction, ); } @@ -114,7 +101,6 @@ class ArcadeOrmTableSchema { return ArcadeOrmTableDeleteOperator( orm: orm, operator: TableOperator.delete, - baseConverter: baseConverter, transaction: transaction, ); } From 053c159e9dc94fb69a590bfa4de8cb2cfc0a77a1 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Tue, 21 Nov 2023 15:59:51 +0600 Subject: [PATCH 09/24] feat: added nvim.lua to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6e04ed1..280bdea 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ pubspec_overrides.yaml melos_dartseid.iml .DS_Store .fvm +.nvim.lua From 11dfc8f0d575f0dae1bcb906282a9fa8ac8ffbe8 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Tue, 21 Nov 2023 23:46:46 +0600 Subject: [PATCH 10/24] feat: added adapter transaction tests --- packages/arcade_orm/lib/src/adapter.dart | 49 +-- .../arcade_orm/test/src/adapter_test.dart | 312 ++++++++++++++++++ 2 files changed, 339 insertions(+), 22 deletions(-) create mode 100644 packages/arcade_orm/test/src/adapter_test.dart diff --git a/packages/arcade_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart index 84fb70f..37f5a79 100644 --- a/packages/arcade_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -43,20 +43,24 @@ abstract interface class ArcadeOrmAdapterBase { } abstract class ArcadeOrmTransaction { - bool isStarted = false; - bool isCommitted = false; - bool isRolledBack = false; + bool _isStarted = false; + bool _isCommitted = false; + bool _isRolledBack = false; - Future _commit() async { + bool get isStarted => _isStarted; + bool get isComitted => _isCommitted; + bool get isRolledBack => _isRolledBack; + + Future commit() async { _checkPrecondition("Commit"); - await commit(); - isCommitted = true; + await $commit(); + _isCommitted = true; } - Future _rollback() async { + Future rollback() async { _checkPrecondition("Rollback"); - await rollback(); - isRolledBack = true; + await $rollback(); + _isRolledBack = true; } Future start([ @@ -64,38 +68,39 @@ abstract class ArcadeOrmTransaction { ]) async { try { _checkStartPreCondition(); - await startTransaction(); - isStarted = true; + await $startTransaction(); + _isStarted = true; if (callback == null) { return null; } final data = await callback(this); - await _commit(); + await commit(); return data; } catch (e) { if (callback != null) { - await _rollback(); + await rollback(); } rethrow; } } - Future commit(); + @protected + Future $commit(); - Future rollback(); + @protected + Future $rollback(); - /// Use [ArcadeOrmTransaction.start] instead @protected - Future startTransaction(); + Future $startTransaction(); void _checkStartPreCondition() { - if (isCommitted) { + if (_isCommitted) { throw ArcadeOrmException( message: "Cannot Start a transaction that is already committed", originalError: null, ); } - if (isRolledBack) { + if (_isRolledBack) { throw ArcadeOrmException( message: "Cannot Start a transaction that is already rolled back", originalError: null, @@ -104,19 +109,19 @@ abstract class ArcadeOrmTransaction { } void _checkPrecondition(String op) { - if (!isStarted) { + if (!_isStarted) { throw ArcadeOrmException( message: "Cannot $op a transaction that has not been started", originalError: null, ); } - if (isCommitted) { + if (_isCommitted) { throw ArcadeOrmException( message: "Cannot $op a transaction that is already committed", originalError: null, ); } - if (isRolledBack) { + if (_isRolledBack) { throw ArcadeOrmException( message: "Cannot $op a transaction that has been rolled back", originalError: null, diff --git a/packages/arcade_orm/test/src/adapter_test.dart b/packages/arcade_orm/test/src/adapter_test.dart new file mode 100644 index 0000000..33f7f68 --- /dev/null +++ b/packages/arcade_orm/test/src/adapter_test.dart @@ -0,0 +1,312 @@ +import 'dart:async'; + +import 'package:arcade_orm/arcade_orm.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class MockAdapter extends Mock implements ArcadeOrmAdapterBase {} + +class Transaction extends ArcadeOrmTransaction { + int commitCount = 0; + int rollbackCount = 0; + int startCount = 0; + + @override + Future $commit() async { + commitCount++; + } + + @override + Future $rollback() async { + rollbackCount++; + } + + @override + Future $startTransaction() async { + startCount++; + } +} + +void main() { + final mockAdapter = MockAdapter(); + group('transaction', () { + setUp(() { + when(() => mockAdapter.transaction()).thenReturn(Transaction()); + }); + tearDown(clearOrms); + test("commit flow", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start(); + await trx.commit(); + final Transaction(:startCount, :commitCount, :rollbackCount) = trx; + expect(startCount, 1); + expect(commitCount, 1); + expect(rollbackCount, 0); + }); + test("rollback flow", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start(); + await trx.rollback(); + final Transaction(:startCount, :commitCount, :rollbackCount) = trx; + expect(startCount, 1); + expect(commitCount, 0); + expect(rollbackCount, 1); + }); + test("callback commit flow", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + final data = await trx.start((trx) async { + return {"key": "value"}; + }); + expect(data, {"key": "value"}); + final Transaction(:startCount, :commitCount, :rollbackCount) = trx; + expect(startCount, 1); + expect(commitCount, 1); + expect(rollbackCount, 0); + }); + test("callback rollback flow", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + try { + await trx.start((trx) async { + throw Exception(); + }); + } catch (_) { + final Transaction(:startCount, :commitCount, :rollbackCount) = trx; + expect(startCount, 1); + expect(commitCount, 0); + expect(rollbackCount, 1); + return; + } + throw Exception("Expected Exception"); + }); + test("early commit", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.commit(); + fail("Expected an Exception"); + } catch (e) { + if (e is! ArcadeOrmException) { + fail("Expected ArcadeOrmException"); + } + expect( + e.message, + "Cannot Commit a transaction that has not been started", + ); + } + }); + test("callback early commit", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start((trx) async { + await trx.commit(); + }); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Rollback a transaction that is already committed", + ); + return; + } + fail("Expected ArcadeOrmException"); + }); + test("early rollback", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.rollback(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Rollback a transaction that has not been started", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("callback - early rollback", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start((trx) async { + await trx.rollback(); + }); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Rollback a transaction that has been rolled back", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("late start after commit", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start(); + await trx.commit(); + await trx.start(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Start a transaction that is already committed", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("callback - late start after commit", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start((trx) async {}); + await trx.start(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Start a transaction that is already committed", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("late start after rollback", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start(); + await trx.rollback(); + await trx.start(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Start a transaction that is already rolled back", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("callback - late start after rollback", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + try { + await trx.start((trx) async { + throw Exception(); + }); + } catch (_) {} + await trx.start(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Start a transaction that is already rolled back", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("commit after rollback", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start(); + await trx.rollback(); + await trx.commit(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Commit a transaction that has been rolled back", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("callback - commit after rollback", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + try { + await trx.start((trx) async { + throw Exception(); + }); + } catch (_) {} + await trx.commit(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Commit a transaction that has been rolled back", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("rollback after commit", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start(); + await trx.commit(); + await trx.rollback(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Rollback a transaction that is already committed", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + test("callback - rollback after commit", () async { + try { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final trx = arcadeOrm.transaction() as Transaction; + await trx.start((trx) async {}); + await trx.rollback(); + } on ArcadeOrmException catch (e) { + expect( + e.message, + "Cannot Rollback a transaction that is already committed", + ); + return; + } + throw Exception("Expected ArcadeOrmException"); + }); + }); +} From d83234ecda61ac013184bcf0f7c786918b7407b9 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Thu, 23 Nov 2023 14:37:43 +0600 Subject: [PATCH 11/24] feat: added create tests --- .../arcade_orm/test/src/adapter_test.dart | 17 +++ .../test/src/query/create_test.dart | 144 ++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 packages/arcade_orm/test/src/query/create_test.dart diff --git a/packages/arcade_orm/test/src/adapter_test.dart b/packages/arcade_orm/test/src/adapter_test.dart index 33f7f68..cdd0649 100644 --- a/packages/arcade_orm/test/src/adapter_test.dart +++ b/packages/arcade_orm/test/src/adapter_test.dart @@ -33,7 +33,9 @@ void main() { setUp(() { when(() => mockAdapter.transaction()).thenReturn(Transaction()); }); + tearDown(clearOrms); + test("commit flow", () async { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, @@ -46,6 +48,7 @@ void main() { expect(commitCount, 1); expect(rollbackCount, 0); }); + test("rollback flow", () async { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, @@ -58,6 +61,7 @@ void main() { expect(commitCount, 0); expect(rollbackCount, 1); }); + test("callback commit flow", () async { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, @@ -72,6 +76,7 @@ void main() { expect(commitCount, 1); expect(rollbackCount, 0); }); + test("callback rollback flow", () async { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, @@ -90,6 +95,7 @@ void main() { } throw Exception("Expected Exception"); }); + test("early commit", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -108,6 +114,7 @@ void main() { ); } }); + test("callback early commit", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -126,6 +133,7 @@ void main() { } fail("Expected ArcadeOrmException"); }); + test("early rollback", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -142,6 +150,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("callback - early rollback", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -160,6 +169,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("late start after commit", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -178,6 +188,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("callback - late start after commit", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -195,6 +206,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("late start after rollback", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -213,6 +225,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("callback - late start after rollback", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -234,6 +247,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("commit after rollback", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -252,6 +266,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("callback - commit after rollback", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -273,6 +288,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("rollback after commit", () async { try { final arcadeOrm = await ArcadeOrm.init( @@ -291,6 +307,7 @@ void main() { } throw Exception("Expected ArcadeOrmException"); }); + test("callback - rollback after commit", () async { try { final arcadeOrm = await ArcadeOrm.init( diff --git a/packages/arcade_orm/test/src/query/create_test.dart b/packages/arcade_orm/test/src/query/create_test.dart new file mode 100644 index 0000000..59a1cc0 --- /dev/null +++ b/packages/arcade_orm/test/src/query/create_test.dart @@ -0,0 +1,144 @@ +import 'package:arcade_orm/arcade_orm.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class MockAdapter extends Mock implements ArcadeOrmAdapterBase {} + +class MockTransaction extends Mock implements ArcadeOrmTransaction {} + +void main() { + final mockAdapter = MockAdapter(); + final mockTransaction = MockTransaction(); + group('create', () { + setUp(() { + when(() => mockAdapter.transaction()).thenReturn(mockTransaction); + }); + + tearDown(() { + clearOrms(); + reset(mockAdapter); + }); + + test("create db record - success", () async { + when( + () => mockAdapter.operate( + operator: TableOperator.create, + transaction: null, + isExplain: false, + createWithParams: any(named: "createWithParams"), + ), + ).thenAnswer( + (_) => Future.value({"nCreated": 1}), + ); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final createQuery = table.create() + ..createWith({"name": "foo", "age": 20}) + ..createWith({"email": "foo@examle.com"}); + final data = await createQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.create, + transaction: null, + isExplain: false, + whereParams: [], + havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: [], + createWithParams: [ + {"name": "foo", "age": 20}, + {"email": "foo@examle.com"}, + ], + ), + ).called(1); + expect(data, isA()); + expect((data as ExecResultData).data, {"nCreated": 1}); + }); + + test("create db record - failure", () async { + when( + () => mockAdapter.operate( + operator: TableOperator.create, + transaction: null, + isExplain: false, + createWithParams: any(named: "createWithParams"), + ), + ).thenThrow( + ArcadeOrmException(message: "Create Failed", originalError: null), + ); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final createQuery = table.create() + ..createWith({"name": "foo", "age": 20}) + ..createWith({"email": "foo@examle.com"}); + final data = await createQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.create, + transaction: null, + isExplain: false, + whereParams: [], + havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: [], + createWithParams: [ + {"name": "foo", "age": 20}, + {"email": "foo@examle.com"}, + ], + ), + ).called(1); + expect(data, isA()); + expect((data as ExecResultFailure).exception.message, "Create Failed"); + }); + + test("create db record with Transaction", () async { + when(() => mockTransaction.start()) + .thenAnswer((_) async => Future.value()); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final trx = table.transaction(); + await trx.start(); + final createQuery = table.create(transaction: trx) + ..createWith({"name": "foo", "age": 20}); + await createQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.create, + transaction: trx, + isExplain: false, + whereParams: [], + havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: [], + createWithParams: [ + {"name": "foo", "age": 20}, + ], + ), + ).called(1); + }); + }); +} From 9129db44d53fbff3a60099002f58c29478beb624 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Thu, 23 Nov 2023 15:12:41 +0600 Subject: [PATCH 12/24] chore: refactored create test --- .../test/src/query/create_test.dart | 196 +++++++++--------- 1 file changed, 102 insertions(+), 94 deletions(-) diff --git a/packages/arcade_orm/test/src/query/create_test.dart b/packages/arcade_orm/test/src/query/create_test.dart index 59a1cc0..50d2ec0 100644 --- a/packages/arcade_orm/test/src/query/create_test.dart +++ b/packages/arcade_orm/test/src/query/create_test.dart @@ -17,50 +17,110 @@ void main() { tearDown(() { clearOrms(); reset(mockAdapter); + reset(mockTransaction); }); - test("create db record - success", () async { - when( - () => mockAdapter.operate( - operator: TableOperator.create, - transaction: null, - isExplain: false, - createWithParams: any(named: "createWithParams"), - ), - ).thenAnswer( - (_) => Future.value({"nCreated": 1}), - ); - final arcadeOrm = await ArcadeOrm.init( - adapter: mockAdapter, - ); - final table = arcadeOrm.table( - "users", - {}, - ); - final createQuery = table.create() - ..createWith({"name": "foo", "age": 20}) - ..createWith({"email": "foo@examle.com"}); - final data = await createQuery.exec(); - verify( - () => mockAdapter.operate( - operator: TableOperator.create, - transaction: null, - isExplain: false, - whereParams: [], - havingParams: [], - selectParams: [], - includeParams: [], - groupParams: [], - sortParams: [], - updateWithParams: [], - createWithParams: [ - {"name": "foo", "age": 20}, - {"email": "foo@examle.com"}, - ], - ), - ).called(1); - expect(data, isA()); - expect((data as ExecResultData).data, {"nCreated": 1}); + group("success", () { + setUp(() { + when( + () => mockAdapter.operate( + operator: TableOperator.create, + transaction: null, + isExplain: false, + createWithParams: any(named: "createWithParams"), + ), + ).thenAnswer( + (_) => Future.value({"nCreated": 1}), + ); + }); + + tearDown(() { + clearOrms(); + reset(mockAdapter); + reset(mockTransaction); + }); + + test("operate", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final createQuery = table.create() + ..createWith({"name": "foo", "age": 20}) + ..createWith({"email": "foo@examle.com"}); + await createQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.create, + transaction: null, + isExplain: false, + whereParams: [], + havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: [], + createWithParams: [ + {"name": "foo", "age": 20}, + {"email": "foo@examle.com"}, + ], + ), + ).called(1); + }); + + test("data", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final createQuery = table.create() + ..createWith({"name": "foo", "age": 20}) + ..createWith({"email": "foo@examle.com"}); + final data = await createQuery.exec(); + expect(data, isA()); + expect((data as ExecResultData).data, equals({"nCreated": 1})); + }); + + test("operate with transaction", () async { + when(() => mockTransaction.start()) + .thenAnswer((_) async => Future.value()); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final trx = table.transaction(); + await trx.start(); + final createQuery = table.create(transaction: trx) + ..createWith({"name": "foo", "age": 20}); + await createQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.create, + transaction: trx, + isExplain: false, + whereParams: [], + havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: [], + createWithParams: [ + {"name": "foo", "age": 20}, + ], + ), + ).called(1); + }); }); test("create db record - failure", () async { @@ -85,60 +145,8 @@ void main() { ..createWith({"name": "foo", "age": 20}) ..createWith({"email": "foo@examle.com"}); final data = await createQuery.exec(); - verify( - () => mockAdapter.operate( - operator: TableOperator.create, - transaction: null, - isExplain: false, - whereParams: [], - havingParams: [], - selectParams: [], - includeParams: [], - groupParams: [], - sortParams: [], - updateWithParams: [], - createWithParams: [ - {"name": "foo", "age": 20}, - {"email": "foo@examle.com"}, - ], - ), - ).called(1); expect(data, isA()); expect((data as ExecResultFailure).exception.message, "Create Failed"); }); - - test("create db record with Transaction", () async { - when(() => mockTransaction.start()) - .thenAnswer((_) async => Future.value()); - final arcadeOrm = await ArcadeOrm.init( - adapter: mockAdapter, - ); - final table = arcadeOrm.table( - "users", - {}, - ); - final trx = table.transaction(); - await trx.start(); - final createQuery = table.create(transaction: trx) - ..createWith({"name": "foo", "age": 20}); - await createQuery.exec(); - verify( - () => mockAdapter.operate( - operator: TableOperator.create, - transaction: trx, - isExplain: false, - whereParams: [], - havingParams: [], - selectParams: [], - includeParams: [], - groupParams: [], - sortParams: [], - updateWithParams: [], - createWithParams: [ - {"name": "foo", "age": 20}, - ], - ), - ).called(1); - }); }); } From 2af04dc8745b64edc52258d6d443a81adb65d85e Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Wed, 20 Dec 2023 03:50:18 +0600 Subject: [PATCH 13/24] feat: delete test --- packages/arcade_orm/example/api/basic.dart | 14 +- packages/arcade_orm/lib/src/query.dart | 8 +- .../test/src/query/create_test.dart | 2 +- .../test/src/query/delete_test.dart | 183 ++++++++++++++++++ 4 files changed, 197 insertions(+), 10 deletions(-) create mode 100644 packages/arcade_orm/test/src/query/delete_test.dart diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index 9af78a8..7b51928 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -65,11 +65,11 @@ class ArcadeOrmMockAdapter } Future orming() async { - final a = await ArcadeOrm.init( + final orm = await ArcadeOrm.init( adapter: ArcadeOrmMockAdapter(connection: ""), ); - final t = a.table( + final userTable = orm.table( "users", { "id": ColumnInt()..nullable(), @@ -78,17 +78,17 @@ Future orming() async { }, ); - t.index({"id": 1, "name": 1}); + userTable.index({"id": 1, "name": 1}); - final trx = t.transaction(); + final trx = userTable.transaction(); await trx.start(); - t.findOne(transaction: trx); + userTable.findOne(transaction: trx); trx.commit(); trx.rollback(); - final data = await t.transaction().start( + final data = await userTable.transaction().start( (trx) async { - final r = t.findOne(transaction: trx) + final r = userTable.findOne(transaction: trx) ..where({ "id": array([1, 2, 4]), }) diff --git a/packages/arcade_orm/lib/src/query.dart b/packages/arcade_orm/lib/src/query.dart index 947dd3c..f52b2d0 100644 --- a/packages/arcade_orm/lib/src/query.dart +++ b/packages/arcade_orm/lib/src/query.dart @@ -217,7 +217,7 @@ class ArcadeOrmTableFindOperator { _operator = operator, _orm = orm; - Future exec({ + Future> exec({ ArcadeOrmTableFromConverter? fromJson, }) async { try { @@ -237,7 +237,7 @@ class ArcadeOrmTableFindOperator { final convertedData = await fromJson?.call(data); - return ExecResultData(convertedData ?? data); + return ExecResultData(convertedData ?? data as T); } on ArcadeOrmException catch (e) { return ExecResultFailure(e); } catch (e) { @@ -262,6 +262,7 @@ class ArcadeOrmTableFindOperator { void include( String tableName, { String? on, + String? as, Map? where, JoinOperation joinType = JoinOperation.inner, }) { @@ -269,6 +270,7 @@ class ArcadeOrmTableFindOperator { IncludeParam( tableName, on: on, + as: as, where: where, joinType: joinType, ), @@ -557,11 +559,13 @@ class ExecResultFailure extends ExecResult { class IncludeParam { final String tableName; final String? on; + final String? as; final JoinOperation joinType; Map? where; IncludeParam( this.tableName, { this.on, + this.as, this.joinType = JoinOperation.inner, Map? where, }) { diff --git a/packages/arcade_orm/test/src/query/create_test.dart b/packages/arcade_orm/test/src/query/create_test.dart index 50d2ec0..04420fb 100644 --- a/packages/arcade_orm/test/src/query/create_test.dart +++ b/packages/arcade_orm/test/src/query/create_test.dart @@ -123,7 +123,7 @@ void main() { }); }); - test("create db record - failure", () async { + test("db record - failure", () async { when( () => mockAdapter.operate( operator: TableOperator.create, diff --git a/packages/arcade_orm/test/src/query/delete_test.dart b/packages/arcade_orm/test/src/query/delete_test.dart new file mode 100644 index 0000000..7e5edb9 --- /dev/null +++ b/packages/arcade_orm/test/src/query/delete_test.dart @@ -0,0 +1,183 @@ +import 'package:arcade_orm/arcade_orm.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class MockAdapter extends Mock implements ArcadeOrmAdapterBase {} + +class MockTransaction extends Mock implements ArcadeOrmTransaction {} + +class FakeWhereParam extends Fake implements WhereParam {} + +void main() { + final mockAdapter = MockAdapter(); + final mockTransaction = MockTransaction(); + + group('delete', () { + setUp(() { + registerFallbackValue(FakeWhereParam()); + when(() => mockAdapter.transaction()).thenReturn(mockTransaction); + }); + + tearDown(() { + clearOrms(); + reset(mockAdapter); + reset(mockTransaction); + }); + + group("success", () { + setUp(() { + when( + () => mockAdapter.operate( + operator: TableOperator.delete, + transaction: null, + isExplain: false, + whereParams: any(named: "whereParams"), + ), + ).thenAnswer( + (_) => Future.value({"deleted": 1}), + ); + }); + + tearDown(() { + clearOrms(); + reset(mockAdapter); + reset(mockTransaction); + }); + + test("operate", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final deleteQuery = table.delete() + ..where({"id": eq(1)}) + ..include("role", where: {"name": notEq("admin")}); + + await deleteQuery.exec(); + + final captured = verify( + () => mockAdapter.operate( + operator: TableOperator.delete, + transaction: null, + isExplain: false, + whereParams: captureAny(named: "whereParams"), + havingParams: [], + selectParams: [], + includeParams: captureAny(named: "includeParams"), + groupParams: [], + sortParams: [], + updateWithParams: [], + createWithParams: [], + ), + ).captured; + final capturedWhereParams = + (captured.first as List>).first['id']; + expect( + capturedWhereParams?.value, + equals(1), + ); + expect( + capturedWhereParams?.operator, + equals(WhereOperator.eq), + ); + final capturedIncludeParams = (captured[1] as List).first; + expect(capturedIncludeParams.tableName, equals("role")); + expect( + capturedIncludeParams.where?["name"]?.operator, + equals(WhereOperator.notEq), + ); + expect( + capturedIncludeParams.where?["name"]?.value, + equals("admin"), + ); + expect(capturedIncludeParams.as, equals(null)); + expect(capturedIncludeParams.on, equals(null)); + expect(capturedIncludeParams.joinType, equals(JoinOperation.inner)); + }); + + test("data", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final deleteQuery = table.delete()..where({"id": eq(1)}); + final data = await deleteQuery.exec(); + expect(data, isA()); + expect((data as ExecResultData).data, equals({"deleted": 1})); + }); + + test("operate with transaction", () async { + when(() => mockTransaction.start()) + .thenAnswer((_) async => Future.value()); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final trx = table.transaction(); + await trx.start(); + final deleteQuery = table.delete(transaction: trx) + ..where({"id": eq(1)}); + await deleteQuery.exec(); + final captured = verify( + () => mockAdapter.operate( + operator: TableOperator.delete, + transaction: trx, + isExplain: false, + whereParams: captureAny(named: "whereParams"), + havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: [], + createWithParams: [], + ), + ).captured; + + final capturedWhereParams = + (captured.first as List>).first['id']; + expect( + capturedWhereParams?.value, + equals(1), + ); + expect( + capturedWhereParams?.operator, + equals(WhereOperator.eq), + ); + }); + }); + + test("db record - failure", () async { + when( + () => mockAdapter.operate( + operator: TableOperator.delete, + transaction: null, + isExplain: false, + whereParams: any(named: "whereParams"), + ), + ).thenThrow( + ArcadeOrmException(message: "Delete Failed", originalError: null), + ); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = arcadeOrm.table( + "users", + {}, + ); + final createQuery = table.delete()..where({"id": eq(1)}); + final data = await createQuery.exec(); + expect(data, isA()); + expect((data as ExecResultFailure).exception.message, "Delete Failed"); + }); + }); +} From 1d69281c886fdeaf101945ec11aefaed796599d4 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Wed, 20 Dec 2023 04:13:52 +0600 Subject: [PATCH 14/24] feat: test scripts --- melos.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/melos.yaml b/melos.yaml index 3c5596a..75667fa 100644 --- a/melos.yaml +++ b/melos.yaml @@ -11,3 +11,12 @@ scripts: format: exec: dart format lib + test: + exec: dart test + packageFilters: + scope: '*' + + testArcadeOrm: + exec: dart test --reporter=expanded --chain-stack-traces + packageFilters: + scope: arcade_orm From 358776a1bff3526adf13b01ce109c33629f87d3f Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Wed, 20 Dec 2023 17:05:56 +0600 Subject: [PATCH 15/24] feat: update docs --- packages/arcade_orm/lib/src/table.dart | 21 +++---- .../test/src/query/create_test.dart | 40 +++++++------ .../test/src/query/delete_test.dart | 57 ++++++++++++------- 3 files changed, 67 insertions(+), 51 deletions(-) diff --git a/packages/arcade_orm/lib/src/table.dart b/packages/arcade_orm/lib/src/table.dart index ab74315..c027ee2 100644 --- a/packages/arcade_orm/lib/src/table.dart +++ b/packages/arcade_orm/lib/src/table.dart @@ -15,14 +15,6 @@ mixin ArcadeOrmTable { late String name; final List _tables = []; - late final ArcadeOrm _orm = getArcadeOrmInstance(name); - - ArcadeOrmTableSchema table(String name, Map schema) { - final schema = ArcadeOrmTableSchema(orm: _orm, name: name); - _orm._tables.add(schema); - return schema; - } - ArcadeOrmTableSchema getTable(String name) { try { return _tables.firstWhere((element) => element.name == name); @@ -34,14 +26,15 @@ mixin ArcadeOrmTable { } } -class ArcadeOrmTableSchema { +abstract class ArcadeOrmTableSchema { final ArcadeOrm orm; - final String name; + String get name; - ArcadeOrmTableSchema({ - required this.orm, - required this.name, - }); + Map get schema; + + ArcadeOrmTableSchema(this.orm) { + orm._tables.add(this); + } ArcadeOrmTransaction transaction() { return orm.transaction(); diff --git a/packages/arcade_orm/test/src/query/create_test.dart b/packages/arcade_orm/test/src/query/create_test.dart index 04420fb..1994e8b 100644 --- a/packages/arcade_orm/test/src/query/create_test.dart +++ b/packages/arcade_orm/test/src/query/create_test.dart @@ -6,6 +6,26 @@ class MockAdapter extends Mock implements ArcadeOrmAdapterBase {} class MockTransaction extends Mock implements ArcadeOrmTransaction {} +class UserTable extends ArcadeOrmTableSchema { + UserTable(super.orm); + + @override + final String name = "user"; + + static const String id = "id"; + static const String userName = "name"; + static const String email = "email"; + static const String age = "age"; + + @override + Map schema = { + id: ColumnInt(), + userName: ColumnString(), + email: ColumnString(), + age: ColumnInt(), + }; +} + void main() { final mockAdapter = MockAdapter(); final mockTransaction = MockTransaction(); @@ -44,10 +64,7 @@ void main() { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); - final table = arcadeOrm.table( - "users", - {}, - ); + final table = UserTable(arcadeOrm); final createQuery = table.create() ..createWith({"name": "foo", "age": 20}) ..createWith({"email": "foo@examle.com"}); @@ -76,10 +93,7 @@ void main() { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); - final table = arcadeOrm.table( - "users", - {}, - ); + final table = UserTable(arcadeOrm); final createQuery = table.create() ..createWith({"name": "foo", "age": 20}) ..createWith({"email": "foo@examle.com"}); @@ -94,10 +108,7 @@ void main() { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); - final table = arcadeOrm.table( - "users", - {}, - ); + final table = UserTable(arcadeOrm); final trx = table.transaction(); await trx.start(); final createQuery = table.create(transaction: trx) @@ -137,10 +148,7 @@ void main() { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); - final table = arcadeOrm.table( - "users", - {}, - ); + final table = UserTable(arcadeOrm); final createQuery = table.create() ..createWith({"name": "foo", "age": 20}) ..createWith({"email": "foo@examle.com"}); diff --git a/packages/arcade_orm/test/src/query/delete_test.dart b/packages/arcade_orm/test/src/query/delete_test.dart index 7e5edb9..da2e605 100644 --- a/packages/arcade_orm/test/src/query/delete_test.dart +++ b/packages/arcade_orm/test/src/query/delete_test.dart @@ -6,7 +6,33 @@ class MockAdapter extends Mock implements ArcadeOrmAdapterBase {} class MockTransaction extends Mock implements ArcadeOrmTransaction {} -class FakeWhereParam extends Fake implements WhereParam {} +class UserTable extends ArcadeOrmTableSchema { + UserTable(super.orm); + + @override + final String name = "user"; + + static const String id = "id"; + + @override + Map schema = {id: ColumnInt()}; +} + +class RoleTable extends ArcadeOrmTableSchema { + RoleTable(super.orm); + + @override + final String name = "role"; + + static const String roleName = "name"; + static const String foo = "foo"; + + @override + Map schema = { + roleName: ColumnString(), + foo: ColumnString(), + }; +} void main() { final mockAdapter = MockAdapter(); @@ -14,7 +40,6 @@ void main() { group('delete', () { setUp(() { - registerFallbackValue(FakeWhereParam()); when(() => mockAdapter.transaction()).thenReturn(mockTransaction); }); @@ -48,13 +73,12 @@ void main() { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); - final table = arcadeOrm.table( - "users", - {}, - ); - final deleteQuery = table.delete() - ..where({"id": eq(1)}) - ..include("role", where: {"name": notEq("admin")}); + final userTable = UserTable(arcadeOrm); + final roleTable = RoleTable(arcadeOrm); + + final deleteQuery = userTable.delete() + ..include(roleTable.name, where: {"name": notEq("admin")}) + ..where({"id": eq(1)}); await deleteQuery.exec(); @@ -102,10 +126,7 @@ void main() { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); - final table = arcadeOrm.table( - "users", - {}, - ); + final table = UserTable(arcadeOrm); final deleteQuery = table.delete()..where({"id": eq(1)}); final data = await deleteQuery.exec(); expect(data, isA()); @@ -118,10 +139,7 @@ void main() { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); - final table = arcadeOrm.table( - "users", - {}, - ); + final table = UserTable(arcadeOrm); final trx = table.transaction(); await trx.start(); final deleteQuery = table.delete(transaction: trx) @@ -170,10 +188,7 @@ void main() { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); - final table = arcadeOrm.table( - "users", - {}, - ); + final table = UserTable(arcadeOrm); final createQuery = table.delete()..where({"id": eq(1)}); final data = await createQuery.exec(); expect(data, isA()); From 667ac80cf90e6cc2c422e195d076f0f42ae0509d Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Thu, 21 Dec 2023 06:14:14 +0600 Subject: [PATCH 16/24] feat: update table and column definition --- packages/arcade_orm/example/api/basic.dart | 111 ++++++++++++----- packages/arcade_orm/lib/src/query.dart | 10 +- packages/arcade_orm/lib/src/table.dart | 112 ++++++++++++------ .../test/src/query/create_test.dart | 12 +- .../test/src/query/delete_test.dart | 20 ++-- 5 files changed, 182 insertions(+), 83 deletions(-) diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index 7b51928..36e44aa 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -64,21 +64,68 @@ class ArcadeOrmMockAdapter } } +class UserTable extends ArcadeOrmTableSchema { + UserTable(super.orm); + + @override + final String tableName = "user"; + + static const String id = "id"; + static const String name = "name"; + static const String email = "email"; + static const String age = "age"; + static const String profileId = "profileId"; + + @override + Map schema = const { + id: ColumnInt(), + name: ColumnString(), + email: ColumnString(), + age: ColumnInt(), + profileId: ColumnInt(), + }; + + @override + Map index = { + name: (1, unique: null), + }; + + @override + Map relations = const { + "profile": ( + type: ArcadeOrmRelationshipType.hasOne, + table: ProfileTable.$tableName, + localKey: profileId, + foreignKey: ProfileTable.id, + ), + }; +} + +class ProfileTable extends ArcadeOrmTableSchema { + ProfileTable(super.orm); + + static const String $tableName = "profile"; + + @override + String tableName = $tableName; + + static const String id = "id"; + static const String bio = "bio"; + + @override + Map schema = {}; +} + +late final UserTable userTable; +late final ProfileTable profileTable; + Future orming() async { final orm = await ArcadeOrm.init( adapter: ArcadeOrmMockAdapter(connection: ""), ); - final userTable = orm.table( - "users", - { - "id": ColumnInt()..nullable(), - "name": ColumnString(), - "json": ColumnJson(), - }, - ); - - userTable.index({"id": 1, "name": 1}); + userTable = UserTable(orm); + profileTable = ProfileTable(orm); final trx = userTable.transaction(); await trx.start(); @@ -90,48 +137,48 @@ Future orming() async { (trx) async { final r = userTable.findOne(transaction: trx) ..where({ - "id": array([1, 2, 4]), + UserTable.id: array([1, 2, 4]), }) - ..where({"id": eq(10)}) + ..where({UserTable.id: eq(10)}) ..where( and([ { - "name": like("%aa"), - "id": array([1, 2, 4]), + UserTable.name: like("%aa"), + UserTable.id: array([1, 2, 4]), }, - {"name": eq("2")}, + {UserTable.name: eq("2")}, ]), ) ..where( or([ { - "name": like("%aa"), - "id": between(1, 200), + UserTable.name: like("%aa"), + UserTable.id: between(1, 200), } ]), ) ..select({ - "id": show(), - "_id": hide(), - "nom": field("name"), - "avg": avg("name"), - "count": count("name"), - "countD": count("DISTINCT(name)"), - "countD2": countDistinct("name"), - "x": distinct("name"), - "max": max("name"), + UserTable.name: show(), + UserTable.id: hide(), + "nom": field(UserTable.name), + "avg": avg(UserTable.age), + "count": count(UserTable.name), + "countD": count("DISTINCT(${UserTable.name})"), + "countD2": countDistinct(UserTable.name), + "x": distinct(UserTable.name), + "max": max(UserTable.age), }) ..include( - "profile", - on: "profileId", + profileTable, + on: UserTable.profileId, where: and([ - {"bio": notEq(null)}, - {"bio": notEq("")}, + {ProfileTable.bio: notEq(null)}, + {ProfileTable.bio: notEq("")}, ]), joinType: JoinOperation.left, ) - ..group("id") - ..sort({"name": 1}) + ..group(UserTable.id) + ..sort({UserTable.name: 1}) ..having(and([])) ..limit(10) ..skip(0); diff --git a/packages/arcade_orm/lib/src/query.dart b/packages/arcade_orm/lib/src/query.dart index f52b2d0..701a278 100644 --- a/packages/arcade_orm/lib/src/query.dart +++ b/packages/arcade_orm/lib/src/query.dart @@ -260,7 +260,7 @@ class ArcadeOrmTableFindOperator { } void include( - String tableName, { + ArcadeOrmTableSchema table, { String? on, String? as, Map? where, @@ -268,7 +268,7 @@ class ArcadeOrmTableFindOperator { }) { _includeParams.add( IncludeParam( - tableName, + table.tableName, on: on, as: as, where: where, @@ -410,15 +410,17 @@ class ArcadeOrmTableDeleteOperator { } void include( - String tableName, { + ArcadeOrmTableSchema table, { String? on, + String? as, Map? where, JoinOperation joinType = JoinOperation.inner, }) { _includeParams.add( IncludeParam( - tableName, + table.tableName, on: on, + as: as, where: where, joinType: joinType, ), diff --git a/packages/arcade_orm/lib/src/table.dart b/packages/arcade_orm/lib/src/table.dart index c027ee2..a10b06c 100644 --- a/packages/arcade_orm/lib/src/table.dart +++ b/packages/arcade_orm/lib/src/table.dart @@ -17,7 +17,7 @@ mixin ArcadeOrmTable { ArcadeOrmTableSchema getTable(String name) { try { - return _tables.firstWhere((element) => element.name == name); + return _tables.firstWhere((element) => element.tableName == name); } catch (e) { throw StateError( "Table ($name) not found. Please make sure table schema is initialized", @@ -26,25 +26,42 @@ mixin ArcadeOrmTable { } } +typedef ArcadeTableIndexRecord = (int direction, {bool? unique}); + +typedef ArcadeOrmRelationshipRecord = ({ + ArcadeOrmRelationshipType type, + String table, + String localKey, + String foreignKey, +}); + +enum ArcadeOrmRelationshipType { + hasOne, + hasMany, + belongsTo, + belongsToMany, +} + abstract class ArcadeOrmTableSchema { - final ArcadeOrm orm; - String get name; + late final ArcadeOrm $orm; + String get tableName; Map get schema; + Map get index => {}; + Map get relations => {}; - ArcadeOrmTableSchema(this.orm) { + ArcadeOrmTableSchema(ArcadeOrm orm) { + $orm = orm; orm._tables.add(this); } ArcadeOrmTransaction transaction() { - return orm.transaction(); + return $orm.transaction(); } - void index(Map config, {({bool? unique})? options}) {} - ArcadeOrmTableRawOperator raw({ArcadeOrmTransaction? transaction}) { return ArcadeOrmTableRawOperator( - orm: orm, + orm: $orm, operator: TableOperator.raw, transaction: transaction, ); @@ -52,7 +69,7 @@ abstract class ArcadeOrmTableSchema { ArcadeOrmTableFindOperator count({ArcadeOrmTransaction? transaction}) { return ArcadeOrmTableFindOperator( - orm: orm, + orm: $orm, operator: TableOperator.count, transaction: transaction, ); @@ -60,7 +77,7 @@ abstract class ArcadeOrmTableSchema { ArcadeOrmTableFindOperator findOne({ArcadeOrmTransaction? transaction}) { return ArcadeOrmTableFindOperator( - orm: orm, + orm: $orm, operator: TableOperator.findOne, transaction: transaction, ); @@ -68,7 +85,7 @@ abstract class ArcadeOrmTableSchema { ArcadeOrmTableFindOperator findMany({ArcadeOrmTransaction? transaction}) { return ArcadeOrmTableFindOperator( - orm: orm, + orm: $orm, operator: TableOperator.findMany, transaction: transaction, ); @@ -76,7 +93,7 @@ abstract class ArcadeOrmTableSchema { ArcadeOrmTableCreateOperator create({ArcadeOrmTransaction? transaction}) { return ArcadeOrmTableCreateOperator( - orm: orm, + orm: $orm, operator: TableOperator.create, transaction: transaction, ); @@ -84,7 +101,7 @@ abstract class ArcadeOrmTableSchema { ArcadeOrmTableUpdateOperator update({ArcadeOrmTransaction? transaction}) { return ArcadeOrmTableUpdateOperator( - orm: orm, + orm: $orm, operator: TableOperator.update, transaction: transaction, ); @@ -92,57 +109,84 @@ abstract class ArcadeOrmTableSchema { ArcadeOrmTableDeleteOperator delete({ArcadeOrmTransaction? transaction}) { return ArcadeOrmTableDeleteOperator( - orm: orm, + orm: $orm, operator: TableOperator.delete, transaction: transaction, ); } } -class ColumnMeta { - void nullable() { - // do something - } +abstract class ColumnMeta { + final bool isNullable; + const ColumnMeta({this.isNullable = false}); } -class ColumnInt extends ColumnMeta {} +class ColumnInt extends ColumnMeta { + const ColumnInt({super.isNullable}); +} -class ColumnIntRange extends ColumnMeta {} +class ColumnIntRange extends ColumnMeta { + const ColumnIntRange(); +} -class ColumnFloat extends ColumnMeta {} +class ColumnFloat extends ColumnMeta { + const ColumnFloat(); +} -class ColumnBool extends ColumnMeta {} +class ColumnBool extends ColumnMeta { + const ColumnBool(); +} class ColumnString extends ColumnMeta { final dynamic search; - ColumnString({this.search}); + const ColumnString({this.search}); } -class ColumnStringEnum extends ColumnMeta {} +class ColumnStringEnum extends ColumnMeta { + const ColumnStringEnum(); +} -class ColumnStringSet extends ColumnMeta {} +class ColumnStringSet extends ColumnMeta { + const ColumnStringSet(); +} -class ColumnBinary extends ColumnMeta {} +class ColumnBinary extends ColumnMeta { + const ColumnBinary(); +} -class ColumnDate extends ColumnMeta {} +class ColumnDate extends ColumnMeta { + const ColumnDate(); +} -class ColumnDateRange extends ColumnMeta {} +class ColumnDateRange extends ColumnMeta { + const ColumnDateRange(); +} -class ColumnJson extends ColumnMeta {} +class ColumnJson extends ColumnMeta { + const ColumnJson(); +} -class ColumnComposite extends ColumnMeta {} +class ColumnComposite extends ColumnMeta { + const ColumnComposite(); +} -class ColumnGeoJson extends ColumnMeta {} +class ColumnGeoJson extends ColumnMeta { + const ColumnGeoJson(); +} -class ColumnObjectId extends ColumnMeta {} +class ColumnObjectId extends ColumnMeta { + const ColumnObjectId(); +} -class ColumnArray extends ColumnMeta {} +class ColumnArray extends ColumnMeta { + const ColumnArray(); +} abstract interface class ColumnCustomDomain extends ColumnMeta {} class ColumnCustom extends ColumnMeta { final String raw; - ColumnCustom({required this.raw}); + const ColumnCustom({required this.raw}); } diff --git a/packages/arcade_orm/test/src/query/create_test.dart b/packages/arcade_orm/test/src/query/create_test.dart index 1994e8b..b5a2bbb 100644 --- a/packages/arcade_orm/test/src/query/create_test.dart +++ b/packages/arcade_orm/test/src/query/create_test.dart @@ -10,19 +10,19 @@ class UserTable extends ArcadeOrmTableSchema { UserTable(super.orm); @override - final String name = "user"; + final String tableName = "user"; static const String id = "id"; - static const String userName = "name"; + static const String name = "name"; static const String email = "email"; static const String age = "age"; @override Map schema = { - id: ColumnInt(), - userName: ColumnString(), - email: ColumnString(), - age: ColumnInt(), + id: const ColumnInt(), + name: const ColumnString(), + email: const ColumnString(), + age: const ColumnInt(), }; } diff --git a/packages/arcade_orm/test/src/query/delete_test.dart b/packages/arcade_orm/test/src/query/delete_test.dart index da2e605..6e9fd45 100644 --- a/packages/arcade_orm/test/src/query/delete_test.dart +++ b/packages/arcade_orm/test/src/query/delete_test.dart @@ -10,27 +10,33 @@ class UserTable extends ArcadeOrmTableSchema { UserTable(super.orm); @override - final String name = "user"; + final String tableName = "user"; static const String id = "id"; @override - Map schema = {id: ColumnInt()}; + Map schema = {id: const ColumnInt()}; + + @override + Map index = {}; + + @override + Map relations = {}; } class RoleTable extends ArcadeOrmTableSchema { RoleTable(super.orm); @override - final String name = "role"; + final String tableName = "role"; - static const String roleName = "name"; + static const String name = "name"; static const String foo = "foo"; @override Map schema = { - roleName: ColumnString(), - foo: ColumnString(), + name: const ColumnString(), + foo: const ColumnString(), }; } @@ -77,7 +83,7 @@ void main() { final roleTable = RoleTable(arcadeOrm); final deleteQuery = userTable.delete() - ..include(roleTable.name, where: {"name": notEq("admin")}) + ..include(roleTable, where: {"name": notEq("admin")}) ..where({"id": eq(1)}); await deleteQuery.exec(); From 0c8db3742e93bfafc433602486691f8d168faf00 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Thu, 21 Dec 2023 06:25:35 +0600 Subject: [PATCH 17/24] feat: create to insert --- packages/arcade_orm/example/api/basic.dart | 2 +- packages/arcade_orm/lib/src/adapter.dart | 2 +- packages/arcade_orm/lib/src/query.dart | 14 ++--- packages/arcade_orm/lib/src/table.dart | 6 +- .../test/src/query/delete_test.dart | 8 +-- .../{create_test.dart => insert_test.dart} | 56 +++++++++---------- 6 files changed, 44 insertions(+), 44 deletions(-) rename packages/arcade_orm/test/src/query/{create_test.dart => insert_test.dart} (71%) diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index 36e44aa..21fd097 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -39,7 +39,7 @@ class ArcadeOrmMockAdapter List groupParams = const [], List> sortParams = const [], List> updateWithParams = const [], - List> createWithParams = const [], + List> insertWithParams = const [], int? limit, int? skip, }) { diff --git a/packages/arcade_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart index 37f5a79..3987d1e 100644 --- a/packages/arcade_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -30,7 +30,7 @@ abstract interface class ArcadeOrmAdapterBase { List groupParams = const [], List> sortParams = const [], List> updateWithParams = const [], - List> createWithParams = const [], + List> insertWithParams = const [], int? limit, int? skip, }); diff --git a/packages/arcade_orm/lib/src/query.dart b/packages/arcade_orm/lib/src/query.dart index 701a278..d52fed0 100644 --- a/packages/arcade_orm/lib/src/query.dart +++ b/packages/arcade_orm/lib/src/query.dart @@ -314,16 +314,16 @@ class ArcadeOrmTableFindOperator { } } -class ArcadeOrmTableCreateOperator { +class ArcadeOrmTableInsertOperator { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; - final List> _createWithParams = []; + final List> _insertWithParams = []; bool _isExplain = false; - ArcadeOrmTableCreateOperator({ + ArcadeOrmTableInsertOperator({ required ArcadeOrm orm, required TableOperator operator, ArcadeOrmTransaction? transaction, @@ -331,8 +331,8 @@ class ArcadeOrmTableCreateOperator { _operator = operator, _orm = orm; - void createWith(Map value) { - _createWithParams.add(value); + void insertWith(Map value) { + _insertWithParams.add(value); } Future exec({ @@ -343,7 +343,7 @@ class ArcadeOrmTableCreateOperator { isExplain: _isExplain, operator: _operator, transaction: _transaction, - createWithParams: _createWithParams, + insertWithParams: _insertWithParams, ); final convertedData = await fromJson?.call(data); @@ -613,7 +613,7 @@ enum TableOperator { count, findOne, findMany, - create, + insert, update, delete, } diff --git a/packages/arcade_orm/lib/src/table.dart b/packages/arcade_orm/lib/src/table.dart index a10b06c..6cd01df 100644 --- a/packages/arcade_orm/lib/src/table.dart +++ b/packages/arcade_orm/lib/src/table.dart @@ -91,10 +91,10 @@ abstract class ArcadeOrmTableSchema { ); } - ArcadeOrmTableCreateOperator create({ArcadeOrmTransaction? transaction}) { - return ArcadeOrmTableCreateOperator( + ArcadeOrmTableInsertOperator insert({ArcadeOrmTransaction? transaction}) { + return ArcadeOrmTableInsertOperator( orm: $orm, - operator: TableOperator.create, + operator: TableOperator.insert, transaction: transaction, ); } diff --git a/packages/arcade_orm/test/src/query/delete_test.dart b/packages/arcade_orm/test/src/query/delete_test.dart index 6e9fd45..34676ed 100644 --- a/packages/arcade_orm/test/src/query/delete_test.dart +++ b/packages/arcade_orm/test/src/query/delete_test.dart @@ -100,7 +100,7 @@ void main() { groupParams: [], sortParams: [], updateWithParams: [], - createWithParams: [], + insertWithParams: [], ), ).captured; final capturedWhereParams = @@ -163,7 +163,7 @@ void main() { groupParams: [], sortParams: [], updateWithParams: [], - createWithParams: [], + insertWithParams: [], ), ).captured; @@ -195,8 +195,8 @@ void main() { adapter: mockAdapter, ); final table = UserTable(arcadeOrm); - final createQuery = table.delete()..where({"id": eq(1)}); - final data = await createQuery.exec(); + final deleteQuery = table.delete()..where({"id": eq(1)}); + final data = await deleteQuery.exec(); expect(data, isA()); expect((data as ExecResultFailure).exception.message, "Delete Failed"); }); diff --git a/packages/arcade_orm/test/src/query/create_test.dart b/packages/arcade_orm/test/src/query/insert_test.dart similarity index 71% rename from packages/arcade_orm/test/src/query/create_test.dart rename to packages/arcade_orm/test/src/query/insert_test.dart index b5a2bbb..c27d092 100644 --- a/packages/arcade_orm/test/src/query/create_test.dart +++ b/packages/arcade_orm/test/src/query/insert_test.dart @@ -29,7 +29,7 @@ class UserTable extends ArcadeOrmTableSchema { void main() { final mockAdapter = MockAdapter(); final mockTransaction = MockTransaction(); - group('create', () { + group('insert', () { setUp(() { when(() => mockAdapter.transaction()).thenReturn(mockTransaction); }); @@ -44,13 +44,13 @@ void main() { setUp(() { when( () => mockAdapter.operate( - operator: TableOperator.create, + operator: TableOperator.insert, transaction: null, isExplain: false, - createWithParams: any(named: "createWithParams"), + insertWithParams: any(named: "insertWithParams"), ), ).thenAnswer( - (_) => Future.value({"nCreated": 1}), + (_) => Future.value({"nInserted": 1}), ); }); @@ -65,13 +65,13 @@ void main() { adapter: mockAdapter, ); final table = UserTable(arcadeOrm); - final createQuery = table.create() - ..createWith({"name": "foo", "age": 20}) - ..createWith({"email": "foo@examle.com"}); - await createQuery.exec(); + final insertQuery = table.insert() + ..insertWith({"name": "foo", "age": 20}) + ..insertWith({"email": "foo@examle.com"}); + await insertQuery.exec(); verify( () => mockAdapter.operate( - operator: TableOperator.create, + operator: TableOperator.insert, transaction: null, isExplain: false, whereParams: [], @@ -81,7 +81,7 @@ void main() { groupParams: [], sortParams: [], updateWithParams: [], - createWithParams: [ + insertWithParams: [ {"name": "foo", "age": 20}, {"email": "foo@examle.com"}, ], @@ -94,12 +94,12 @@ void main() { adapter: mockAdapter, ); final table = UserTable(arcadeOrm); - final createQuery = table.create() - ..createWith({"name": "foo", "age": 20}) - ..createWith({"email": "foo@examle.com"}); - final data = await createQuery.exec(); + final insertQuery = table.insert() + ..insertWith({"name": "foo", "age": 20}) + ..insertWith({"email": "foo@examle.com"}); + final data = await insertQuery.exec(); expect(data, isA()); - expect((data as ExecResultData).data, equals({"nCreated": 1})); + expect((data as ExecResultData).data, equals({"nInserted": 1})); }); test("operate with transaction", () async { @@ -111,12 +111,12 @@ void main() { final table = UserTable(arcadeOrm); final trx = table.transaction(); await trx.start(); - final createQuery = table.create(transaction: trx) - ..createWith({"name": "foo", "age": 20}); - await createQuery.exec(); + final insertQuery = table.insert(transaction: trx) + ..insertWith({"name": "foo", "age": 20}); + await insertQuery.exec(); verify( () => mockAdapter.operate( - operator: TableOperator.create, + operator: TableOperator.insert, transaction: trx, isExplain: false, whereParams: [], @@ -126,7 +126,7 @@ void main() { groupParams: [], sortParams: [], updateWithParams: [], - createWithParams: [ + insertWithParams: [ {"name": "foo", "age": 20}, ], ), @@ -137,24 +137,24 @@ void main() { test("db record - failure", () async { when( () => mockAdapter.operate( - operator: TableOperator.create, + operator: TableOperator.insert, transaction: null, isExplain: false, - createWithParams: any(named: "createWithParams"), + insertWithParams: any(named: "insertWithParams"), ), ).thenThrow( - ArcadeOrmException(message: "Create Failed", originalError: null), + ArcadeOrmException(message: "Insert Failed", originalError: null), ); final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); final table = UserTable(arcadeOrm); - final createQuery = table.create() - ..createWith({"name": "foo", "age": 20}) - ..createWith({"email": "foo@examle.com"}); - final data = await createQuery.exec(); + final insertQuery = table.insert() + ..insertWith({"name": "foo", "age": 20}) + ..insertWith({"email": "foo@examle.com"}); + final data = await insertQuery.exec(); expect(data, isA()); - expect((data as ExecResultFailure).exception.message, "Create Failed"); + expect((data as ExecResultFailure).exception.message, "Insert Failed"); }); }); } From 1852f90e1a6f771eaddabbfa239351a84a560e95 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Fri, 22 Dec 2023 13:08:37 +0600 Subject: [PATCH 18/24] feat: updated where implementation --- packages/arcade_orm/example/api/basic.dart | 46 +- packages/arcade_orm/lib/src/adapter.dart | 7 +- packages/arcade_orm/lib/src/query.dart | 350 +-------------- .../arcade_orm/lib/src/query/include.dart | 31 ++ .../lib/src/query/mixins/where.dart | 14 + packages/arcade_orm/lib/src/query/select.dart | 89 ++++ packages/arcade_orm/lib/src/query/where.dart | 411 ++++++++++++++++++ .../test/src/query/delete_test.dart | 74 +++- .../test/src/query/insert_test.dart | 6 +- .../test/src/query/update_test.dart | 150 +++++++ 10 files changed, 791 insertions(+), 387 deletions(-) create mode 100644 packages/arcade_orm/lib/src/query/include.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/where.dart create mode 100644 packages/arcade_orm/lib/src/query/select.dart create mode 100644 packages/arcade_orm/lib/src/query/where.dart create mode 100644 packages/arcade_orm/test/src/query/update_test.dart diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index 21fd097..e523b10 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -1,6 +1,9 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; +import 'package:arcade_orm/src/query/include.dart'; +import 'package:arcade_orm/src/query/select.dart'; +import 'package:arcade_orm/src/query/where.dart'; typedef OptionsRecord = ({String? name, String? host, int? port}); @@ -25,27 +28,6 @@ class ArcadeOrmMockAdapter throw UnimplementedError(); } - @override - Future> operate({ - required TableOperator operator, - required ArcadeOrmTransaction? transaction, - required bool isExplain, - String? rawSql, - Map? rawNoSql, - List> whereParams = const [], - List> havingParams = const [], - List> selectParams = const [], - List includeParams = const [], - List groupParams = const [], - List> sortParams = const [], - List> updateWithParams = const [], - List> insertWithParams = const [], - int? limit, - int? skip, - }) { - throw UnimplementedError(); - } - @override ArcadeOrmTransaction transaction() { // TODO: implement transaction @@ -62,6 +44,27 @@ class ArcadeOrmMockAdapter // TODO: implement close throw UnimplementedError(); } + + @override + Future> operate( + {required TableOperator operator, + required ArcadeOrmTransaction? transaction, + required bool isExplain, + String? rawSql, + Map? rawNoSql, + WhereExpressionNode? whereParams, + WhereExpressionNode? havingParams, + List> selectParams = const [], + List includeParams = const [], + List groupParams = const [], + List> sortParams = const [], + List> updateWithParams = const [], + List> insertWithParams = const [], + int? limit, + int? skip}) { + // TODO: implement operate + throw UnimplementedError(); + } } class UserTable extends ArcadeOrmTableSchema { @@ -179,7 +182,6 @@ Future orming() async { ) ..group(UserTable.id) ..sort({UserTable.name: 1}) - ..having(and([])) ..limit(10) ..skip(0); diff --git a/packages/arcade_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart index 3987d1e..96bc0b7 100644 --- a/packages/arcade_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -1,6 +1,9 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; +import 'package:arcade_orm/src/query/include.dart'; +import 'package:arcade_orm/src/query/select.dart'; +import 'package:arcade_orm/src/query/where.dart'; import 'package:meta/meta.dart'; abstract interface class ArcadeOrmAdapterBase { @@ -23,8 +26,8 @@ abstract interface class ArcadeOrmAdapterBase { required bool isExplain, String? rawSql, Map? rawNoSql, - List> whereParams = const [], - List> havingParams = const [], + WhereExpressionNode? whereParams, + WhereExpressionNode? havingParams, List> selectParams = const [], List includeParams = const [], List groupParams = const [], diff --git a/packages/arcade_orm/lib/src/query.dart b/packages/arcade_orm/lib/src/query.dart index d52fed0..c8260b6 100644 --- a/packages/arcade_orm/lib/src/query.dart +++ b/packages/arcade_orm/lib/src/query.dart @@ -1,204 +1,17 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; +import 'package:arcade_orm/src/query/include.dart'; +import 'package:arcade_orm/src/query/mixins/where.dart'; +import 'package:arcade_orm/src/query/select.dart'; +import 'package:arcade_orm/src/query/where.dart'; -const dAnd = r'$__AND'; -const dOr = r'$__OR'; - -Map and(List> value) { - final List> whereParamList = []; - for (final element in value) { - element.forEach((key, _) { - if (element[key] != null) { - element[key]!.param.isAnd = true; - element[key]!.param.isOr = false; - whereParamList.add({key: element[key]!.param}); - } - }); - } - return {dAnd: MultipleWhereParam(whereParamList)}; -} - -Map or(List> value) { - final List> whereParamList = []; - for (final element in value) { - element.forEach((key, _) { - if (element[key] != null) { - element[key]!.param.isAnd = false; - element[key]!.param.isOr = true; - whereParamList.add({key: element[key]!.param}); - } - }); - } - return {dOr: MultipleWhereParam(whereParamList)}; -} - -SingleWhereParam array(T value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.array, - value: value, - ), - ); -} - -SingleWhereParam between(T start, T end) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.between, - start: start, - end: end, - ), - ); -} - -SingleWhereParam eq(T value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.eq, - value: value, - ), - ); -} - -SingleWhereParam gt(T value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.gt, - value: value, - ), - ); -} - -SingleWhereParam gte(T value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.gte, - value: value, - ), - ); -} - -SingleWhereParam like(String value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.like, - value: value, - ), - ); -} - -SingleWhereParam lt(T value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.lt, - value: value, - ), - ); -} - -SingleWhereParam lte(T value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.lte, - value: value, - ), - ); -} - -SingleWhereParam notInArray(T value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.notInArray, - value: value, - ), - ); -} - -SingleWhereParam notEq(T value) { - return SingleWhereParam( - WhereParam( - operator: WhereOperator.notEq, - value: value, - ), - ); -} - -SelectParam avg(String value) { - return SelectParam( - operator: SelectAggregationOperator.avg, - fieldAs: value, - ); -} - -SelectParam count(String value) { - return SelectParam( - operator: SelectAggregationOperator.count, - fieldAs: value, - ); -} - -SelectParam countDistinct(String value) { - return SelectParam( - operator: SelectAggregationOperator.countDistinct, - fieldAs: value, - ); -} - -SelectParam distinct(String value) { - return SelectParam( - operator: SelectAggregationOperator.distinct, - fieldAs: value, - ); -} - -SelectParam field(String value) { - return SelectParam( - operator: SelectAggregationOperator.show, - fieldAs: value, - ); -} - -SelectParam hide() { - return SelectParam( - operator: SelectAggregationOperator.hide, - ); -} - -SelectParam max(String value) { - return SelectParam( - operator: SelectAggregationOperator.max, - fieldAs: value, - ); -} - -SelectParam min(String value) { - return SelectParam( - operator: SelectAggregationOperator.min, - fieldAs: value, - ); -} - -SelectParam show() { - return SelectParam( - operator: SelectAggregationOperator.show, - ); -} - -SelectParam sum(String value) { - return SelectParam( - operator: SelectAggregationOperator.sum, - fieldAs: value, - ); -} - -class ArcadeOrmTableFindOperator { +class ArcadeOrmTableFindOperator with WhereMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; - final List> _whereParams = []; - final List> _havingParams = []; + // final List> _havingParams = []; final List _includeParams = []; final List _groupParams = []; final List> _sortParams = []; @@ -225,10 +38,10 @@ class ArcadeOrmTableFindOperator { isExplain: _isExplain, operator: _operator, transaction: _transaction, - whereParams: _whereParams, + whereParams: $whereParams?.simplify(), includeParams: _includeParams, selectParams: _selectParams, - havingParams: _havingParams, + // havingParams: _havingParams, groupParams: _groupParams, sortParams: _sortParams, limit: _limit, @@ -255,9 +68,9 @@ class ArcadeOrmTableFindOperator { _groupParams.add(column); } - void having(Map map) { - _whereParams.add(WhereParam.evaluateWhereParams(map)); - } + // void having(Map map) { + // _whereParams.add(WhereParam.evaluateWhereParams(map)); + // } void include( ArcadeOrmTableSchema table, { @@ -308,10 +121,6 @@ class ArcadeOrmTableFindOperator { sortBy.map((key, value) => MapEntry(key, value > 0 ? 1 : -1)); _sortParams.add(sortValue); } - - void where(Map map) { - _whereParams.add(WhereParam.evaluateWhereParams(map)); - } } class ArcadeOrmTableInsertOperator { @@ -363,12 +172,11 @@ class ArcadeOrmTableInsertOperator { } } -class ArcadeOrmTableDeleteOperator { +class ArcadeOrmTableDeleteOperator with WhereMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; - final List> _whereParams = []; final List _includeParams = []; bool _isExplain = false; @@ -389,7 +197,7 @@ class ArcadeOrmTableDeleteOperator { isExplain: _isExplain, operator: _operator, transaction: _transaction, - whereParams: _whereParams, + whereParams: $whereParams?.simplify(), includeParams: _includeParams, ); @@ -426,10 +234,6 @@ class ArcadeOrmTableDeleteOperator { ), ); } - - void where(Map map) { - _whereParams.add(WhereParam.evaluateWhereParams(map)); - } } class ArcadeOrmTableRawOperator { @@ -489,13 +293,12 @@ class ArcadeOrmTableRawOperator { } } -class ArcadeOrmTableUpdateOperator { +class ArcadeOrmTableUpdateOperator with WhereMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; final List> _updateWithParams = []; - final List> _whereParams = []; bool _isExplain = false; @@ -515,7 +318,7 @@ class ArcadeOrmTableUpdateOperator { isExplain: _isExplain, operator: _operator, transaction: _transaction, - whereParams: _whereParams, + whereParams: $whereParams?.simplify(), updateWithParams: _updateWithParams, ); @@ -538,10 +341,6 @@ class ArcadeOrmTableUpdateOperator { void updateWith(Map value) { _updateWithParams.add(value); } - - void where(Map map) { - _whereParams.add(WhereParam.evaluateWhereParams(map)); - } } sealed class ExecResult {} @@ -558,56 +357,6 @@ class ExecResultFailure extends ExecResult { ExecResultFailure(this.exception); } -class IncludeParam { - final String tableName; - final String? on; - final String? as; - final JoinOperation joinType; - Map? where; - IncludeParam( - this.tableName, { - this.on, - this.as, - this.joinType = JoinOperation.inner, - Map? where, - }) { - Map? value; - if (where != null) { - value = WhereParam.evaluateWhereParams(where); - } - this.where = value; - } -} - -enum JoinOperation { - inner, - left, - right, - cross, -} - -enum SelectAggregationOperator { - show, - hide, - count, - sum, - avg, - min, - max, - distinct, - countDistinct, -} - -class SelectParam { - String? fieldAs; - final SelectAggregationOperator operator; - - SelectParam({ - required this.operator, - this.fieldAs, - }); -} - enum TableOperator { raw, count, @@ -617,72 +366,3 @@ enum TableOperator { update, delete, } - -enum WhereOperator { - eq, - gt, - gte, - lt, - lte, - between, - notEq, - like, - array, - notInArray, - and, - or, -} - -sealed class WhereParamBuilder {} - -class SingleWhereParam extends WhereParamBuilder { - final WhereParam param; - - SingleWhereParam(this.param); -} - -class MultipleWhereParam extends WhereParamBuilder { - final List> param; - - MultipleWhereParam(this.param); -} - -class WhereParam { - final WhereOperator operator; - final T? value; - final T? start; - final T? end; - bool isAnd = true; - bool isOr = false; - - WhereParam({ - required this.operator, - this.value, - this.start, - this.end, - }); - - static Map evaluateWhereParams( - Map map, - ) { - Map value = {}; - - if (map.containsKey(dAnd)) { - final multiple = map[dAnd]! as MultipleWhereParam; - for (final element in multiple.param) { - value = element; - } - } else if (map.containsKey(dOr)) { - final multiple = map[dOr]! as MultipleWhereParam; - for (final element in multiple.param) { - value = element; - } - } else { - value = map.map( - (key, v) => MapEntry(key, (v as SingleWhereParam).param), - ); - } - - return value; - } -} diff --git a/packages/arcade_orm/lib/src/query/include.dart b/packages/arcade_orm/lib/src/query/include.dart new file mode 100644 index 0000000..2c65406 --- /dev/null +++ b/packages/arcade_orm/lib/src/query/include.dart @@ -0,0 +1,31 @@ +import 'package:arcade_orm/src/query/where.dart'; + +enum JoinOperation { + inner, + left, + right, + cross, +} + +class IncludeParam { + final String tableName; + final String? on; + final String? as; + final JoinOperation joinType; + WhereExpressionNode? where; + IncludeParam( + this.tableName, { + this.on, + this.as, + this.joinType = JoinOperation.inner, + Map? where, + }) { + final value = WhereParamBuilder.root(null); + if (where != null) { + for (final element in where.entries) { + value.addNode(element.value, element.key); + } + this.where = value.simplify(); + } + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/where.dart b/packages/arcade_orm/lib/src/query/mixins/where.dart new file mode 100644 index 0000000..1f2b097 --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/where.dart @@ -0,0 +1,14 @@ +import 'package:arcade_orm/src/query/where.dart'; +import 'package:meta/meta.dart'; + +mixin WhereMixin { + @protected + WhereExpressionOperatorNode? $whereParams; + + void where(Map map) { + $whereParams ??= WhereParamBuilder.root(null); + for (final entry in map.entries) { + $whereParams!.addNode(entry.value, entry.key); + } + } +} diff --git a/packages/arcade_orm/lib/src/query/select.dart b/packages/arcade_orm/lib/src/query/select.dart new file mode 100644 index 0000000..582e19c --- /dev/null +++ b/packages/arcade_orm/lib/src/query/select.dart @@ -0,0 +1,89 @@ +enum SelectAggregationOperator { + show, + hide, + count, + sum, + avg, + min, + max, + distinct, + countDistinct, +} + +class SelectParam { + String? fieldAs; + final SelectAggregationOperator operator; + + SelectParam({ + required this.operator, + this.fieldAs, + }); +} + +SelectParam avg(String value) { + return SelectParam( + operator: SelectAggregationOperator.avg, + fieldAs: value, + ); +} + +SelectParam count(String value) { + return SelectParam( + operator: SelectAggregationOperator.count, + fieldAs: value, + ); +} + +SelectParam countDistinct(String value) { + return SelectParam( + operator: SelectAggregationOperator.countDistinct, + fieldAs: value, + ); +} + +SelectParam distinct(String value) { + return SelectParam( + operator: SelectAggregationOperator.distinct, + fieldAs: value, + ); +} + +SelectParam field(String value) { + return SelectParam( + operator: SelectAggregationOperator.show, + fieldAs: value, + ); +} + +SelectParam hide() { + return SelectParam( + operator: SelectAggregationOperator.hide, + ); +} + +SelectParam max(String value) { + return SelectParam( + operator: SelectAggregationOperator.max, + fieldAs: value, + ); +} + +SelectParam min(String value) { + return SelectParam( + operator: SelectAggregationOperator.min, + fieldAs: value, + ); +} + +SelectParam show() { + return SelectParam( + operator: SelectAggregationOperator.show, + ); +} + +SelectParam sum(String value) { + return SelectParam( + operator: SelectAggregationOperator.sum, + fieldAs: value, + ); +} diff --git a/packages/arcade_orm/lib/src/query/where.dart b/packages/arcade_orm/lib/src/query/where.dart new file mode 100644 index 0000000..2ba8238 --- /dev/null +++ b/packages/arcade_orm/lib/src/query/where.dart @@ -0,0 +1,411 @@ +const dAnd = r'$__AND'; +const dOr = r'$__OR'; + +enum WhereExpressionOperator { + and(dAnd), + or(dOr); + + final String name; + + const WhereExpressionOperator(this.name); +} + +sealed class WhereParamBuilder { + WhereParamBuilder(); + + // ignore: prefer_constructors_over_static_methods + static WhereExpressionOperatorNode root(WhereExpressionOperatorNode? node) { + return node ?? + WhereExpressionOperatorNode( + operator: WhereExpressionOperator.and, + nodes: [], + ); + } +} + +class WhereParam extends WhereParamBuilder { + final WhereOperator operator; + final T? value; + final T? start; + final T? end; + + WhereParam({ + required this.operator, + this.value, + this.start, + this.end, + }); + + @override + bool operator ==(Object other) => + other is WhereParam && + other.runtimeType == runtimeType && + other.operator == operator && + other.value == value && + other.start == start && + other.end == end; + + @override + int get hashCode => Object.hash(operator, value, start, end); +} + +sealed class WhereExpressionNode extends WhereParamBuilder { + List nodes; + + WhereExpressionNode({ + this.nodes = const [], + }); + + void addNode( + WhereParamBuilder node, [ + String? field, + ]) { + if (this is WhereExpressionCompareNode) { + throw StateError('Cannot add node to compare node'); + } + if (this is WhereParam) { + throw StateError('Cannot add node to where param'); + } + if (this is WhereExpressionOperatorNode) { + if (node is WhereExpressionOperatorNode) { + if (node.operator == (this as WhereExpressionOperatorNode).operator) { + nodes.addAll(node.nodes); + return; + } + nodes.add(node); + return; + } + if (node is WhereExpressionCompareNode) { + nodes.add(node); + return; + } + if (node is WhereParam) { + if (field == null) { + throw StateError('Field cannot be null for WhereParam'); + } + nodes.add( + WhereExpressionCompareNode( + field: field, + param: node, + ), + ); + } + } + } + + WhereExpressionNode simplify() { + if (nodes.length == 1) { + return nodes.first; + } + if (nodes.length > 1) { + bool isSame = true; + WhereExpressionOperator? operator; + for (final node in nodes) { + if (node is WhereExpressionOperatorNode) { + if (operator == null) { + operator = node.operator; + } else if (operator != node.operator) { + isSame = false; + break; + } + } else { + isSame = false; + break; + } + } + if (isSame && operator != null) { + final simplifiedNodes = nodes.fold>( + [], + (previousValue, element) { + previousValue.addAll(element.nodes); + return previousValue; + }, + ); + return WhereExpressionOperatorNode( + operator: operator, + nodes: simplifiedNodes, + ); + } + } + return this; + } + + Map toMap(); +} + +extension MapParse on List { + List> toMap() { + // turn list into map + return fold>>( + [], + (previousValue, element) { + if (element is WhereExpressionCompareNode) { + previousValue.add({element.field: element.param}); + } else if (element is WhereExpressionOperatorNode) { + previousValue.add({element.operator.name: element.nodes.toMap()}); + } + return previousValue; + }, + ); + } +} + +class WhereExpressionOperatorNode extends WhereExpressionNode { + final WhereExpressionOperator operator; + WhereExpressionOperatorNode({ + required this.operator, + required super.nodes, + }); + + @override + Map>> toMap() { + return {operator.name: nodes.toMap()}; + } +} + +class WhereExpressionCompareNode extends WhereExpressionNode { + final String field; + final WhereParam param; + WhereExpressionCompareNode({ + required this.field, + required this.param, + }); + + @override + Map toMap() { + return {field: param}; + } +} + +enum WhereOperator { + eq, + gt, + gte, + lt, + lte, + between, + notEq, + like, + array, + notInArray, + and, + or, +} + +Map and(List> input) { + return { + dAnd: WhereExpressionOperatorNode( + operator: WhereExpressionOperator.and, + nodes: _getNodesFromMap(input), + ), + }; +} + +Map or(List> input) { + return { + dOr: WhereExpressionOperatorNode( + operator: WhereExpressionOperator.or, + nodes: _getNodesFromMap(input), + ), + }; +} + +List _getNodesFromMap( + List> value, +) { + final List nodes = []; + + for (final item in value) { + for (final entry in item.entries) { + nodes.add( + WhereExpressionCompareNode( + field: entry.key, + param: entry.value, + ), + ); + } + } + + return nodes; +} + +WhereParam array(T value) { + return WhereParam( + operator: WhereOperator.array, + value: value, + ); +} + +WhereParam between(T start, T end) { + return WhereParam( + operator: WhereOperator.between, + start: start, + end: end, + ); +} + +WhereParam eq(T value) { + return WhereParam( + operator: WhereOperator.eq, + value: value, + ); +} + +WhereParam gt(T value) { + return WhereParam( + operator: WhereOperator.gt, + value: value, + ); +} + +WhereParam gte(T value) { + return WhereParam( + operator: WhereOperator.gte, + value: value, + ); +} + +WhereParam like(String value) { + return WhereParam( + operator: WhereOperator.like, + value: value, + ); +} + +WhereParam lt(T value) { + return WhereParam( + operator: WhereOperator.lt, + value: value, + ); +} + +WhereParam lte(T value) { + return WhereParam( + operator: WhereOperator.lte, + value: value, + ); +} + +WhereParam notInArray(T value) { + return WhereParam( + operator: WhereOperator.notInArray, + value: value, + ); +} + +WhereParam notEq(T value) { + return WhereParam( + operator: WhereOperator.notEq, + value: value, + ); +} + +// WhereExpressionNode test1() { +// // where A = 1 +// final rootNode = WhereExpressionOperatorNode( +// operator: WhereExpressionOperator.and, +// nodes: [], +// ); + +// rootNode.addNode( +// WhereExpressionCompareNode( +// field: 'A', +// param: eq(1), +// ), +// ); + +// return rootNode.simplify(); +// } + +// WhereExpressionNode test2() { +// // where A = 1 and A = 2 and B = 3 +// final rootNode = WhereExpressionOperatorNode( +// operator: WhereExpressionOperator.and, +// nodes: [], +// ); + +// rootNode.addNode( +// WhereExpressionCompareNode( +// field: 'A', +// param: eq(1), +// ), +// ); + +// rootNode.addNode( +// WhereExpressionCompareNode( +// field: 'A', +// param: eq(2), +// ), +// ); + +// rootNode.addNode( +// WhereExpressionCompareNode( +// field: 'B', +// param: eq(3), +// ), +// ); + +// return rootNode.simplify(); +// } + +// WhereExpressionNode test3() { +// // where (A = 1 or A = 2) and A = 3 and B = 2 +// final rootNode = WhereExpressionOperatorNode( +// operator: WhereExpressionOperator.and, +// nodes: [], +// ); + +// rootNode.addNode( +// or([ +// {'A': eq(1)}, +// {'A': eq(2)}, +// ]), +// ); + +// rootNode.addNode( +// and([ +// { +// 'A': eq(3), +// 'B': eq(2), +// }, +// ]), +// ); + +// return rootNode.simplify(); +// } + +// WhereExpressionNode test4() { +// // where A = 1 or A = 2 or B = 2 or B = 3 or A = 3 or B = 4 +// final rootNode = WhereExpressionOperatorNode( +// operator: WhereExpressionOperator.and, +// nodes: [], +// ); + +// rootNode.addNode( +// or([ +// {'A': eq(1)}, +// {'A': eq(2)}, +// {'B': eq(2)}, +// ]), +// ); + +// rootNode.addNode( +// or([ +// {'B': eq(3)}, +// ]), +// ); + +// rootNode.addNode( +// or([ +// {'A': eq(3)}, +// ]), +// ); + +// rootNode.addNode( +// or([ +// {'B': eq(4)}, +// ]), +// ); + +// return rootNode.simplify(); +// } diff --git a/packages/arcade_orm/test/src/query/delete_test.dart b/packages/arcade_orm/test/src/query/delete_test.dart index 34676ed..fc4db53 100644 --- a/packages/arcade_orm/test/src/query/delete_test.dart +++ b/packages/arcade_orm/test/src/query/delete_test.dart @@ -1,4 +1,6 @@ import 'package:arcade_orm/arcade_orm.dart'; +import 'package:arcade_orm/src/query/include.dart'; +import 'package:arcade_orm/src/query/where.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; @@ -75,7 +77,7 @@ void main() { reset(mockTransaction); }); - test("operate", () async { + test("operate where", () async { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); @@ -94,9 +96,9 @@ void main() { transaction: null, isExplain: false, whereParams: captureAny(named: "whereParams"), - havingParams: [], + // havingParams: [], selectParams: [], - includeParams: captureAny(named: "includeParams"), + includeParams: any(named: "includeParams"), groupParams: [], sortParams: [], updateWithParams: [], @@ -104,24 +106,52 @@ void main() { ), ).captured; final capturedWhereParams = - (captured.first as List>).first['id']; + (captured.first as WhereExpressionNode).toMap(); expect( - capturedWhereParams?.value, - equals(1), + capturedWhereParams["id"], + equals(WhereParam(operator: WhereOperator.eq, value: 1)), ); - expect( - capturedWhereParams?.operator, - equals(WhereOperator.eq), + }); + + test("operate include", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, ); - final capturedIncludeParams = (captured[1] as List).first; + final userTable = UserTable(arcadeOrm); + final roleTable = RoleTable(arcadeOrm); + + final deleteQuery = userTable.delete() + ..include(roleTable, where: {"name": notEq("admin")}) + ..where({"id": eq(1)}); + + await deleteQuery.exec(); + + final captured = verify( + () => mockAdapter.operate( + operator: TableOperator.delete, + transaction: null, + isExplain: false, + whereParams: any(named: "whereParams"), + // havingParams: [], + selectParams: [], + includeParams: captureAny(named: "includeParams"), + groupParams: [], + sortParams: [], + updateWithParams: [], + insertWithParams: [], + ), + ).captured; + final capturedIncludeParams = + (captured.first as List).first; expect(capturedIncludeParams.tableName, equals("role")); expect( - capturedIncludeParams.where?["name"]?.operator, - equals(WhereOperator.notEq), - ); - expect( - capturedIncludeParams.where?["name"]?.value, - equals("admin"), + capturedIncludeParams.where?.toMap()["name"], + equals( + WhereParam( + operator: WhereOperator.notEq, + value: "admin", + ), + ), ); expect(capturedIncludeParams.as, equals(null)); expect(capturedIncludeParams.on, equals(null)); @@ -157,7 +187,7 @@ void main() { transaction: trx, isExplain: false, whereParams: captureAny(named: "whereParams"), - havingParams: [], + // havingParams: [], selectParams: [], includeParams: [], groupParams: [], @@ -168,14 +198,10 @@ void main() { ).captured; final capturedWhereParams = - (captured.first as List>).first['id']; - expect( - capturedWhereParams?.value, - equals(1), - ); + (captured.first as WhereExpressionNode).toMap(); expect( - capturedWhereParams?.operator, - equals(WhereOperator.eq), + capturedWhereParams["id"], + equals(WhereParam(operator: WhereOperator.eq, value: 1)), ); }); }); diff --git a/packages/arcade_orm/test/src/query/insert_test.dart b/packages/arcade_orm/test/src/query/insert_test.dart index c27d092..459b060 100644 --- a/packages/arcade_orm/test/src/query/insert_test.dart +++ b/packages/arcade_orm/test/src/query/insert_test.dart @@ -74,8 +74,7 @@ void main() { operator: TableOperator.insert, transaction: null, isExplain: false, - whereParams: [], - havingParams: [], + // havingParams: [], selectParams: [], includeParams: [], groupParams: [], @@ -119,8 +118,7 @@ void main() { operator: TableOperator.insert, transaction: trx, isExplain: false, - whereParams: [], - havingParams: [], + // havingParams: [], selectParams: [], includeParams: [], groupParams: [], diff --git a/packages/arcade_orm/test/src/query/update_test.dart b/packages/arcade_orm/test/src/query/update_test.dart new file mode 100644 index 0000000..d96a930 --- /dev/null +++ b/packages/arcade_orm/test/src/query/update_test.dart @@ -0,0 +1,150 @@ +import 'package:arcade_orm/arcade_orm.dart'; +import 'package:arcade_orm/src/query/where.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class MockAdapter extends Mock implements ArcadeOrmAdapterBase {} + +class MockTransaction extends Mock implements ArcadeOrmTransaction {} + +class UserTable extends ArcadeOrmTableSchema { + UserTable(super.orm); + + @override + final String tableName = "user"; + + static const String id = "id"; + static const String name = "name"; + static const String email = "email"; + static const String age = "age"; + + @override + Map schema = { + id: const ColumnInt(), + name: const ColumnString(), + email: const ColumnString(), + age: const ColumnInt(), + }; +} + +void main() { + final mockAdapter = MockAdapter(); + final mockTransaction = MockTransaction(); + + group('update', () { + setUp(() { + when(() => mockAdapter.transaction()).thenReturn(mockTransaction); + }); + + tearDown(() { + clearOrms(); + reset(mockAdapter); + reset(mockTransaction); + }); + + group("success", () { + setUp(() { + when( + () => mockAdapter.operate( + operator: TableOperator.update, + transaction: null, + isExplain: false, + updateWithParams: any(named: "updateWithParams"), + ), + ).thenAnswer( + (_) => Future.value({"nUpdated": 1}), + ); + }); + + tearDown(() { + clearOrms(); + reset(mockAdapter); + reset(mockTransaction); + }); + + test("operate", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = UserTable(arcadeOrm); + final updateQuery = table.update() + ..where( + and([ + { + UserTable.name: eq("bar"), + UserTable.age: gt(20), + } + ]), + ) + ..updateWith({ + UserTable.name: "foo", + UserTable.age: 20, + }); + + await updateQuery.exec(); + + final captured = verify( + () => mockAdapter.operate( + operator: TableOperator.update, + transaction: null, + isExplain: false, + whereParams: captureAny(named: "whereParams"), + // havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: captureAny(named: "updateWithParams"), + insertWithParams: [], + ), + ).captured; + + print((captured[1] as WhereExpressionNode).toMap()); + }); + + // test("data", () async { + // final arcadeOrm = await ArcadeOrm.init( + // adapter: mockAdapter, + // ); + // final table = UserTable(arcadeOrm); + // final insertQuery = table.insert() + // ..insertWith({"name": "foo", "age": 20}) + // ..insertWith({"email": "foo@examle.com"}); + // final data = await insertQuery.exec(); + // expect(data, isA()); + // expect((data as ExecResultData).data, equals({"nInserted": 1})); + // }); + + // test("operate with transaction", () async { + // when(() => mockTransaction.start()) + // .thenAnswer((_) async => Future.value()); + // final arcadeOrm = await ArcadeOrm.init( + // adapter: mockAdapter, + // ); + // final table = UserTable(arcadeOrm); + // final trx = table.transaction(); + // await trx.start(); + // final insertQuery = table.insert(transaction: trx) + // ..insertWith({"name": "foo", "age": 20}); + // await insertQuery.exec(); + // verify( + // () => mockAdapter.operate( + // operator: TableOperator.insert, + // transaction: trx, + // isExplain: false, + // whereParams: [], + // havingParams: [], + // selectParams: [], + // includeParams: [], + // groupParams: [], + // sortParams: [], + // updateWithParams: [], + // insertWithParams: [ + // {"name": "foo", "age": 20}, + // ], + // ), + // ).called(1); + // }); + }); + }); +} From a5f99172cffacd2b9359862ad6f1878ffcf272df Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Fri, 22 Dec 2023 14:12:44 +0600 Subject: [PATCH 19/24] feat: moved to mixins --- packages/arcade_orm/lib/src/adapter.dart | 3 +- packages/arcade_orm/lib/src/query.dart | 200 ++++-------------- .../lib/src/query/mixins/explain.dart | 9 + .../lib/src/query/mixins/group.dart | 9 + .../lib/src/query/mixins/include.dart | 27 +++ .../lib/src/query/mixins/insert.dart | 10 + .../lib/src/query/mixins/pagination.dart | 31 +++ .../arcade_orm/lib/src/query/mixins/raw.dart | 18 ++ .../lib/src/query/mixins/select.dart | 10 + .../arcade_orm/lib/src/query/mixins/sort.dart | 11 + .../lib/src/query/mixins/update.dart | 10 + 11 files changed, 175 insertions(+), 163 deletions(-) create mode 100644 packages/arcade_orm/lib/src/query/mixins/explain.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/group.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/include.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/insert.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/pagination.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/raw.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/select.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/sort.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/update.dart diff --git a/packages/arcade_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart index 96bc0b7..26c5a2d 100644 --- a/packages/arcade_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; import 'package:arcade_orm/src/query/include.dart'; +import 'package:arcade_orm/src/query/mixins/sort.dart'; import 'package:arcade_orm/src/query/select.dart'; import 'package:arcade_orm/src/query/where.dart'; import 'package:meta/meta.dart'; @@ -31,7 +32,7 @@ abstract interface class ArcadeOrmAdapterBase { List> selectParams = const [], List includeParams = const [], List groupParams = const [], - List> sortParams = const [], + List> sortParams = const [], List> updateWithParams = const [], List> insertWithParams = const [], int? limit, diff --git a/packages/arcade_orm/lib/src/query.dart b/packages/arcade_orm/lib/src/query.dart index c8260b6..65b814f 100644 --- a/packages/arcade_orm/lib/src/query.dart +++ b/packages/arcade_orm/lib/src/query.dart @@ -1,27 +1,30 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; -import 'package:arcade_orm/src/query/include.dart'; +import 'package:arcade_orm/src/query/mixins/explain.dart'; +import 'package:arcade_orm/src/query/mixins/group.dart'; +import 'package:arcade_orm/src/query/mixins/include.dart'; +import 'package:arcade_orm/src/query/mixins/insert.dart'; +import 'package:arcade_orm/src/query/mixins/pagination.dart'; +import 'package:arcade_orm/src/query/mixins/raw.dart'; +import 'package:arcade_orm/src/query/mixins/select.dart'; +import 'package:arcade_orm/src/query/mixins/sort.dart'; +import 'package:arcade_orm/src/query/mixins/update.dart'; import 'package:arcade_orm/src/query/mixins/where.dart'; -import 'package:arcade_orm/src/query/select.dart'; -import 'package:arcade_orm/src/query/where.dart'; -class ArcadeOrmTableFindOperator with WhereMixin { +class ArcadeOrmTableFindOperator + with + SelectMixin, + WhereMixin, + GroupMixin, + PaginationMixin, + SortMixin, + IncludeMixin, + ExplainMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; - // final List> _havingParams = []; - final List _includeParams = []; - final List _groupParams = []; - final List> _sortParams = []; - final List> _selectParams = []; - - int? _limit; - int? _skip; - - bool _isExplain = false; - ArcadeOrmTableFindOperator({ required ArcadeOrm orm, required TableOperator operator, @@ -35,17 +38,17 @@ class ArcadeOrmTableFindOperator with WhereMixin { }) async { try { final data = await _orm.adapter.operate( - isExplain: _isExplain, + isExplain: $explain, operator: _operator, transaction: _transaction, whereParams: $whereParams?.simplify(), - includeParams: _includeParams, - selectParams: _selectParams, + includeParams: $includeParams, + selectParams: $selectParams, // havingParams: _havingParams, - groupParams: _groupParams, - sortParams: _sortParams, - limit: _limit, - skip: _skip, + groupParams: $groupParams, + sortParams: $sortParams, + limit: $limit, + skip: $skip, ); final convertedData = await fromJson?.call(data); @@ -60,78 +63,16 @@ class ArcadeOrmTableFindOperator with WhereMixin { } } - void explain() { - _isExplain = true; - } - - void group(String column) { - _groupParams.add(column); - } - // void having(Map map) { // _whereParams.add(WhereParam.evaluateWhereParams(map)); // } - - void include( - ArcadeOrmTableSchema table, { - String? on, - String? as, - Map? where, - JoinOperation joinType = JoinOperation.inner, - }) { - _includeParams.add( - IncludeParam( - table.tableName, - on: on, - as: as, - where: where, - joinType: joinType, - ), - ); - } - - /// Set the number of results to return. Cannot be less than 1. - void limit(int limit) { - if (limit <= 0) { - throw ArcadeOrmException( - message: "limit cannot be less then 1", - originalError: null, - ); - } - _limit = limit; - } - - void select(Map value) { - _selectParams.add(value); - } - - /// Set the number of results skipped. Cannot be less than 0. - void skip(int skip) { - if (skip < 0) { - throw ArcadeOrmException( - message: "skip cannot be less then 0", - originalError: null, - ); - } - _skip = skip; - } - - void sort(Map sortBy) { - final Map sortValue = - sortBy.map((key, value) => MapEntry(key, value > 0 ? 1 : -1)); - _sortParams.add(sortValue); - } } -class ArcadeOrmTableInsertOperator { +class ArcadeOrmTableInsertOperator with InsertMixin, ExplainMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; - final List> _insertWithParams = []; - - bool _isExplain = false; - ArcadeOrmTableInsertOperator({ required ArcadeOrm orm, required TableOperator operator, @@ -140,19 +81,15 @@ class ArcadeOrmTableInsertOperator { _operator = operator, _orm = orm; - void insertWith(Map value) { - _insertWithParams.add(value); - } - Future exec({ ArcadeOrmTableFromConverter? fromJson, }) async { try { final data = await _orm.adapter.operate( - isExplain: _isExplain, + isExplain: $explain, operator: _operator, transaction: _transaction, - insertWithParams: _insertWithParams, + insertWithParams: $insertWithParams, ); final convertedData = await fromJson?.call(data); @@ -166,21 +103,13 @@ class ArcadeOrmTableInsertOperator { ); } } - - void explain() { - _isExplain = true; - } } -class ArcadeOrmTableDeleteOperator with WhereMixin { +class ArcadeOrmTableDeleteOperator with WhereMixin, IncludeMixin, ExplainMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; - final List _includeParams = []; - - bool _isExplain = false; - ArcadeOrmTableDeleteOperator({ required ArcadeOrm orm, required TableOperator operator, @@ -194,11 +123,11 @@ class ArcadeOrmTableDeleteOperator with WhereMixin { }) async { try { final data = await _orm.adapter.operate( - isExplain: _isExplain, operator: _operator, transaction: _transaction, + isExplain: $explain, whereParams: $whereParams?.simplify(), - includeParams: _includeParams, + includeParams: $includeParams, ); final convertedData = await fromJson?.call(data); @@ -212,40 +141,13 @@ class ArcadeOrmTableDeleteOperator with WhereMixin { ); } } - - void explain() { - _isExplain = true; - } - - void include( - ArcadeOrmTableSchema table, { - String? on, - String? as, - Map? where, - JoinOperation joinType = JoinOperation.inner, - }) { - _includeParams.add( - IncludeParam( - table.tableName, - on: on, - as: as, - where: where, - joinType: joinType, - ), - ); - } } -class ArcadeOrmTableRawOperator { +class ArcadeOrmTableRawOperator with ExplainMixin, RawMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; - bool _isExplain = false; - - String? _rawSql; - Map? _rawNoSql; - ArcadeOrmTableRawOperator({ required ArcadeOrm orm, required TableOperator operator, @@ -259,9 +161,9 @@ class ArcadeOrmTableRawOperator { }) async { try { final data = await _orm.adapter.operate( - isExplain: _isExplain, - rawSql: _rawSql, - rawNoSql: _rawNoSql, + rawSql: $rawSql, + rawNoSql: $rawNoSql, + isExplain: $explain, operator: _operator, transaction: _transaction, ); @@ -277,31 +179,13 @@ class ArcadeOrmTableRawOperator { ); } } - - void explain() { - _isExplain = true; - } - - // ignore: use_setters_to_change_properties - void noSql(Map query) { - _rawNoSql = query; - } - - // ignore: use_setters_to_change_properties - void sql(String query) { - _rawSql = query; - } } -class ArcadeOrmTableUpdateOperator with WhereMixin { +class ArcadeOrmTableUpdateOperator with WhereMixin, UpdateMixin, ExplainMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; - final List> _updateWithParams = []; - - bool _isExplain = false; - ArcadeOrmTableUpdateOperator({ required ArcadeOrm orm, required TableOperator operator, @@ -315,11 +199,11 @@ class ArcadeOrmTableUpdateOperator with WhereMixin { }) async { try { final data = await _orm.adapter.operate( - isExplain: _isExplain, + isExplain: $explain, operator: _operator, transaction: _transaction, whereParams: $whereParams?.simplify(), - updateWithParams: _updateWithParams, + updateWithParams: $updateWithParams, ); final convertedData = await fromJson?.call(data); @@ -333,14 +217,6 @@ class ArcadeOrmTableUpdateOperator with WhereMixin { ); } } - - void explain() { - _isExplain = true; - } - - void updateWith(Map value) { - _updateWithParams.add(value); - } } sealed class ExecResult {} diff --git a/packages/arcade_orm/lib/src/query/mixins/explain.dart b/packages/arcade_orm/lib/src/query/mixins/explain.dart new file mode 100644 index 0000000..0f31648 --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/explain.dart @@ -0,0 +1,9 @@ +import 'package:meta/meta.dart'; + +mixin ExplainMixin { + @protected + bool $explain = false; + void explain() { + $explain = true; + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/group.dart b/packages/arcade_orm/lib/src/query/mixins/group.dart new file mode 100644 index 0000000..585f37b --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/group.dart @@ -0,0 +1,9 @@ +import 'package:meta/meta.dart'; + +mixin GroupMixin { + @protected + final List $groupParams = []; + void group(String column) { + $groupParams.add(column); + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/include.dart b/packages/arcade_orm/lib/src/query/mixins/include.dart new file mode 100644 index 0000000..13ec1f2 --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/include.dart @@ -0,0 +1,27 @@ +import 'package:arcade_orm/arcade_orm.dart'; +import 'package:arcade_orm/src/query/include.dart'; +import 'package:arcade_orm/src/query/where.dart'; +import 'package:meta/meta.dart'; + +mixin IncludeMixin { + @protected + final List $includeParams = []; + + void include( + ArcadeOrmTableSchema table, { + String? on, + String? as, + Map? where, + JoinOperation joinType = JoinOperation.inner, + }) { + $includeParams.add( + IncludeParam( + table.tableName, + on: on, + as: as, + where: where, + joinType: joinType, + ), + ); + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/insert.dart b/packages/arcade_orm/lib/src/query/mixins/insert.dart new file mode 100644 index 0000000..41d2f96 --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/insert.dart @@ -0,0 +1,10 @@ +import 'package:meta/meta.dart'; + +mixin InsertMixin { + @protected + final List> $insertWithParams = []; + + void insertWith(Map value) { + $insertWithParams.add(value); + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/pagination.dart b/packages/arcade_orm/lib/src/query/mixins/pagination.dart new file mode 100644 index 0000000..4da1c7a --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/pagination.dart @@ -0,0 +1,31 @@ +import 'package:arcade_orm/arcade_orm.dart'; +import 'package:meta/meta.dart'; + +mixin PaginationMixin { + @protected + int? $limit; + @protected + int? $skip; + + /// Set the number of results skipped. Cannot be less than 0. + void skip(int skip) { + if (skip < 0) { + throw ArcadeOrmException( + message: "skip cannot be less then 0", + originalError: null, + ); + } + $skip = skip; + } + + /// Set the number of results to return. Cannot be less than 1. + void limit(int limit) { + if (limit <= 0) { + throw ArcadeOrmException( + message: "limit cannot be less then 1", + originalError: null, + ); + } + $limit = limit; + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/raw.dart b/packages/arcade_orm/lib/src/query/mixins/raw.dart new file mode 100644 index 0000000..6150c67 --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/raw.dart @@ -0,0 +1,18 @@ +import 'package:meta/meta.dart'; + +mixin RawMixin { + @protected + String? $rawSql; + @protected + Map? $rawNoSql; + + // ignore: use_setters_to_change_properties + void noSql(Map query) { + $rawNoSql = query; + } + + // ignore: use_setters_to_change_properties + void sql(String query) { + $rawSql = query; + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/select.dart b/packages/arcade_orm/lib/src/query/mixins/select.dart new file mode 100644 index 0000000..234b1ab --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/select.dart @@ -0,0 +1,10 @@ +import 'package:arcade_orm/src/query/select.dart'; +import 'package:meta/meta.dart'; + +mixin SelectMixin { + @protected + final List> $selectParams = []; + void select(Map value) { + $selectParams.add(value); + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/sort.dart b/packages/arcade_orm/lib/src/query/mixins/sort.dart new file mode 100644 index 0000000..b180113 --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/sort.dart @@ -0,0 +1,11 @@ +enum SortDirection { asc, desc } + +mixin SortMixin { + final List> $sortParams = []; + + void sort(Map sortBy) { + final Map sortValue = + sortBy.map((key, value) => MapEntry(key, value)); + $sortParams.add(sortValue); + } +} diff --git a/packages/arcade_orm/lib/src/query/mixins/update.dart b/packages/arcade_orm/lib/src/query/mixins/update.dart new file mode 100644 index 0000000..1dd7eed --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/update.dart @@ -0,0 +1,10 @@ +import 'package:meta/meta.dart'; + +mixin UpdateMixin { + @protected + final List> $updateWithParams = []; + + void updateWith(Map value) { + $updateWithParams.add(value); + } +} From 39408b3bf92f9b4b1cf51faea578f806176ecb13 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Fri, 22 Dec 2023 14:15:56 +0600 Subject: [PATCH 20/24] feat: updated example --- packages/arcade_orm/example/api/basic.dart | 36 ++++++++++++---------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index e523b10..fca8d68 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; import 'package:arcade_orm/src/query/include.dart'; +import 'package:arcade_orm/src/query/mixins/sort.dart'; import 'package:arcade_orm/src/query/select.dart'; import 'package:arcade_orm/src/query/where.dart'; @@ -46,22 +47,23 @@ class ArcadeOrmMockAdapter } @override - Future> operate( - {required TableOperator operator, - required ArcadeOrmTransaction? transaction, - required bool isExplain, - String? rawSql, - Map? rawNoSql, - WhereExpressionNode? whereParams, - WhereExpressionNode? havingParams, - List> selectParams = const [], - List includeParams = const [], - List groupParams = const [], - List> sortParams = const [], - List> updateWithParams = const [], - List> insertWithParams = const [], - int? limit, - int? skip}) { + Future> operate({ + required TableOperator operator, + required ArcadeOrmTransaction? transaction, + required bool isExplain, + String? rawSql, + Map? rawNoSql, + WhereExpressionNode? whereParams, + WhereExpressionNode? havingParams, + List> selectParams = const [], + List includeParams = const [], + List groupParams = const [], + List> sortParams = const [], + List> updateWithParams = const [], + List> insertWithParams = const [], + int? limit, + int? skip, + }) { // TODO: implement operate throw UnimplementedError(); } @@ -181,7 +183,7 @@ Future orming() async { joinType: JoinOperation.left, ) ..group(UserTable.id) - ..sort({UserTable.name: 1}) + ..sort({UserTable.name: SortDirection.asc}) ..limit(10) ..skip(0); From 180778e7d34380b7588c3c095e55c76568bfef45 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Fri, 22 Dec 2023 16:23:23 +0600 Subject: [PATCH 21/24] feat: where update --- packages/arcade_orm/example/api/basic.dart | 4 +- packages/arcade_orm/lib/src/query/where.dart | 189 ++++-------------- .../test/src/query/delete_test.dart | 6 +- .../test/src/query/update_test.dart | 7 +- 4 files changed, 54 insertions(+), 152 deletions(-) diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index fca8d68..1acd593 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -142,14 +142,14 @@ Future orming() async { (trx) async { final r = userTable.findOne(transaction: trx) ..where({ - UserTable.id: array([1, 2, 4]), + UserTable.id: inList([1, 2, 4]), }) ..where({UserTable.id: eq(10)}) ..where( and([ { UserTable.name: like("%aa"), - UserTable.id: array([1, 2, 4]), + UserTable.id: inList([1, 2, 4]), }, {UserTable.name: eq("2")}, ]), diff --git a/packages/arcade_orm/lib/src/query/where.dart b/packages/arcade_orm/lib/src/query/where.dart index 2ba8238..dc05576 100644 --- a/packages/arcade_orm/lib/src/query/where.dart +++ b/packages/arcade_orm/lib/src/query/where.dart @@ -38,15 +38,24 @@ class WhereParam extends WhereParamBuilder { @override bool operator ==(Object other) => + identical(this, other) || other is WhereParam && - other.runtimeType == runtimeType && - other.operator == operator && - other.value == value && - other.start == start && - other.end == end; + other.operator == operator && + other.value == value && + other.start == start && + other.end == end; @override int get hashCode => Object.hash(operator, value, start, end); + + @override + String toString() { + return 'WhereParam{operator: $operator, value: $value, start: $start, end: $end}'; + } + + String toJson() { + return toString(); + } } sealed class WhereExpressionNode extends WhereParamBuilder { @@ -97,35 +106,33 @@ sealed class WhereExpressionNode extends WhereParamBuilder { if (nodes.length == 1) { return nodes.first; } - if (nodes.length > 1) { - bool isSame = true; - WhereExpressionOperator? operator; - for (final node in nodes) { - if (node is WhereExpressionOperatorNode) { - if (operator == null) { - operator = node.operator; - } else if (operator != node.operator) { - isSame = false; - break; - } - } else { + bool isSame = true; + WhereExpressionOperator? operator; + for (final node in nodes) { + if (node is WhereExpressionOperatorNode) { + if (operator == null) { + operator = node.operator; + } else if (operator != node.operator) { isSame = false; break; } + } else { + isSame = false; + break; } - if (isSame && operator != null) { - final simplifiedNodes = nodes.fold>( - [], - (previousValue, element) { - previousValue.addAll(element.nodes); - return previousValue; - }, - ); - return WhereExpressionOperatorNode( - operator: operator, - nodes: simplifiedNodes, - ); - } + } + if (isSame && operator != null) { + final simplifiedNodes = nodes.fold>( + [], + (previousValue, element) { + previousValue.addAll(element.nodes); + return previousValue; + }, + ); + return WhereExpressionOperatorNode( + operator: operator, + nodes: simplifiedNodes, + ); } return this; } @@ -186,8 +193,8 @@ enum WhereOperator { between, notEq, like, - array, - notInArray, + inList, + notInList, and, or, } @@ -229,9 +236,9 @@ List _getNodesFromMap( return nodes; } -WhereParam array(T value) { +WhereParam inList(T value) { return WhereParam( - operator: WhereOperator.array, + operator: WhereOperator.inList, value: value, ); } @@ -286,9 +293,9 @@ WhereParam lte(T value) { ); } -WhereParam notInArray(T value) { +WhereParam notInList(T value) { return WhereParam( - operator: WhereOperator.notInArray, + operator: WhereOperator.notInList, value: value, ); } @@ -299,113 +306,3 @@ WhereParam notEq(T value) { value: value, ); } - -// WhereExpressionNode test1() { -// // where A = 1 -// final rootNode = WhereExpressionOperatorNode( -// operator: WhereExpressionOperator.and, -// nodes: [], -// ); - -// rootNode.addNode( -// WhereExpressionCompareNode( -// field: 'A', -// param: eq(1), -// ), -// ); - -// return rootNode.simplify(); -// } - -// WhereExpressionNode test2() { -// // where A = 1 and A = 2 and B = 3 -// final rootNode = WhereExpressionOperatorNode( -// operator: WhereExpressionOperator.and, -// nodes: [], -// ); - -// rootNode.addNode( -// WhereExpressionCompareNode( -// field: 'A', -// param: eq(1), -// ), -// ); - -// rootNode.addNode( -// WhereExpressionCompareNode( -// field: 'A', -// param: eq(2), -// ), -// ); - -// rootNode.addNode( -// WhereExpressionCompareNode( -// field: 'B', -// param: eq(3), -// ), -// ); - -// return rootNode.simplify(); -// } - -// WhereExpressionNode test3() { -// // where (A = 1 or A = 2) and A = 3 and B = 2 -// final rootNode = WhereExpressionOperatorNode( -// operator: WhereExpressionOperator.and, -// nodes: [], -// ); - -// rootNode.addNode( -// or([ -// {'A': eq(1)}, -// {'A': eq(2)}, -// ]), -// ); - -// rootNode.addNode( -// and([ -// { -// 'A': eq(3), -// 'B': eq(2), -// }, -// ]), -// ); - -// return rootNode.simplify(); -// } - -// WhereExpressionNode test4() { -// // where A = 1 or A = 2 or B = 2 or B = 3 or A = 3 or B = 4 -// final rootNode = WhereExpressionOperatorNode( -// operator: WhereExpressionOperator.and, -// nodes: [], -// ); - -// rootNode.addNode( -// or([ -// {'A': eq(1)}, -// {'A': eq(2)}, -// {'B': eq(2)}, -// ]), -// ); - -// rootNode.addNode( -// or([ -// {'B': eq(3)}, -// ]), -// ); - -// rootNode.addNode( -// or([ -// {'A': eq(3)}, -// ]), -// ); - -// rootNode.addNode( -// or([ -// {'B': eq(4)}, -// ]), -// ); - -// return rootNode.simplify(); -// } diff --git a/packages/arcade_orm/test/src/query/delete_test.dart b/packages/arcade_orm/test/src/query/delete_test.dart index fc4db53..191309c 100644 --- a/packages/arcade_orm/test/src/query/delete_test.dart +++ b/packages/arcade_orm/test/src/query/delete_test.dart @@ -109,7 +109,7 @@ void main() { (captured.first as WhereExpressionNode).toMap(); expect( capturedWhereParams["id"], - equals(WhereParam(operator: WhereOperator.eq, value: 1)), + equals(WhereParam(operator: WhereOperator.eq, value: 1)), ); }); @@ -147,7 +147,7 @@ void main() { expect( capturedIncludeParams.where?.toMap()["name"], equals( - WhereParam( + WhereParam( operator: WhereOperator.notEq, value: "admin", ), @@ -201,7 +201,7 @@ void main() { (captured.first as WhereExpressionNode).toMap(); expect( capturedWhereParams["id"], - equals(WhereParam(operator: WhereOperator.eq, value: 1)), + equals(WhereParam(operator: WhereOperator.eq, value: 1)), ); }); }); diff --git a/packages/arcade_orm/test/src/query/update_test.dart b/packages/arcade_orm/test/src/query/update_test.dart index d96a930..ef7d92a 100644 --- a/packages/arcade_orm/test/src/query/update_test.dart +++ b/packages/arcade_orm/test/src/query/update_test.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:arcade_orm/arcade_orm.dart'; import 'package:arcade_orm/src/query/where.dart'; import 'package:mocktail/mocktail.dart'; @@ -99,7 +101,10 @@ void main() { ), ).captured; - print((captured[1] as WhereExpressionNode).toMap()); + // print( + // const JsonEncoder.withIndent(" ") + // .convert((captured[1] as WhereExpressionNode).toMap()), + // ); }); // test("data", () async { From f01df4519561e98d1168cdd97962ea3f3ba6cd4f Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Mon, 25 Dec 2023 20:38:54 +0600 Subject: [PATCH 22/24] feat: update test --- packages/arcade_orm/lib/src/adapter.dart | 2 +- .../lib/src/query/mixins/update.dart | 4 +- .../test/src/query/delete_test.dart | 6 +- .../test/src/query/insert_test.dart | 4 +- .../test/src/query/update_test.dart | 155 ++++++++++++------ 5 files changed, 115 insertions(+), 56 deletions(-) diff --git a/packages/arcade_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart index 26c5a2d..5191730 100644 --- a/packages/arcade_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -33,7 +33,7 @@ abstract interface class ArcadeOrmAdapterBase { List includeParams = const [], List groupParams = const [], List> sortParams = const [], - List> updateWithParams = const [], + Map updateWithParams = const {}, List> insertWithParams = const [], int? limit, int? skip, diff --git a/packages/arcade_orm/lib/src/query/mixins/update.dart b/packages/arcade_orm/lib/src/query/mixins/update.dart index 1dd7eed..fa6a632 100644 --- a/packages/arcade_orm/lib/src/query/mixins/update.dart +++ b/packages/arcade_orm/lib/src/query/mixins/update.dart @@ -2,9 +2,9 @@ import 'package:meta/meta.dart'; mixin UpdateMixin { @protected - final List> $updateWithParams = []; + final Map $updateWithParams = {}; void updateWith(Map value) { - $updateWithParams.add(value); + $updateWithParams.addAll(value); } } diff --git a/packages/arcade_orm/test/src/query/delete_test.dart b/packages/arcade_orm/test/src/query/delete_test.dart index 191309c..7f43508 100644 --- a/packages/arcade_orm/test/src/query/delete_test.dart +++ b/packages/arcade_orm/test/src/query/delete_test.dart @@ -101,7 +101,7 @@ void main() { includeParams: any(named: "includeParams"), groupParams: [], sortParams: [], - updateWithParams: [], + updateWithParams: {}, insertWithParams: [], ), ).captured; @@ -137,7 +137,7 @@ void main() { includeParams: captureAny(named: "includeParams"), groupParams: [], sortParams: [], - updateWithParams: [], + updateWithParams: {}, insertWithParams: [], ), ).captured; @@ -192,7 +192,7 @@ void main() { includeParams: [], groupParams: [], sortParams: [], - updateWithParams: [], + updateWithParams: {}, insertWithParams: [], ), ).captured; diff --git a/packages/arcade_orm/test/src/query/insert_test.dart b/packages/arcade_orm/test/src/query/insert_test.dart index 459b060..06cb850 100644 --- a/packages/arcade_orm/test/src/query/insert_test.dart +++ b/packages/arcade_orm/test/src/query/insert_test.dart @@ -79,7 +79,7 @@ void main() { includeParams: [], groupParams: [], sortParams: [], - updateWithParams: [], + updateWithParams: {}, insertWithParams: [ {"name": "foo", "age": 20}, {"email": "foo@examle.com"}, @@ -123,7 +123,7 @@ void main() { includeParams: [], groupParams: [], sortParams: [], - updateWithParams: [], + updateWithParams: {}, insertWithParams: [ {"name": "foo", "age": 20}, ], diff --git a/packages/arcade_orm/test/src/query/update_test.dart b/packages/arcade_orm/test/src/query/update_test.dart index ef7d92a..9bf0654 100644 --- a/packages/arcade_orm/test/src/query/update_test.dart +++ b/packages/arcade_orm/test/src/query/update_test.dart @@ -51,6 +51,7 @@ void main() { operator: TableOperator.update, transaction: null, isExplain: false, + whereParams: any(named: "whereParams"), updateWithParams: any(named: "updateWithParams"), ), ).thenAnswer( @@ -64,7 +65,7 @@ void main() { reset(mockTransaction); }); - test("operate", () async { + test("operate where", () async { final arcadeOrm = await ArcadeOrm.init( adapter: mockAdapter, ); @@ -96,60 +97,118 @@ void main() { includeParams: [], groupParams: [], sortParams: [], + updateWithParams: any(named: "updateWithParams"), + insertWithParams: [], + ), + ).captured; + + final capturedWhereParams = + (captured.first as WhereExpressionNode).toMap(); + + final andExpr = capturedWhereParams[WhereExpressionOperator.and.name] + as List>; + + expect( + andExpr.first[UserTable.name], + equals(WhereParam(operator: WhereOperator.eq, value: "bar")), + ); + expect( + andExpr.last[UserTable.age], + equals(WhereParam(operator: WhereOperator.gt, value: 20)), + ); + }); + + test("operate updateWith", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = UserTable(arcadeOrm); + final updateQuery = table.update() + ..where( + and([ + { + UserTable.name: eq("bar"), + UserTable.age: gt(20), + } + ]), + ) + ..updateWith({ + UserTable.name: "foo", + UserTable.age: 20, + }) + ..updateWith({ + UserTable.age: 30, + UserTable.email: "foo@example.com", + }); + + await updateQuery.exec(); + + final captured = verify( + () => mockAdapter.operate( + operator: TableOperator.update, + transaction: null, + isExplain: false, + whereParams: any(named: "whereParams"), + // havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], updateWithParams: captureAny(named: "updateWithParams"), insertWithParams: [], ), ).captured; - // print( - // const JsonEncoder.withIndent(" ") - // .convert((captured[1] as WhereExpressionNode).toMap()), - // ); + final updateWithParams = captured.first as Map; + + expect( + updateWithParams, + equals({ + UserTable.name: "foo", + UserTable.age: 30, + UserTable.email: "foo@example.com", + }), + ); + }); + + test("data", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = UserTable(arcadeOrm); + final udpateQuery = table.update() + ..updateWith({"name": "foo", "age": 20}); + final data = await udpateQuery.exec(); + expect(data, isA()); + expect((data as ExecResultData).data, equals({"nUpdated": 1})); }); - // test("data", () async { - // final arcadeOrm = await ArcadeOrm.init( - // adapter: mockAdapter, - // ); - // final table = UserTable(arcadeOrm); - // final insertQuery = table.insert() - // ..insertWith({"name": "foo", "age": 20}) - // ..insertWith({"email": "foo@examle.com"}); - // final data = await insertQuery.exec(); - // expect(data, isA()); - // expect((data as ExecResultData).data, equals({"nInserted": 1})); - // }); - - // test("operate with transaction", () async { - // when(() => mockTransaction.start()) - // .thenAnswer((_) async => Future.value()); - // final arcadeOrm = await ArcadeOrm.init( - // adapter: mockAdapter, - // ); - // final table = UserTable(arcadeOrm); - // final trx = table.transaction(); - // await trx.start(); - // final insertQuery = table.insert(transaction: trx) - // ..insertWith({"name": "foo", "age": 20}); - // await insertQuery.exec(); - // verify( - // () => mockAdapter.operate( - // operator: TableOperator.insert, - // transaction: trx, - // isExplain: false, - // whereParams: [], - // havingParams: [], - // selectParams: [], - // includeParams: [], - // groupParams: [], - // sortParams: [], - // updateWithParams: [], - // insertWithParams: [ - // {"name": "foo", "age": 20}, - // ], - // ), - // ).called(1); - // }); + test("operate with transaction", () async { + when(() => mockTransaction.start()) + .thenAnswer((_) async => Future.value()); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = UserTable(arcadeOrm); + final trx = table.transaction(); + await trx.start(); + final insertQuery = table.update(transaction: trx) + ..updateWith({"name": "foo", "age": 20}); + await insertQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.update, + transaction: trx, + isExplain: false, + whereParams: any(named: "whereParams"), + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: {"name": "foo", "age": 20}, + ), + ).called(1); + }); }); }); } From ca8032a18a859baf151ca8939bf1ddf7152c73b8 Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Tue, 26 Dec 2023 04:18:02 +0600 Subject: [PATCH 23/24] feat: raw test --- packages/arcade_orm/example/api/basic.dart | 35 ++-- packages/arcade_orm/lib/src/adapter.dart | 6 +- packages/arcade_orm/lib/src/query.dart | 26 +-- .../lib/src/query/mixins/explain.dart | 9 - .../arcade_orm/lib/src/query/mixins/raw.dart | 17 +- .../lib/src/query/mixins/verbose.dart | 9 + .../test/src/query/delete_test.dart | 10 +- .../test/src/query/insert_test.dart | 8 +- .../arcade_orm/test/src/query/raw_test.dart | 172 ++++++++++++++++++ .../test/src/query/update_test.dart | 10 +- 10 files changed, 243 insertions(+), 59 deletions(-) delete mode 100644 packages/arcade_orm/lib/src/query/mixins/explain.dart create mode 100644 packages/arcade_orm/lib/src/query/mixins/verbose.dart create mode 100644 packages/arcade_orm/test/src/query/raw_test.dart diff --git a/packages/arcade_orm/example/api/basic.dart b/packages/arcade_orm/example/api/basic.dart index 1acd593..73c887c 100644 --- a/packages/arcade_orm/example/api/basic.dart +++ b/packages/arcade_orm/example/api/basic.dart @@ -47,23 +47,24 @@ class ArcadeOrmMockAdapter } @override - Future> operate({ - required TableOperator operator, - required ArcadeOrmTransaction? transaction, - required bool isExplain, - String? rawSql, - Map? rawNoSql, - WhereExpressionNode? whereParams, - WhereExpressionNode? havingParams, - List> selectParams = const [], - List includeParams = const [], - List groupParams = const [], - List> sortParams = const [], - List> updateWithParams = const [], - List> insertWithParams = const [], - int? limit, - int? skip, - }) { + Future> operate( + {required TableOperator operator, + required ArcadeOrmTransaction? transaction, + required bool isVerbose, + String? rawSql, + List>? rawNoSqlAggregate, + Map? rawNoSqlAggregateOptions, + Map? rawParams, + WhereExpressionNode? whereParams, + WhereExpressionNode? havingParams, + List> selectParams = const [], + List includeParams = const [], + List groupParams = const [], + List> sortParams = const [], + Map updateWithParams = const {}, + List> insertWithParams = const [], + int? limit, + int? skip}) { // TODO: implement operate throw UnimplementedError(); } diff --git a/packages/arcade_orm/lib/src/adapter.dart b/packages/arcade_orm/lib/src/adapter.dart index 5191730..fafb31a 100644 --- a/packages/arcade_orm/lib/src/adapter.dart +++ b/packages/arcade_orm/lib/src/adapter.dart @@ -24,9 +24,11 @@ abstract interface class ArcadeOrmAdapterBase { Future> operate({ required TableOperator operator, required ArcadeOrmTransaction? transaction, - required bool isExplain, + required bool isVerbose, String? rawSql, - Map? rawNoSql, + List>? rawNoSqlAggregate, + Map? rawNoSqlAggregateOptions, + Map? rawParams, WhereExpressionNode? whereParams, WhereExpressionNode? havingParams, List> selectParams = const [], diff --git a/packages/arcade_orm/lib/src/query.dart b/packages/arcade_orm/lib/src/query.dart index 65b814f..112397e 100644 --- a/packages/arcade_orm/lib/src/query.dart +++ b/packages/arcade_orm/lib/src/query.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:arcade_orm/arcade_orm.dart'; -import 'package:arcade_orm/src/query/mixins/explain.dart'; import 'package:arcade_orm/src/query/mixins/group.dart'; import 'package:arcade_orm/src/query/mixins/include.dart'; import 'package:arcade_orm/src/query/mixins/insert.dart'; @@ -10,6 +9,7 @@ import 'package:arcade_orm/src/query/mixins/raw.dart'; import 'package:arcade_orm/src/query/mixins/select.dart'; import 'package:arcade_orm/src/query/mixins/sort.dart'; import 'package:arcade_orm/src/query/mixins/update.dart'; +import 'package:arcade_orm/src/query/mixins/verbose.dart'; import 'package:arcade_orm/src/query/mixins/where.dart'; class ArcadeOrmTableFindOperator @@ -20,7 +20,7 @@ class ArcadeOrmTableFindOperator PaginationMixin, SortMixin, IncludeMixin, - ExplainMixin { + VerboseMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; @@ -38,7 +38,7 @@ class ArcadeOrmTableFindOperator }) async { try { final data = await _orm.adapter.operate( - isExplain: $explain, + isVerbose: $verbose, operator: _operator, transaction: _transaction, whereParams: $whereParams?.simplify(), @@ -68,7 +68,7 @@ class ArcadeOrmTableFindOperator // } } -class ArcadeOrmTableInsertOperator with InsertMixin, ExplainMixin { +class ArcadeOrmTableInsertOperator with InsertMixin, VerboseMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; @@ -86,7 +86,7 @@ class ArcadeOrmTableInsertOperator with InsertMixin, ExplainMixin { }) async { try { final data = await _orm.adapter.operate( - isExplain: $explain, + isVerbose: $verbose, operator: _operator, transaction: _transaction, insertWithParams: $insertWithParams, @@ -105,7 +105,7 @@ class ArcadeOrmTableInsertOperator with InsertMixin, ExplainMixin { } } -class ArcadeOrmTableDeleteOperator with WhereMixin, IncludeMixin, ExplainMixin { +class ArcadeOrmTableDeleteOperator with WhereMixin, IncludeMixin, VerboseMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; @@ -125,7 +125,7 @@ class ArcadeOrmTableDeleteOperator with WhereMixin, IncludeMixin, ExplainMixin { final data = await _orm.adapter.operate( operator: _operator, transaction: _transaction, - isExplain: $explain, + isVerbose: $verbose, whereParams: $whereParams?.simplify(), includeParams: $includeParams, ); @@ -143,7 +143,7 @@ class ArcadeOrmTableDeleteOperator with WhereMixin, IncludeMixin, ExplainMixin { } } -class ArcadeOrmTableRawOperator with ExplainMixin, RawMixin { +class ArcadeOrmTableRawOperator with VerboseMixin, RawMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; @@ -162,8 +162,10 @@ class ArcadeOrmTableRawOperator with ExplainMixin, RawMixin { try { final data = await _orm.adapter.operate( rawSql: $rawSql, - rawNoSql: $rawNoSql, - isExplain: $explain, + rawParams: $params, + rawNoSqlAggregate: $rawNoSqlAggregate, + rawNoSqlAggregateOptions: $rawNoSqlAggregateOptions, + isVerbose: $verbose, operator: _operator, transaction: _transaction, ); @@ -181,7 +183,7 @@ class ArcadeOrmTableRawOperator with ExplainMixin, RawMixin { } } -class ArcadeOrmTableUpdateOperator with WhereMixin, UpdateMixin, ExplainMixin { +class ArcadeOrmTableUpdateOperator with WhereMixin, UpdateMixin, VerboseMixin { final ArcadeOrm _orm; final TableOperator _operator; final ArcadeOrmTransaction? _transaction; @@ -199,7 +201,7 @@ class ArcadeOrmTableUpdateOperator with WhereMixin, UpdateMixin, ExplainMixin { }) async { try { final data = await _orm.adapter.operate( - isExplain: $explain, + isVerbose: $verbose, operator: _operator, transaction: _transaction, whereParams: $whereParams?.simplify(), diff --git a/packages/arcade_orm/lib/src/query/mixins/explain.dart b/packages/arcade_orm/lib/src/query/mixins/explain.dart deleted file mode 100644 index 0f31648..0000000 --- a/packages/arcade_orm/lib/src/query/mixins/explain.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:meta/meta.dart'; - -mixin ExplainMixin { - @protected - bool $explain = false; - void explain() { - $explain = true; - } -} diff --git a/packages/arcade_orm/lib/src/query/mixins/raw.dart b/packages/arcade_orm/lib/src/query/mixins/raw.dart index 6150c67..a65af28 100644 --- a/packages/arcade_orm/lib/src/query/mixins/raw.dart +++ b/packages/arcade_orm/lib/src/query/mixins/raw.dart @@ -4,15 +4,24 @@ mixin RawMixin { @protected String? $rawSql; @protected - Map? $rawNoSql; + Map? $params; + @protected + List>? $rawNoSqlAggregate; + @protected + Map? $rawNoSqlAggregateOptions; // ignore: use_setters_to_change_properties - void noSql(Map query) { - $rawNoSql = query; + void aggregate( + List>? aggregate, { + Map? options, + }) { + $rawNoSqlAggregate = aggregate; + $rawNoSqlAggregateOptions = options; } // ignore: use_setters_to_change_properties - void sql(String query) { + void sql(String query, {Map? params}) { $rawSql = query; + $params = params; } } diff --git a/packages/arcade_orm/lib/src/query/mixins/verbose.dart b/packages/arcade_orm/lib/src/query/mixins/verbose.dart new file mode 100644 index 0000000..ae80f8a --- /dev/null +++ b/packages/arcade_orm/lib/src/query/mixins/verbose.dart @@ -0,0 +1,9 @@ +import 'package:meta/meta.dart'; + +mixin VerboseMixin { + @protected + bool $verbose = false; + void verbose() { + $verbose = true; + } +} diff --git a/packages/arcade_orm/test/src/query/delete_test.dart b/packages/arcade_orm/test/src/query/delete_test.dart index 7f43508..13b0b46 100644 --- a/packages/arcade_orm/test/src/query/delete_test.dart +++ b/packages/arcade_orm/test/src/query/delete_test.dart @@ -63,7 +63,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.delete, transaction: null, - isExplain: false, + isVerbose: false, whereParams: any(named: "whereParams"), ), ).thenAnswer( @@ -94,7 +94,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.delete, transaction: null, - isExplain: false, + isVerbose: false, whereParams: captureAny(named: "whereParams"), // havingParams: [], selectParams: [], @@ -130,7 +130,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.delete, transaction: null, - isExplain: false, + isVerbose: false, whereParams: any(named: "whereParams"), // havingParams: [], selectParams: [], @@ -185,7 +185,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.delete, transaction: trx, - isExplain: false, + isVerbose: false, whereParams: captureAny(named: "whereParams"), // havingParams: [], selectParams: [], @@ -211,7 +211,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.delete, transaction: null, - isExplain: false, + isVerbose: false, whereParams: any(named: "whereParams"), ), ).thenThrow( diff --git a/packages/arcade_orm/test/src/query/insert_test.dart b/packages/arcade_orm/test/src/query/insert_test.dart index 06cb850..67af12c 100644 --- a/packages/arcade_orm/test/src/query/insert_test.dart +++ b/packages/arcade_orm/test/src/query/insert_test.dart @@ -46,7 +46,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.insert, transaction: null, - isExplain: false, + isVerbose: false, insertWithParams: any(named: "insertWithParams"), ), ).thenAnswer( @@ -73,7 +73,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.insert, transaction: null, - isExplain: false, + isVerbose: false, // havingParams: [], selectParams: [], includeParams: [], @@ -117,7 +117,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.insert, transaction: trx, - isExplain: false, + isVerbose: false, // havingParams: [], selectParams: [], includeParams: [], @@ -137,7 +137,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.insert, transaction: null, - isExplain: false, + isVerbose: false, insertWithParams: any(named: "insertWithParams"), ), ).thenThrow( diff --git a/packages/arcade_orm/test/src/query/raw_test.dart b/packages/arcade_orm/test/src/query/raw_test.dart new file mode 100644 index 0000000..25d5529 --- /dev/null +++ b/packages/arcade_orm/test/src/query/raw_test.dart @@ -0,0 +1,172 @@ +import 'package:arcade_orm/arcade_orm.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class MockAdapter extends Mock implements ArcadeOrmAdapterBase {} + +class MockTransaction extends Mock implements ArcadeOrmTransaction {} + +class UserTable extends ArcadeOrmTableSchema { + UserTable(super.orm); + + @override + final String tableName = "user"; + + @override + Map schema = {}; +} + +void main() { + final mockAdapter = MockAdapter(); + final mockTransaction = MockTransaction(); + group('raw', () { + setUp(() { + when(() => mockAdapter.transaction()).thenReturn(mockTransaction); + }); + + tearDown(() { + clearOrms(); + reset(mockAdapter); + reset(mockTransaction); + }); + + group("success", () { + setUp(() { + when( + () => mockAdapter.operate( + operator: TableOperator.raw, + transaction: null, + isVerbose: false, + rawSql: any(named: "rawSql"), + rawNoSqlAggregate: any(named: "rawNoSqlAggregate"), + rawNoSqlAggregateOptions: any(named: "rawNoSqlAggregateOptions"), + ), + ).thenAnswer( + (_) => Future.value({"nResult": 1}), + ); + }); + + test("operate sql", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = UserTable(arcadeOrm); + final rawQuery = table.raw() + ..sql( + "INSERT INTO user (name, email) VALUES (@name, @email)", + params: { + "name:": "John", + "email": "john@example.com", + }, + ); + await rawQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.raw, + transaction: null, + isVerbose: false, + // havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: {}, + insertWithParams: [], + rawSql: "INSERT INTO user (name, email) VALUES (@name, @email)", + rawParams: { + "name:": "John", + "email": "john@example.com", + }, + ), + ).called(1); + }); + test("operate noSql", () async { + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = UserTable(arcadeOrm); + final rawQuery = table.raw() + ..aggregate( + [ + { + "\$match": { + "name:": "John", + "email": "john@example.com", + }, + }, + { + "\$group": { + "_id": "\$name", + "count": {"\$sum"}, + }, + }, + ], + options: { + "useDisk": "true", + }, + ); + await rawQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.raw, + transaction: null, + isVerbose: false, + // havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: {}, + insertWithParams: [], + rawNoSqlAggregate: [ + { + "\$match": { + "name:": "John", + "email": "john@example.com", + }, + }, + { + "\$group": { + "_id": "\$name", + "count": {"\$sum"}, + }, + }, + ], + rawNoSqlAggregateOptions: { + "useDisk": "true", + }, + ), + ).called(1); + }); + test('with transaction', () async { + when(() => mockTransaction.start()) + .thenAnswer((_) async => Future.value()); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = UserTable(arcadeOrm); + final trx = table.transaction(); + await trx.start(); + final rawQuery = table.raw(transaction: trx) + ..sql("SELECT * FROM user WHERE id = @id", params: {"id": 1}); + await rawQuery.exec(); + verify( + () => mockAdapter.operate( + operator: TableOperator.raw, + transaction: trx, + isVerbose: false, + // havingParams: [], + selectParams: [], + includeParams: [], + groupParams: [], + sortParams: [], + updateWithParams: {}, + insertWithParams: [], + rawSql: "SELECT * FROM user WHERE id = @id", + rawParams: {"id": 1}, + ), + ).called(1); + }); + }); + }); +} diff --git a/packages/arcade_orm/test/src/query/update_test.dart b/packages/arcade_orm/test/src/query/update_test.dart index 9bf0654..1b770d6 100644 --- a/packages/arcade_orm/test/src/query/update_test.dart +++ b/packages/arcade_orm/test/src/query/update_test.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:arcade_orm/arcade_orm.dart'; import 'package:arcade_orm/src/query/where.dart'; import 'package:mocktail/mocktail.dart'; @@ -50,7 +48,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.update, transaction: null, - isExplain: false, + isVerbose: false, whereParams: any(named: "whereParams"), updateWithParams: any(named: "updateWithParams"), ), @@ -90,7 +88,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.update, transaction: null, - isExplain: false, + isVerbose: false, whereParams: captureAny(named: "whereParams"), // havingParams: [], selectParams: [], @@ -147,7 +145,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.update, transaction: null, - isExplain: false, + isVerbose: false, whereParams: any(named: "whereParams"), // havingParams: [], selectParams: [], @@ -199,7 +197,7 @@ void main() { () => mockAdapter.operate( operator: TableOperator.update, transaction: trx, - isExplain: false, + isVerbose: false, whereParams: any(named: "whereParams"), selectParams: [], includeParams: [], From c927326f3c08314979228d32e9f75897d7801d7c Mon Sep 17 00:00:00 2001 From: Kazi Waseef Date: Tue, 23 Jan 2024 10:53:50 +0600 Subject: [PATCH 24/24] feat: raw test fail case --- .../arcade_orm/test/src/query/raw_test.dart | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/arcade_orm/test/src/query/raw_test.dart b/packages/arcade_orm/test/src/query/raw_test.dart index 25d5529..ea19bb4 100644 --- a/packages/arcade_orm/test/src/query/raw_test.dart +++ b/packages/arcade_orm/test/src/query/raw_test.dart @@ -168,5 +168,30 @@ void main() { ).called(1); }); }); + + test("db record - failure", () async { + when( + () => mockAdapter.operate( + operator: TableOperator.raw, + transaction: null, + isVerbose: false, + rawParams: any(named: "rawParams"), + rawSql: any(named: "rawSql"), + rawNoSqlAggregate: any(named: "rawNoSqlAggregate"), + rawNoSqlAggregateOptions: any(named: "rawNoSqlAggregateOptions"), + ), + ).thenThrow( + ArcadeOrmException(message: "Operation Failed", originalError: null), + ); + final arcadeOrm = await ArcadeOrm.init( + adapter: mockAdapter, + ); + final table = UserTable(arcadeOrm); + final rawQuery = table.raw() + ..sql("SELECT * FROM user WHERE id = @id", params: {"id": 1}); + final data = await rawQuery.exec(); + expect(data, isA()); + expect((data as ExecResultFailure).exception.message, "Operation Failed"); + }); }); }