From bff4af14a37ac2e14079e34b6ac4bd7928c7975b Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Sat, 23 Mar 2024 20:18:46 +0000 Subject: [PATCH 01/13] entity type analyzer: wip --- type_analyzer/.gitignore | 3 + type_analyzer/CHANGELOG.md | 3 + type_analyzer/README.md | 2 + type_analyzer/analysis_options.yaml | 30 ++ type_analyzer/bin/type_analyzer.dart | 7 + type_analyzer/lib/entity/entity.dart | 1 + type_analyzer/lib/type_analyzer.dart | 242 +++++++++++ type_analyzer/pubspec.lock | 445 +++++++++++++++++++++ type_analyzer/pubspec.yaml | 21 + type_analyzer/test/type_analyzer_test.dart | 6 + 10 files changed, 760 insertions(+) create mode 100644 type_analyzer/.gitignore create mode 100644 type_analyzer/CHANGELOG.md create mode 100644 type_analyzer/README.md create mode 100644 type_analyzer/analysis_options.yaml create mode 100644 type_analyzer/bin/type_analyzer.dart create mode 100644 type_analyzer/lib/entity/entity.dart create mode 100644 type_analyzer/lib/type_analyzer.dart create mode 100644 type_analyzer/pubspec.lock create mode 100644 type_analyzer/pubspec.yaml create mode 100644 type_analyzer/test/type_analyzer_test.dart diff --git a/type_analyzer/.gitignore b/type_analyzer/.gitignore new file mode 100644 index 0000000..3a85790 --- /dev/null +++ b/type_analyzer/.gitignore @@ -0,0 +1,3 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ diff --git a/type_analyzer/CHANGELOG.md b/type_analyzer/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/type_analyzer/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/type_analyzer/README.md b/type_analyzer/README.md new file mode 100644 index 0000000..3816eca --- /dev/null +++ b/type_analyzer/README.md @@ -0,0 +1,2 @@ +A sample command-line application with an entrypoint in `bin/`, library code +in `lib/`, and example unit test in `test/`. diff --git a/type_analyzer/analysis_options.yaml b/type_analyzer/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/type_analyzer/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/type_analyzer/bin/type_analyzer.dart b/type_analyzer/bin/type_analyzer.dart new file mode 100644 index 0000000..d2ff5dc --- /dev/null +++ b/type_analyzer/bin/type_analyzer.dart @@ -0,0 +1,7 @@ +import 'dart:io'; + +import 'package:type_analyzer/type_analyzer.dart' as type_analyzer; + +void main(List arguments) { + type_analyzer.EndpointsAnalyzer(Directory.current).analyze(); +} diff --git a/type_analyzer/lib/entity/entity.dart b/type_analyzer/lib/entity/entity.dart new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type_analyzer/lib/entity/entity.dart @@ -0,0 +1 @@ + diff --git a/type_analyzer/lib/type_analyzer.dart b/type_analyzer/lib/type_analyzer.dart new file mode 100644 index 0000000..0d980e3 --- /dev/null +++ b/type_analyzer/lib/type_analyzer.dart @@ -0,0 +1,242 @@ +import 'dart:io'; + +import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; +import 'package:analyzer/dart/analysis/results.dart'; +import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/physical_file_system.dart'; +import 'package:code_builder/code_builder.dart'; +import 'package:dart_style/dart_style.dart'; +import 'package:path/path.dart' as path; +import 'package:recase/recase.dart'; +import 'package:grammer/grammer.dart'; +import 'package:collection/collection.dart'; + +const yaroormIdentifier = 'package:yaroorm/src/database/entity/entity.dart'; + +class EndpointsAnalyzer { + final AnalysisContextCollection collection; + + /// Create a new [EndpointsAnalyzer], containing a + /// [AnalysisContextCollection] that analyzes all dart files in the + /// provided [endpointDirectory]. + EndpointsAnalyzer(Directory endpointDirectory) + : collection = AnalysisContextCollection( + includedPaths: [ + path.join(endpointDirectory.path, 'lib/src/models'), + // path.join(endpointDirectory.path, 'lib/src/controllers'), + // path.join(endpointDirectory.path, 'lib/src/services'), + ], + resourceProvider: PhysicalResourceProvider.INSTANCE, + ); + + void analyze() async { + await for (var (library, filePath, _) in _libraries) { + final libraryElement = library.element; + final topElements = libraryElement.topLevelElements; + final classElements = topElements.whereType(); + + if (classElements.isEmpty) return; + + analyzeClassElement(libraryElement, filePath, classElements.first); + } + } + + void analyzeClassElement( + LibraryElement libElement, + String filePath, + ClassElement classElement, + ) async { + final fields = classElement.fields.where(allowedTypes).toList(); + + final className = classElement.name; + final meta = classElement.metadata + .firstWhere((e) => e.element?.library?.identifier == 'package:yaroorm/src/database/entity/entity.dart') + .computeConstantValue(); + final tableName = meta!.getField('name')?.toStringValue() ?? classElement.name.snakeCase.toPlural().first; + + final primaryKey = getEntityField(fields, 'PrimaryKey'); + final createdAt = getEntityField(fields, 'CreatedAtColumn'); + final updatedAt = getEntityField(fields, 'UpdatedAtColumn'); + + final timestampsEnabled = (createdAt ?? updatedAt) != null; + final updatableFields = fields.where((e) => ![primaryKey, createdAt].contains(e)); + + final primaryConstructor = classElement.constructors.firstWhereOrNull((e) => e.name == ""); + if (primaryConstructor == null) { + throw '$className Entity does not have a default constructor'; + } + + if (primaryKey == null) { + throw Exception("$className Entity doesn't have primary key"); + } + + final fieldNames = fields.map((e) => e.name); + final contructorArgs = primaryConstructor.children; + final notAllowedProps = contructorArgs.where((e) => !fieldNames.contains(e.name)); + if (notAllowedProps.isNotEmpty) { + throw Exception( + 'These props are not allowed in $className Entity default constructor: ${notAllowedProps.join(', ')}'); + } + + String fieldToString(FieldElement e) { + final symbol = '#${e.name}'; + return '''DBEntityField( + "${e.name}", + ${e.type.getDisplayString(withNullability: false)}, + $symbol, + nullable: ${libElement.typeSystem.isNullable(e.type)}, + primaryKey: ${e == primaryKey} + )'''; + } + + final typeDataName = '${className.toLowerCase()}TypeData'; + + final library = Library((b) => b + ..comments.add('ignore_for_file: non_constant_identifier_names') + ..body.addAll([ + Directive.partOf(path.basename(filePath)), + Method((m) => m + ..name = '${classElement.name.pascalCase}Query' + ..returns = refer('Query<$className>') + ..type = MethodType.getter + ..lambda = true + ..body = Code('DB.query<$className>()')), + Method((m) => m + ..name = '${classElement.name.pascalCase}Schema' + ..returns = refer('CreateSchema') + ..lambda = true + ..type = MethodType.getter + ..body = Code('Schema.fromEntity<$className>()')), + Method((m) => m + ..name = typeDataName + ..returns = refer('DBEntity<$className>') + ..type = MethodType.getter + ..lambda = true + ..body = Code( + '''DBEntity<$className>( + "$tableName", + timestampsEnabled: $timestampsEnabled, + columns: ${fields.map(fieldToString).toList()}, + mirror: _\$${className}EntityMirror.new, + build: (args) => ${_generateConstructorCode(className, primaryConstructor)} + ,)''', + )), + Class( + (b) => b + ..name = '_\$${className}Entity' + ..extend = refer('Entity<$className>') + ..methods.addAll([ + Method((m) => m + ..name = '_instance' + ..returns = refer(className) + ..type = MethodType.getter + ..lambda = true + ..body = Code('this as $className')), + Method((m) => m + ..name = 'update' + ..returns = refer('Future<$className>') + ..modifier = MethodModifier.async + ..optionalParameters.addAll([ + ...updatableFields.map((e) => Parameter((m) => m + ..name = e.name + ..required = false + ..named = true + ..type = refer('${e.type.getDisplayString(withNullability: false)}?'))), + ]) + ..body = Code('return _instance;')), + ]), + ), + Class( + (b) => b + ..name = '_\$${className}EntityMirror' + ..extend = refer('EntityMirror<$className>') + ..constructors.add(Constructor( + (b) => b + ..constant = true + ..requiredParameters.add(Parameter((p) => p + ..toSuper = true + ..name = 'instance')), + )) + ..methods.addAll([ + Method((m) => m + ..name = 'get' + ..annotations.add(CodeExpression(Code('override'))) + ..requiredParameters.add(Parameter((p) => p + ..name = 'field' + ..type = refer('Symbol'))) + ..returns = refer('Object?') + ..body = Code(''' +return switch(field) { + ${fields.map((e) => ''' + #${e.name} => instance.${e.name} +''').join(',')}, + _ => throw Exception('Unknown property \$field'), +}; +''')), + ]), + ), + ])); + + final actualFilePath = path.basename(filePath).replaceFirst('.dart', '.entity.dart'); + + final df = path.join(path.dirname(filePath), actualFilePath); + + final emitter = DartEmitter(); + + await File(df).writeAsString( + DartFormatter().format('${library.accept(emitter)}'), + ); + } + + Stream<(ResolvedLibraryResult, String, String)> get _libraries async* { + for (var context in collection.contexts) { + final analyzedDartFiles = context.contextRoot.analyzedFiles().where((path) => + path.endsWith('.dart') && + !path.endsWith('_test.dart') && + !path.endsWith('.g.dart') && + !path.endsWith('.e.dart')); + + for (var filePath in analyzedDartFiles) { + var library = await context.currentSession.getResolvedLibrary(filePath); + if (library is ResolvedLibraryResult) { + yield (library, filePath, context.contextRoot.root.path); + } + } + } + } +} + +bool allowedTypes(FieldElement field) { + return field.getter?.isSynthetic ?? false; +} + +String _generateConstructorCode(String className, ConstructorElement constructor) { + final sb = StringBuffer()..write('$className('); + + final normalParams = constructor.type.normalParameterNames; + final namedParams = constructor.type.namedParameterTypes.keys; + + if (normalParams.isNotEmpty) { + sb + ..write(normalParams.map((name) => 'args[#$name]').join(',')) + ..write(','); + } + + if (namedParams.isNotEmpty) { + sb + ..writeln(namedParams.map((name) => '$name: args[#$name]').join(', ')) + ..write(','); + } + + return (sb..write(')')).toString(); +} + +FieldElement? getEntityField(List fields, String type) { + return fields.firstWhereOrNull((f) { + return f.metadata.firstWhereOrNull((e) => + e.element?.library?.identifier == yaroormIdentifier && + (e.element is PropertyAccessorElement) && + (e.element as PropertyAccessorElement).returnType.toString() == type) != + null; + }); +} diff --git a/type_analyzer/pubspec.lock b/type_analyzer/pubspec.lock new file mode 100644 index 0000000..45731c7 --- /dev/null +++ b/type_analyzer/pubspec.lock @@ -0,0 +1,445 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: "direct main" + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e + url: "https://pub.dev" + source: hosted + version: "8.9.1" + code_builder: + dependency: "direct main" + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" + collection: + dependency: "direct main" + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + url: "https://pub.dev" + source: hosted + version: "1.7.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + dart_style: + dependency: "direct main" + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + grammer: + dependency: "direct main" + description: + name: grammer + sha256: "333c0f99fb116ae554276f64769c3a5219d314bb4fc9de43d83ae9746e0b4dd4" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + lints: + dependency: "direct dev" + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct main" + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + recase: + dependency: "direct main" + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stemmer: + dependency: transitive + description: + name: stemmer + sha256: "9a548a410ad690152b7de946c45e8b166f157f2811fb3ad717da3721f5cee144" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + url: "https://pub.dev" + source: hosted + version: "1.25.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: e7d5ecd604e499358c5fe35ee828c0298a320d54455e791e9dcf73486bc8d9f0 + url: "https://pub.dev" + source: hosted + version: "14.1.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + url: "https://pub.dev" + source: hosted + version: "2.4.4" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.3.1 <4.0.0" diff --git a/type_analyzer/pubspec.yaml b/type_analyzer/pubspec.yaml new file mode 100644 index 0000000..585da75 --- /dev/null +++ b/type_analyzer/pubspec.yaml @@ -0,0 +1,21 @@ +name: type_analyzer +description: A sample command-line application. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: ^3.3.1 + +# Add regular dependencies here. +dependencies: + analyzer: + path: ^1.9.0 + code_builder: ^4.10.0 + dart_style: + recase: ^4.1.0 + grammer: ^1.0.3 + collection: ^1.18.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/type_analyzer/test/type_analyzer_test.dart b/type_analyzer/test/type_analyzer_test.dart new file mode 100644 index 0000000..adf7fdd --- /dev/null +++ b/type_analyzer/test/type_analyzer_test.dart @@ -0,0 +1,6 @@ +import 'package:type_analyzer/type_analyzer.dart'; +import 'package:test/test.dart'; + +void main() { + test('calculate', () {}); +} From 935b138f7e8eafc59851cd494ba64ae3794e6051 Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Sat, 23 Mar 2024 20:19:15 +0000 Subject: [PATCH 02/13] misc --- .gitignore | 1 + .vscode/settings.json | 5 +- .../migrations/create_articles_table.dart | 25 ++++----- database/migrations/create_users_table.dart | 14 ++--- lib/backend.dart | 2 +- lib/src/controllers/article_controller.dart | 2 +- lib/src/controllers/auth_controller.dart | 2 +- lib/src/{models => }/dto/article_dto.dart | 0 lib/src/{models => }/dto/dto.dart | 0 lib/src/{models => }/dto/user_dto.dart | 0 lib/src/models/article.dart | 24 --------- lib/src/models/article/article.dart | 53 +++++++++++++++++++ lib/src/models/models.dart | 2 - lib/src/models/user.dart | 21 -------- lib/src/models/user/user.dart | 53 +++++++++++++++++++ lib/src/services/article_service.dart | 2 +- pubspec.lock | 17 +++--- pubspec.yaml | 11 ++-- 18 files changed, 140 insertions(+), 94 deletions(-) rename lib/src/{models => }/dto/article_dto.dart (100%) rename lib/src/{models => }/dto/dto.dart (100%) rename lib/src/{models => }/dto/user_dto.dart (100%) delete mode 100644 lib/src/models/article.dart create mode 100644 lib/src/models/article/article.dart delete mode 100644 lib/src/models/models.dart delete mode 100644 lib/src/models/user.dart create mode 100644 lib/src/models/user/user.dart diff --git a/.gitignore b/.gitignore index be989c1..1b73bd2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .dart_tool/ *.g.dart *.sqlite +*.entity.dart _yoorm_tool/ diff --git a/.vscode/settings.json b/.vscode/settings.json index f4607f2..1a87504 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "dart.lineLength": 120 + "dart.lineLength": 120, + "[dart]": { + "editor.rulers": [120], + } } diff --git a/database/migrations/create_articles_table.dart b/database/migrations/create_articles_table.dart index 56bf16b..2110520 100644 --- a/database/migrations/create_articles_table.dart +++ b/database/migrations/create_articles_table.dart @@ -1,28 +1,21 @@ -import 'package:backend/src/models/models.dart'; +import 'package:backend/src/models/article/article.dart'; +import 'package:backend/src/models/user/user.dart'; import 'package:yaroorm/migration.dart'; class CreateArticlesTable extends Migration { @override void up(List schemas) { - final articleSchema = Schema.create('articles', (table) { - return table - ..id() - ..string('title') - ..string('description') - ..string('imageUrl', nullable: true) - ..integer('ownerId') - ..foreign( - column: 'ownerId', - onKey: (fkey) => fkey.actions(onDelete: ForeignKeyAction.cascade, onUpdate: ForeignKeyAction.cascade), - ) - ..timestamps(); - }); + final arc = ArticleSchema + ..foreign( + column: 'ownerId', + onKey: (fkey) => fkey.actions(onDelete: ForeignKeyAction.cascade, onUpdate: ForeignKeyAction.cascade), + ); - schemas.add(articleSchema); + schemas.add(arc); } @override void down(List actions) { - actions.add(Schema.dropIfExists('articles')); + actions.add(Schema.dropIfExists(ArticleSchema)); } } diff --git a/database/migrations/create_users_table.dart b/database/migrations/create_users_table.dart index 9f67ba6..fe27354 100644 --- a/database/migrations/create_users_table.dart +++ b/database/migrations/create_users_table.dart @@ -1,22 +1,14 @@ +import 'package:backend/src/models/user/user.dart'; import 'package:yaroorm/migration.dart'; class CreateUsersTable extends Migration { @override void up(List schemas) { - final userSchema = Schema.create('users', (table) { - return table - ..id() - ..string('name') - ..string('email') - ..string('password') - ..timestamps(); - }); - - schemas.add(userSchema); + schemas.add(UserSchema); } @override void down(List schemas) { - schemas.add(Schema.dropIfExists('users')); + schemas.add(Schema.dropIfExists(UserSchema)); } } diff --git a/lib/backend.dart b/lib/backend.dart index a4ed083..dbdb022 100644 --- a/lib/backend.dart +++ b/lib/backend.dart @@ -12,7 +12,7 @@ import 'app/providers/providers.dart'; export 'src/controllers/controllers.dart'; export 'src/models/models.dart'; -export 'src/models/dto/dto.dart'; +export 'src/dto/dto.dart'; bool get isDebugMode { var isDebug = false; diff --git a/lib/src/controllers/article_controller.dart b/lib/src/controllers/article_controller.dart index 28527a1..01a95f4 100644 --- a/lib/src/controllers/article_controller.dart +++ b/lib/src/controllers/article_controller.dart @@ -1,4 +1,4 @@ -import 'package:backend/src/models/dto/article_dto.dart'; +import 'package:backend/src/dto/article_dto.dart'; import 'package:backend/src/services/services.dart'; import 'package:yaroo/http/http.dart'; import 'package:yaroo/http/meta.dart'; diff --git a/lib/src/controllers/auth_controller.dart b/lib/src/controllers/auth_controller.dart index 7634349..bbb7e42 100644 --- a/lib/src/controllers/auth_controller.dart +++ b/lib/src/controllers/auth_controller.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:yaroo/http/http.dart'; import 'package:yaroo/http/meta.dart'; import 'package:yaroorm/yaroorm.dart'; -import 'package:backend/src/models/dto/dto.dart'; +import 'package:backend/src/dto/dto.dart'; import 'package:backend/src/models/models.dart'; import 'package:backend/src/services/services.dart'; import 'package:bcrypt/bcrypt.dart'; diff --git a/lib/src/models/dto/article_dto.dart b/lib/src/dto/article_dto.dart similarity index 100% rename from lib/src/models/dto/article_dto.dart rename to lib/src/dto/article_dto.dart diff --git a/lib/src/models/dto/dto.dart b/lib/src/dto/dto.dart similarity index 100% rename from lib/src/models/dto/dto.dart rename to lib/src/dto/dto.dart diff --git a/lib/src/models/dto/user_dto.dart b/lib/src/dto/user_dto.dart similarity index 100% rename from lib/src/models/dto/user_dto.dart rename to lib/src/dto/user_dto.dart diff --git a/lib/src/models/article.dart b/lib/src/models/article.dart deleted file mode 100644 index 193259a..0000000 --- a/lib/src/models/article.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:backend/src/models/models.dart'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:yaroorm/yaroorm.dart'; - -part 'article.g.dart'; - -@JsonSerializable() -@EntityMeta(table: 'articles', timestamps: true) -class Article extends Entity { - String title; - String description; - - String? imageUrl; - - final int ownerId; - - Article(this.ownerId, this.title, this.description, {this.imageUrl}); - - Map toJson() => _$ArticleToJson(this); - - Future get owner => DB.query().get(ownerId); - - factory Article.fromJson(Map json) => _$ArticleFromJson(json); -} diff --git a/lib/src/models/article/article.dart b/lib/src/models/article/article.dart new file mode 100644 index 0000000..43ee0ef --- /dev/null +++ b/lib/src/models/article/article.dart @@ -0,0 +1,53 @@ +import 'package:yaroorm/migration.dart'; +import 'package:yaroorm/yaroorm.dart'; + +part 'article.entity.dart'; + +@Table('articles') +class Article extends _$ArticleEntity { + @primaryKey + final int id; + + final String title; + final String description; + + final String? imageUrl; + + final int ownerId; + + @createdAtCol + final DateTime createdAt; + + @updatedAtCol + final DateTime updatedAt; + + Article( + this.id, + this.title, + this.ownerId, + this.description, { + this.imageUrl, + required this.createdAt, + required this.updatedAt, + }); + + Map toJson() => { + 'id': id, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + 'title': title, + 'description': description, + 'imageUrl': imageUrl, + 'ownerId': ownerId, + }; + + factory Article.fromJson(Map json) => Article( + json['id'] as int, + json['title'] as String, + json['ownerId'] as int, + json['description'] as String, + imageUrl: json['imageUrl'] as String?, + createdAt: DateTime.parse(json['createdAt'] as String), + updatedAt: DateTime.parse(json['updatedAt'] as String), + ); +} diff --git a/lib/src/models/models.dart b/lib/src/models/models.dart deleted file mode 100644 index 0ccfdb7..0000000 --- a/lib/src/models/models.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'user.dart'; -export 'article.dart'; diff --git a/lib/src/models/user.dart b/lib/src/models/user.dart deleted file mode 100644 index 63c78aa..0000000 --- a/lib/src/models/user.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; -import 'package:yaroorm/yaroorm.dart'; - -part 'user.g.dart'; - -@JsonSerializable() -@EntityMeta(table: 'users', timestamps: true) -class User extends Entity { - final String name; - - final String email; - - @JsonKey(includeToJson: false, defaultValue: '') - final String password; - - User(this.name, this.email, {required this.password}); - - Map toJson() => _$UserToJson(this); - - factory User.fromJson(Map json) => _$UserFromJson(json); -} diff --git a/lib/src/models/user/user.dart b/lib/src/models/user/user.dart new file mode 100644 index 0000000..a7cd156 --- /dev/null +++ b/lib/src/models/user/user.dart @@ -0,0 +1,53 @@ +import 'package:backend/src/models/article/article.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:yaroorm/migration.dart'; +import 'package:yaroorm/yaroorm.dart'; + +part 'user.entity.dart'; + +@Table('users') +class User extends _$UserEntity { + @primaryKey + final int id; + + final String name; + + final String email; + + @JsonKey(includeToJson: false, defaultValue: '') + final String password; + + @createdAtCol + final DateTime createdAt; + + @updatedAtCol + final DateTime updatedAt; + + User( + this.id, + this.name, + this.email, { + required this.password, + required this.createdAt, + required this.updatedAt, + }); + + HasMany
get articles => hasMany
(); + + Map toJson() => { + 'id': id, + 'name': name, + 'email': email, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + }; + + factory User.fromJson(Map json) => User( + json['id'] as int, + json['name'] as String, + json['email'] as String, + password: json['password'] as String? ?? '', + createdAt: DateTime.parse(json['createdAt'] as String), + updatedAt: DateTime.parse(json['updatedAt'] as String), + ); +} diff --git a/lib/src/services/article_service.dart b/lib/src/services/article_service.dart index a9d53c5..f33fe80 100644 --- a/lib/src/services/article_service.dart +++ b/lib/src/services/article_service.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:isolate'; -import 'package:backend/src/models/dto/article_dto.dart'; +import 'package:backend/src/dto/article_dto.dart'; import 'package:backend/src/models/models.dart'; import 'package:yaroo/yaroo.dart'; import 'package:yaroorm/yaroorm.dart'; diff --git a/pubspec.lock b/pubspec.lock index 4ca2f09..1f242ef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -964,21 +964,18 @@ packages: source: git version: "0.0.1" yaroo_cli: - dependency: "direct dev" + dependency: "direct overridden" description: - path: "packages/yaroo_cli" - ref: HEAD - resolved-ref: e91a7a1218a35c23b7634186a270ceb43337e78c - url: "https://github.com/codekeyz/yaroo.git" - source: git + path: "../yaroorm/packages/yaroo_cli" + relative: true + source: path version: "1.0.0" yaroorm: dependency: "direct main" description: - name: yaroorm - sha256: "652afef1db82631540de247eef89be554c93a01cc7dbaa96fc9c7a03aa7e54c5" - url: "https://pub.dev" - source: hosted + path: "../yaroorm/packages/yaroorm" + relative: true + source: path version: "0.0.2" sdks: dart: ">=3.3.0 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 06cbf3f..21024a2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,8 @@ dependencies: git: url: https://github.com/codekeyz/yaroo.git path: packages/yaroo - yaroorm: ^0.0.2 + yaroorm: + path: ../yaroorm/packages/yaroorm collection: ^1.18.0 logger: ^2.0.2+1 @@ -27,13 +28,13 @@ dependencies: dependency_overrides: reflectable: + yaroo_cli: + path: ../yaroorm/packages/yaroo_cli + yaroorm: + path: ../yaroorm/packages/yaroorm dev_dependencies: lints: ^3.0.0 test: ^1.24.0 json_serializable: ^6.7.1 melos: ^3.2.0 - yaroo_cli: - git: - url: https://github.com/codekeyz/yaroo.git - path: packages/yaroo_cli From ca965b5a94f89551871c43866c0279adac6a6b68 Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Sat, 6 Apr 2024 14:43:15 +0000 Subject: [PATCH 03/13] wip --- .DS_Store | Bin 6148 -> 6148 bytes bin/tools/migrator.dart | 13 +- database/config.dart | 4 +- .../migrations/create_articles_table.dart | 5 +- lib/backend.dart | 11 +- lib/src/models/article/article.dart | 7 +- lib/src/models/user/user.dart | 8 +- lib/src/services/article_service.dart | 10 +- lib/src/utils/utils.dart | 8 + pubspec.lock | 25 +- pubspec.yaml | 4 + type_analyzer/.gitignore | 3 - type_analyzer/CHANGELOG.md | 3 - type_analyzer/README.md | 2 - type_analyzer/analysis_options.yaml | 30 -- type_analyzer/bin/type_analyzer.dart | 7 - type_analyzer/lib/entity/entity.dart | 1 - type_analyzer/lib/type_analyzer.dart | 242 ---------- type_analyzer/pubspec.lock | 445 ------------------ type_analyzer/pubspec.yaml | 21 - type_analyzer/test/type_analyzer_test.dart | 6 - 21 files changed, 65 insertions(+), 790 deletions(-) create mode 100644 lib/src/utils/utils.dart delete mode 100644 type_analyzer/.gitignore delete mode 100644 type_analyzer/CHANGELOG.md delete mode 100644 type_analyzer/README.md delete mode 100644 type_analyzer/analysis_options.yaml delete mode 100644 type_analyzer/bin/type_analyzer.dart delete mode 100644 type_analyzer/lib/entity/entity.dart delete mode 100644 type_analyzer/lib/type_analyzer.dart delete mode 100644 type_analyzer/pubspec.lock delete mode 100644 type_analyzer/pubspec.yaml delete mode 100644 type_analyzer/test/type_analyzer_test.dart diff --git a/.DS_Store b/.DS_Store index d0dcf172a5b512d4e1e9241d3363dabef2557c24..f3721f5b034b2ba1dae85ff36329d3a0cdc5cc76 100644 GIT binary patch delta 78 zcmZoMXfc=|#>B)qu~2NHo+2ar#(>?7jO>$nSc)e{_ z5>e)u)Z&fVvww2S1y_ta#08I)d6G{#SST?wrXz%nF5F3-_(`-{e^|vm*^nw9O}Nan z*qY# dS`ul=s2Ti+w6DHZQmb2r0Ax1G^rZf(egRFUUZMa1 diff --git a/bin/tools/migrator.dart b/bin/tools/migrator.dart index 73da399..7b5be99 100644 --- a/bin/tools/migrator.dart +++ b/bin/tools/migrator.dart @@ -1,12 +1,13 @@ -// ignore: depend_on_referenced_packages -import 'package:yaroo_cli/orm/orm.dart'; +import 'package:backend/src/models/article/article.dart'; +import 'package:backend/src/models/user/user.dart'; +import 'package:yaroo_cli/orm.dart'; +import 'package:yaroorm/yaroorm.dart'; import '../../database/config.dart' as orm; -import 'migrator.reflectable.dart'; - -export 'package:backend/src/models/models.dart'; void main(List args) async { - initializeReflectable(); + Query.addTypeDef(userTypeData); + Query.addTypeDef
(articleTypeData); + await OrmCLIRunner.start(args, orm.config); } diff --git a/database/config.dart b/database/config.dart index 408ae39..e61e6c1 100644 --- a/database/config.dart +++ b/database/config.dart @@ -1,4 +1,4 @@ -import 'package:backend/backend.dart'; +import 'package:backend/src/utils/utils.dart'; import 'package:path/path.dart' as path; import 'package:yaroo/yaroo.dart'; import 'package:yaroorm/yaroorm.dart'; @@ -7,7 +7,7 @@ import './migrations/create_articles_table.dart'; import './migrations/create_users_table.dart'; final config = YaroormConfig( - isDebugMode ? 'test_db' : 'mysql', + 'test_db', connections: [ DatabaseConnection('test_db', DatabaseDriverType.sqlite, database: path.absolute('database', 'db.sqlite')), DatabaseConnection( diff --git a/database/migrations/create_articles_table.dart b/database/migrations/create_articles_table.dart index 2110520..e354b4d 100644 --- a/database/migrations/create_articles_table.dart +++ b/database/migrations/create_articles_table.dart @@ -8,7 +8,10 @@ class CreateArticlesTable extends Migration { final arc = ArticleSchema ..foreign( column: 'ownerId', - onKey: (fkey) => fkey.actions(onDelete: ForeignKeyAction.cascade, onUpdate: ForeignKeyAction.cascade), + onKey: (fkey) => fkey.actions( + onDelete: ForeignKeyAction.cascade, + onUpdate: ForeignKeyAction.cascade, + ), ); schemas.add(arc); diff --git a/lib/backend.dart b/lib/backend.dart index dbdb022..886a54e 100644 --- a/lib/backend.dart +++ b/lib/backend.dart @@ -9,20 +9,11 @@ import 'package:yaroo/yaroo.dart'; import 'app/middlewares/core_middleware.dart'; import 'app/middlewares/api_auth_middleware.dart'; import 'app/providers/providers.dart'; +import 'src/utils/utils.dart'; export 'src/controllers/controllers.dart'; -export 'src/models/models.dart'; export 'src/dto/dto.dart'; -bool get isDebugMode { - var isDebug = false; - assert(() { - isDebug = true; - return true; - }()); - return isDebug; -} - final blogApp = App(AppConfig( name: 'Dart Blog', environment: env('APP_ENV', isDebugMode ? 'test' : 'development'), diff --git a/lib/src/models/article/article.dart b/lib/src/models/article/article.dart index 43ee0ef..2714a88 100644 --- a/lib/src/models/article/article.dart +++ b/lib/src/models/article/article.dart @@ -1,10 +1,9 @@ -import 'package:yaroorm/migration.dart'; import 'package:yaroorm/yaroorm.dart'; -part 'article.entity.dart'; +part 'article.g.dart'; -@Table('articles') -class Article extends _$ArticleEntity { +@Table('articles', converters: [dateTimeConverter, booleanConverter]) +class Article extends Entity { @primaryKey final int id; diff --git a/lib/src/models/user/user.dart b/lib/src/models/user/user.dart index a7cd156..e0da6bf 100644 --- a/lib/src/models/user/user.dart +++ b/lib/src/models/user/user.dart @@ -1,12 +1,10 @@ -import 'package:backend/src/models/article/article.dart'; import 'package:json_annotation/json_annotation.dart'; -import 'package:yaroorm/migration.dart'; import 'package:yaroorm/yaroorm.dart'; -part 'user.entity.dart'; +part 'user.g.dart'; @Table('users') -class User extends _$UserEntity { +class User extends Entity { @primaryKey final int id; @@ -32,7 +30,7 @@ class User extends _$UserEntity { required this.updatedAt, }); - HasMany
get articles => hasMany
(); + // HasMany
get articles => hasMany
(); Map toJson() => { 'id': id, diff --git a/lib/src/services/article_service.dart b/lib/src/services/article_service.dart index f33fe80..64742a7 100644 --- a/lib/src/services/article_service.dart +++ b/lib/src/services/article_service.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'dart:isolate'; import 'package:backend/src/dto/article_dto.dart'; +import 'package:backend/src/models/article/article.dart'; import 'package:backend/src/models/models.dart'; import 'package:yaroo/yaroo.dart'; import 'package:yaroorm/yaroorm.dart'; @@ -20,7 +21,14 @@ class ArticleService { Future
createArticle(User user, CreateArticleDTO data, {String? imageUrl}) async { imageUrl ??= await getRandomImage(data.title); - return Article(user.id!, data.title, data.description, imageUrl: imageUrl).save(); + + return await ArticleQuery.create( + title: data.title, + description: data.description, + ownerId: user.id, + updatedAt: DateTime.now(), + imageUrl: imageUrl, + ); } Future updateArticle(User user, int articleId, CreateArticleDTO dto) async { diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart new file mode 100644 index 0000000..4a18a46 --- /dev/null +++ b/lib/src/utils/utils.dart @@ -0,0 +1,8 @@ +bool get isDebugMode { + var isDebug = false; + assert(() { + isDebug = true; + return true; + }()); + return isDebug; +} diff --git a/pubspec.lock b/pubspec.lock index 1f242ef..c1d8b4c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -106,7 +106,7 @@ packages: source: hosted version: "2.4.2" build_runner: - dependency: transitive + dependency: "direct dev" description: name: build_runner sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" @@ -217,6 +217,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + copy_with_extension: + dependency: transitive + description: + name: copy_with_extension + sha256: fbcf890b0c34aedf0894f91a11a579994b61b4e04080204656b582708b5b1125 + url: "https://pub.dev" + source: hosted + version: "5.0.4" + copy_with_extension_gen: + dependency: "direct dev" + description: + name: copy_with_extension_gen + sha256: "51cd11094096d40824c8da629ca7f16f3b7cea5fc44132b679617483d43346b0" + url: "https://pub.dev" + source: hosted + version: "5.0.4" coverage: dependency: transitive description: @@ -977,5 +993,12 @@ packages: relative: true source: path version: "0.0.2" + yaroorm_builder: + dependency: "direct dev" + description: + path: "../yaroorm/packages/generator" + relative: true + source: path + version: "1.0.0" sdks: dart: ">=3.3.0 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 21024a2..31e2256 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,3 +38,7 @@ dev_dependencies: test: ^1.24.0 json_serializable: ^6.7.1 melos: ^3.2.0 + build_runner: + yaroorm_builder: + path: ../yaroorm/packages/generator + copy_with_extension_gen: ^5.0.4 diff --git a/type_analyzer/.gitignore b/type_analyzer/.gitignore deleted file mode 100644 index 3a85790..0000000 --- a/type_analyzer/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# https://dart.dev/guides/libraries/private-files -# Created by `dart pub` -.dart_tool/ diff --git a/type_analyzer/CHANGELOG.md b/type_analyzer/CHANGELOG.md deleted file mode 100644 index effe43c..0000000 --- a/type_analyzer/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 1.0.0 - -- Initial version. diff --git a/type_analyzer/README.md b/type_analyzer/README.md deleted file mode 100644 index 3816eca..0000000 --- a/type_analyzer/README.md +++ /dev/null @@ -1,2 +0,0 @@ -A sample command-line application with an entrypoint in `bin/`, library code -in `lib/`, and example unit test in `test/`. diff --git a/type_analyzer/analysis_options.yaml b/type_analyzer/analysis_options.yaml deleted file mode 100644 index dee8927..0000000 --- a/type_analyzer/analysis_options.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# This file configures the static analysis results for your project (errors, -# warnings, and lints). -# -# This enables the 'recommended' set of lints from `package:lints`. -# This set helps identify many issues that may lead to problems when running -# or consuming Dart code, and enforces writing Dart using a single, idiomatic -# style and format. -# -# If you want a smaller set of lints you can change this to specify -# 'package:lints/core.yaml'. These are just the most critical lints -# (the recommended set includes the core lints). -# The core lints are also what is used by pub.dev for scoring packages. - -include: package:lints/recommended.yaml - -# Uncomment the following section to specify additional rules. - -# linter: -# rules: -# - camel_case_types - -# analyzer: -# exclude: -# - path/to/excluded/files/** - -# For more information about the core and recommended set of lints, see -# https://dart.dev/go/core-lints - -# For additional information about configuring this file, see -# https://dart.dev/guides/language/analysis-options diff --git a/type_analyzer/bin/type_analyzer.dart b/type_analyzer/bin/type_analyzer.dart deleted file mode 100644 index d2ff5dc..0000000 --- a/type_analyzer/bin/type_analyzer.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'dart:io'; - -import 'package:type_analyzer/type_analyzer.dart' as type_analyzer; - -void main(List arguments) { - type_analyzer.EndpointsAnalyzer(Directory.current).analyze(); -} diff --git a/type_analyzer/lib/entity/entity.dart b/type_analyzer/lib/entity/entity.dart deleted file mode 100644 index 8b13789..0000000 --- a/type_analyzer/lib/entity/entity.dart +++ /dev/null @@ -1 +0,0 @@ - diff --git a/type_analyzer/lib/type_analyzer.dart b/type_analyzer/lib/type_analyzer.dart deleted file mode 100644 index 0d980e3..0000000 --- a/type_analyzer/lib/type_analyzer.dart +++ /dev/null @@ -1,242 +0,0 @@ -import 'dart:io'; - -import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; -import 'package:analyzer/dart/analysis/results.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/file_system/physical_file_system.dart'; -import 'package:code_builder/code_builder.dart'; -import 'package:dart_style/dart_style.dart'; -import 'package:path/path.dart' as path; -import 'package:recase/recase.dart'; -import 'package:grammer/grammer.dart'; -import 'package:collection/collection.dart'; - -const yaroormIdentifier = 'package:yaroorm/src/database/entity/entity.dart'; - -class EndpointsAnalyzer { - final AnalysisContextCollection collection; - - /// Create a new [EndpointsAnalyzer], containing a - /// [AnalysisContextCollection] that analyzes all dart files in the - /// provided [endpointDirectory]. - EndpointsAnalyzer(Directory endpointDirectory) - : collection = AnalysisContextCollection( - includedPaths: [ - path.join(endpointDirectory.path, 'lib/src/models'), - // path.join(endpointDirectory.path, 'lib/src/controllers'), - // path.join(endpointDirectory.path, 'lib/src/services'), - ], - resourceProvider: PhysicalResourceProvider.INSTANCE, - ); - - void analyze() async { - await for (var (library, filePath, _) in _libraries) { - final libraryElement = library.element; - final topElements = libraryElement.topLevelElements; - final classElements = topElements.whereType(); - - if (classElements.isEmpty) return; - - analyzeClassElement(libraryElement, filePath, classElements.first); - } - } - - void analyzeClassElement( - LibraryElement libElement, - String filePath, - ClassElement classElement, - ) async { - final fields = classElement.fields.where(allowedTypes).toList(); - - final className = classElement.name; - final meta = classElement.metadata - .firstWhere((e) => e.element?.library?.identifier == 'package:yaroorm/src/database/entity/entity.dart') - .computeConstantValue(); - final tableName = meta!.getField('name')?.toStringValue() ?? classElement.name.snakeCase.toPlural().first; - - final primaryKey = getEntityField(fields, 'PrimaryKey'); - final createdAt = getEntityField(fields, 'CreatedAtColumn'); - final updatedAt = getEntityField(fields, 'UpdatedAtColumn'); - - final timestampsEnabled = (createdAt ?? updatedAt) != null; - final updatableFields = fields.where((e) => ![primaryKey, createdAt].contains(e)); - - final primaryConstructor = classElement.constructors.firstWhereOrNull((e) => e.name == ""); - if (primaryConstructor == null) { - throw '$className Entity does not have a default constructor'; - } - - if (primaryKey == null) { - throw Exception("$className Entity doesn't have primary key"); - } - - final fieldNames = fields.map((e) => e.name); - final contructorArgs = primaryConstructor.children; - final notAllowedProps = contructorArgs.where((e) => !fieldNames.contains(e.name)); - if (notAllowedProps.isNotEmpty) { - throw Exception( - 'These props are not allowed in $className Entity default constructor: ${notAllowedProps.join(', ')}'); - } - - String fieldToString(FieldElement e) { - final symbol = '#${e.name}'; - return '''DBEntityField( - "${e.name}", - ${e.type.getDisplayString(withNullability: false)}, - $symbol, - nullable: ${libElement.typeSystem.isNullable(e.type)}, - primaryKey: ${e == primaryKey} - )'''; - } - - final typeDataName = '${className.toLowerCase()}TypeData'; - - final library = Library((b) => b - ..comments.add('ignore_for_file: non_constant_identifier_names') - ..body.addAll([ - Directive.partOf(path.basename(filePath)), - Method((m) => m - ..name = '${classElement.name.pascalCase}Query' - ..returns = refer('Query<$className>') - ..type = MethodType.getter - ..lambda = true - ..body = Code('DB.query<$className>()')), - Method((m) => m - ..name = '${classElement.name.pascalCase}Schema' - ..returns = refer('CreateSchema') - ..lambda = true - ..type = MethodType.getter - ..body = Code('Schema.fromEntity<$className>()')), - Method((m) => m - ..name = typeDataName - ..returns = refer('DBEntity<$className>') - ..type = MethodType.getter - ..lambda = true - ..body = Code( - '''DBEntity<$className>( - "$tableName", - timestampsEnabled: $timestampsEnabled, - columns: ${fields.map(fieldToString).toList()}, - mirror: _\$${className}EntityMirror.new, - build: (args) => ${_generateConstructorCode(className, primaryConstructor)} - ,)''', - )), - Class( - (b) => b - ..name = '_\$${className}Entity' - ..extend = refer('Entity<$className>') - ..methods.addAll([ - Method((m) => m - ..name = '_instance' - ..returns = refer(className) - ..type = MethodType.getter - ..lambda = true - ..body = Code('this as $className')), - Method((m) => m - ..name = 'update' - ..returns = refer('Future<$className>') - ..modifier = MethodModifier.async - ..optionalParameters.addAll([ - ...updatableFields.map((e) => Parameter((m) => m - ..name = e.name - ..required = false - ..named = true - ..type = refer('${e.type.getDisplayString(withNullability: false)}?'))), - ]) - ..body = Code('return _instance;')), - ]), - ), - Class( - (b) => b - ..name = '_\$${className}EntityMirror' - ..extend = refer('EntityMirror<$className>') - ..constructors.add(Constructor( - (b) => b - ..constant = true - ..requiredParameters.add(Parameter((p) => p - ..toSuper = true - ..name = 'instance')), - )) - ..methods.addAll([ - Method((m) => m - ..name = 'get' - ..annotations.add(CodeExpression(Code('override'))) - ..requiredParameters.add(Parameter((p) => p - ..name = 'field' - ..type = refer('Symbol'))) - ..returns = refer('Object?') - ..body = Code(''' -return switch(field) { - ${fields.map((e) => ''' - #${e.name} => instance.${e.name} -''').join(',')}, - _ => throw Exception('Unknown property \$field'), -}; -''')), - ]), - ), - ])); - - final actualFilePath = path.basename(filePath).replaceFirst('.dart', '.entity.dart'); - - final df = path.join(path.dirname(filePath), actualFilePath); - - final emitter = DartEmitter(); - - await File(df).writeAsString( - DartFormatter().format('${library.accept(emitter)}'), - ); - } - - Stream<(ResolvedLibraryResult, String, String)> get _libraries async* { - for (var context in collection.contexts) { - final analyzedDartFiles = context.contextRoot.analyzedFiles().where((path) => - path.endsWith('.dart') && - !path.endsWith('_test.dart') && - !path.endsWith('.g.dart') && - !path.endsWith('.e.dart')); - - for (var filePath in analyzedDartFiles) { - var library = await context.currentSession.getResolvedLibrary(filePath); - if (library is ResolvedLibraryResult) { - yield (library, filePath, context.contextRoot.root.path); - } - } - } - } -} - -bool allowedTypes(FieldElement field) { - return field.getter?.isSynthetic ?? false; -} - -String _generateConstructorCode(String className, ConstructorElement constructor) { - final sb = StringBuffer()..write('$className('); - - final normalParams = constructor.type.normalParameterNames; - final namedParams = constructor.type.namedParameterTypes.keys; - - if (normalParams.isNotEmpty) { - sb - ..write(normalParams.map((name) => 'args[#$name]').join(',')) - ..write(','); - } - - if (namedParams.isNotEmpty) { - sb - ..writeln(namedParams.map((name) => '$name: args[#$name]').join(', ')) - ..write(','); - } - - return (sb..write(')')).toString(); -} - -FieldElement? getEntityField(List fields, String type) { - return fields.firstWhereOrNull((f) { - return f.metadata.firstWhereOrNull((e) => - e.element?.library?.identifier == yaroormIdentifier && - (e.element is PropertyAccessorElement) && - (e.element as PropertyAccessorElement).returnType.toString() == type) != - null; - }); -} diff --git a/type_analyzer/pubspec.lock b/type_analyzer/pubspec.lock deleted file mode 100644 index 45731c7..0000000 --- a/type_analyzer/pubspec.lock +++ /dev/null @@ -1,445 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" - url: "https://pub.dev" - source: hosted - version: "67.0.0" - analyzer: - dependency: "direct main" - description: - name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" - url: "https://pub.dev" - source: hosted - version: "6.4.1" - args: - dependency: transitive - description: - name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e - url: "https://pub.dev" - source: hosted - version: "8.9.1" - code_builder: - dependency: "direct main" - description: - name: code_builder - sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 - url: "https://pub.dev" - source: hosted - version: "4.10.0" - collection: - dependency: "direct main" - description: - name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a - url: "https://pub.dev" - source: hosted - version: "1.18.0" - convert: - dependency: transitive - description: - name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dev" - source: hosted - version: "3.1.1" - coverage: - dependency: transitive - description: - name: coverage - sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" - url: "https://pub.dev" - source: hosted - version: "1.7.2" - crypto: - dependency: transitive - description: - name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab - url: "https://pub.dev" - source: hosted - version: "3.0.3" - dart_style: - dependency: "direct main" - description: - name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" - url: "https://pub.dev" - source: hosted - version: "2.3.6" - file: - dependency: transitive - description: - name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" - url: "https://pub.dev" - source: hosted - version: "3.2.0" - glob: - dependency: transitive - description: - name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - grammer: - dependency: "direct main" - description: - name: grammer - sha256: "333c0f99fb116ae554276f64769c3a5219d314bb4fc9de43d83ae9746e0b4dd4" - url: "https://pub.dev" - source: hosted - version: "1.0.3" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - io: - dependency: transitive - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - lints: - dependency: "direct dev" - description: - name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 - url: "https://pub.dev" - source: hosted - version: "3.0.0" - logging: - dependency: transitive - description: - name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" - source: hosted - version: "0.12.16+1" - meta: - dependency: transitive - description: - name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" - url: "https://pub.dev" - source: hosted - version: "1.12.0" - mime: - dependency: transitive - description: - name: mime - sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: "direct main" - description: - name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" - url: "https://pub.dev" - source: hosted - version: "1.9.0" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - recase: - dependency: "direct main" - description: - name: recase - sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 - url: "https://pub.dev" - source: hosted - version: "4.1.0" - shelf: - dependency: transitive - description: - name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" - source: hosted - version: "1.4.1" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e - url: "https://pub.dev" - source: hosted - version: "1.1.2" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" - url: "https://pub.dev" - source: hosted - version: "1.11.1" - stemmer: - dependency: transitive - description: - name: stemmer - sha256: "9a548a410ad690152b7de946c45e8b166f157f2811fb3ad717da3721f5cee144" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" - source: hosted - version: "2.1.2" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test: - dependency: "direct dev" - description: - name: test - sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" - url: "https://pub.dev" - source: hosted - version: "1.25.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" - url: "https://pub.dev" - source: hosted - version: "0.7.0" - test_core: - dependency: transitive - description: - name: test_core - sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c - url: "https://pub.dev" - source: hosted - version: "1.3.2" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: e7d5ecd604e499358c5fe35ee828c0298a320d54455e791e9dcf73486bc8d9f0 - url: "https://pub.dev" - source: hosted - version: "14.1.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" - url: "https://pub.dev" - source: hosted - version: "0.5.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" - url: "https://pub.dev" - source: hosted - version: "2.4.4" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" - source: hosted - version: "3.1.2" -sdks: - dart: ">=3.3.1 <4.0.0" diff --git a/type_analyzer/pubspec.yaml b/type_analyzer/pubspec.yaml deleted file mode 100644 index 585da75..0000000 --- a/type_analyzer/pubspec.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: type_analyzer -description: A sample command-line application. -version: 1.0.0 -# repository: https://github.com/my_org/my_repo - -environment: - sdk: ^3.3.1 - -# Add regular dependencies here. -dependencies: - analyzer: - path: ^1.9.0 - code_builder: ^4.10.0 - dart_style: - recase: ^4.1.0 - grammer: ^1.0.3 - collection: ^1.18.0 - -dev_dependencies: - lints: ^3.0.0 - test: ^1.24.0 diff --git a/type_analyzer/test/type_analyzer_test.dart b/type_analyzer/test/type_analyzer_test.dart deleted file mode 100644 index adf7fdd..0000000 --- a/type_analyzer/test/type_analyzer_test.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:type_analyzer/type_analyzer.dart'; -import 'package:test/test.dart'; - -void main() { - test('calculate', () {}); -} From 02b0958ce04401b70b5de2d61f04c0918ede414f Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Sun, 7 Apr 2024 14:23:21 +0000 Subject: [PATCH 04/13] =?UTF-8?q?little=20baby=20steps,=20we=20making=20pr?= =?UTF-8?q?ogress=20=F0=9F=94=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/create_user.dart | 23 ++++++++++++++++++ database/config.dart | 1 - .../migrations/create_articles_table.dart | 2 +- database/migrations/create_users_table.dart | 2 +- lib/app/middlewares/api_auth_middleware.dart | 9 +++---- lib/app/providers/provide_blog_services.dart | 2 -- lib/src/controllers/article_controller.dart | 5 ++-- lib/src/controllers/auth_controller.dart | 13 +++++----- lib/src/controllers/user_controller.dart | 13 ++++------ lib/src/models/user/user.dart | 2 -- lib/src/services/article_service.dart | 24 ++++++++++--------- lib/src/services/auth_service.dart | 5 ++-- lib/src/services/services.dart | 1 - lib/src/services/user_service.dart | 12 ---------- pubspec.lock | 18 +------------- pubspec.yaml | 2 -- test/backend_test.dart | 22 ++++++++--------- 17 files changed, 71 insertions(+), 85 deletions(-) create mode 100644 bin/create_user.dart delete mode 100644 lib/src/services/user_service.dart diff --git a/bin/create_user.dart b/bin/create_user.dart new file mode 100644 index 0000000..06fc690 --- /dev/null +++ b/bin/create_user.dart @@ -0,0 +1,23 @@ +import 'package:backend/src/models/article/article.dart'; +import 'package:backend/src/models/user/user.dart'; +import 'package:yaroorm/yaroorm.dart'; + +import '../database/config.dart'; + +void main() async { + DB.init(config); + + Query.addTypeDef(userTypeData); + Query.addTypeDef
(articleTypeData); + + final totalUsers = await UserQuery.max('id'); + print(totalUsers); + + // final user = await UserQuery.create( + // name: 'Felix Angelo', + // email: 'felix@angelo.com', + // password: 'hello1234', + // ); + + // print(user.toJson()); +} diff --git a/database/config.dart b/database/config.dart index e61e6c1..f94572b 100644 --- a/database/config.dart +++ b/database/config.dart @@ -1,4 +1,3 @@ -import 'package:backend/src/utils/utils.dart'; import 'package:path/path.dart' as path; import 'package:yaroo/yaroo.dart'; import 'package:yaroorm/yaroorm.dart'; diff --git a/database/migrations/create_articles_table.dart b/database/migrations/create_articles_table.dart index e354b4d..86d924a 100644 --- a/database/migrations/create_articles_table.dart +++ b/database/migrations/create_articles_table.dart @@ -1,6 +1,6 @@ import 'package:backend/src/models/article/article.dart'; import 'package:backend/src/models/user/user.dart'; -import 'package:yaroorm/migration.dart'; +import 'package:yaroorm/yaroorm.dart'; class CreateArticlesTable extends Migration { @override diff --git a/database/migrations/create_users_table.dart b/database/migrations/create_users_table.dart index fe27354..af5cff9 100644 --- a/database/migrations/create_users_table.dart +++ b/database/migrations/create_users_table.dart @@ -1,5 +1,5 @@ import 'package:backend/src/models/user/user.dart'; -import 'package:yaroorm/migration.dart'; +import 'package:yaroorm/yaroorm.dart'; class CreateUsersTable extends Migration { @override diff --git a/lib/app/middlewares/api_auth_middleware.dart b/lib/app/middlewares/api_auth_middleware.dart index 1f3e8af..3f4577e 100644 --- a/lib/app/middlewares/api_auth_middleware.dart +++ b/lib/app/middlewares/api_auth_middleware.dart @@ -1,18 +1,19 @@ -import 'package:backend/src/services/services.dart'; import 'package:yaroo/http/http.dart'; +import '../../src/models/user/user.dart'; +import '../../src/services/auth_service.dart'; + class ApiAuthMiddleware extends Middleware { final AuthService _authService; - final UserService _userService; - ApiAuthMiddleware(this._userService, this._authService); + ApiAuthMiddleware(this._authService); @override handle(Request req, Response res, NextFunction next) async { final userId = _authService.validateRequest(req); if (userId == null) return next(res.unauthorized()); - final user = await _userService.getUser(userId); + final user = await UserQuery.get(userId); if (user == null) return next(res.unauthorized()); return next(req..auth = user); diff --git a/lib/app/providers/provide_blog_services.dart b/lib/app/providers/provide_blog_services.dart index 7e558d6..9d26da2 100644 --- a/lib/app/providers/provide_blog_services.dart +++ b/lib/app/providers/provide_blog_services.dart @@ -4,8 +4,6 @@ import 'package:yaroo/http/http.dart'; class BlogServiceProvider extends ServiceProvider { @override void register() { - app.singleton(UserService()); - app.singleton(ArticleService()); } } diff --git a/lib/src/controllers/article_controller.dart b/lib/src/controllers/article_controller.dart index 01a95f4..0be8850 100644 --- a/lib/src/controllers/article_controller.dart +++ b/lib/src/controllers/article_controller.dart @@ -3,7 +3,8 @@ import 'package:backend/src/services/services.dart'; import 'package:yaroo/http/http.dart'; import 'package:yaroo/http/meta.dart'; -import '../models/models.dart'; +import '../models/article/article.dart'; +import '../models/user/user.dart'; class ArticleController extends HTTPController { final ArticleService _articleService; @@ -38,7 +39,7 @@ class ArticleController extends HTTPController { } Future delete(@param int articleId) async { - await _articleService.deleteArticle(user.id!, articleId); + await _articleService.deleteArticle(user.id, articleId); return response.json({'message': 'Article deleted'}); } diff --git a/lib/src/controllers/auth_controller.dart b/lib/src/controllers/auth_controller.dart index bbb7e42..5f05903 100644 --- a/lib/src/controllers/auth_controller.dart +++ b/lib/src/controllers/auth_controller.dart @@ -2,20 +2,19 @@ import 'dart:io'; import 'package:yaroo/http/http.dart'; import 'package:yaroo/http/meta.dart'; -import 'package:yaroorm/yaroorm.dart'; import 'package:backend/src/dto/dto.dart'; -import 'package:backend/src/models/models.dart'; import 'package:backend/src/services/services.dart'; import 'package:bcrypt/bcrypt.dart'; +import '../models/user/user.dart'; + class AuthController extends HTTPController { final AuthService _authService; - final UserService _userService; - AuthController(this._authService, this._userService); + AuthController(this._authService); Future login(@body LoginUserDTO data) async { - final user = await DB.query().whereEqual('email', data.email).findOne(); + final user = await UserQuery.equal('email', data.email).findOne(); if (user == null) return invalidLogin; final match = BCrypt.checkpw(data.password, user.password); @@ -28,13 +27,13 @@ class AuthController extends HTTPController { } Future register(@body CreateUserDTO data) async { - final existing = await DB.query().whereEqual('email', data.email).findOne(); + final existing = await UserQuery.equal('email', data.email).findOne(); if (existing != null) { return response.json(_makeError(['Email already taken']), statusCode: HttpStatus.badRequest); } final hashedPass = BCrypt.hashpw(data.password, BCrypt.gensalt()); - final newUser = await _userService.newUser(data.name, data.email, hashedPass); + final newUser = await UserQuery.create(name: data.name, email: data.email, password: hashedPass); return response.json(_userResponse(newUser)); } diff --git a/lib/src/controllers/user_controller.dart b/lib/src/controllers/user_controller.dart index ed5b53a..a594c0e 100644 --- a/lib/src/controllers/user_controller.dart +++ b/lib/src/controllers/user_controller.dart @@ -1,13 +1,10 @@ -import 'package:backend/src/models/models.dart'; -import 'package:backend/src/services/services.dart'; import 'package:yaroo/http/http.dart'; import 'package:yaroo/http/meta.dart'; -import 'package:yaroorm/yaroorm.dart'; -class UserController extends HTTPController { - final UserService userSvc; +import '../models/user/user.dart'; - UserController(this.userSvc); +class UserController extends HTTPController { + UserController(); Future currentUser() async { final user = request.auth as User; @@ -15,12 +12,12 @@ class UserController extends HTTPController { } Future index() async { - final result = await DB.query().all(); + final result = await UserQuery.all(); return jsonResponse(result); } Future show(@param int userId) async { - final user = await userSvc.getUser(userId); + final user = await UserQuery.get(userId); if (user == null) return notFound('User not found'); return jsonResponse({'user': user.toJson()}); } diff --git a/lib/src/models/user/user.dart b/lib/src/models/user/user.dart index e0da6bf..ef49242 100644 --- a/lib/src/models/user/user.dart +++ b/lib/src/models/user/user.dart @@ -1,4 +1,3 @@ -import 'package:json_annotation/json_annotation.dart'; import 'package:yaroorm/yaroorm.dart'; part 'user.g.dart'; @@ -12,7 +11,6 @@ class User extends Entity { final String email; - @JsonKey(includeToJson: false, defaultValue: '') final String password; @createdAtCol diff --git a/lib/src/services/article_service.dart b/lib/src/services/article_service.dart index 64742a7..5fd6f8f 100644 --- a/lib/src/services/article_service.dart +++ b/lib/src/services/article_service.dart @@ -4,17 +4,18 @@ import 'dart:isolate'; import 'package:backend/src/dto/article_dto.dart'; import 'package:backend/src/models/article/article.dart'; -import 'package:backend/src/models/models.dart'; import 'package:yaroo/yaroo.dart'; import 'package:yaroorm/yaroorm.dart'; import 'package:http/http.dart' as http; +import '../models/user/user.dart'; + class ArticleService { Future> getArticles({String? ownerId}) async { final query = DB.query
().orderByDesc('updatedAt'); if (ownerId == null) return query.all(); - return query.whereEqual('ownerId', ownerId).findMany(); + return query.equal('ownerId', ownerId).findMany(); } Future getArticle(int articleId) => DB.query
().get(articleId); @@ -26,26 +27,27 @@ class ArticleService { title: data.title, description: data.description, ownerId: user.id, - updatedAt: DateTime.now(), imageUrl: imageUrl, ); } Future updateArticle(User user, int articleId, CreateArticleDTO dto) async { - final userId = user.id!; - final query = DB.query
().whereEqual('id', articleId).whereEqual('ownerId', userId); + final userId = user.id; + final query = DB.query
().equal('id', articleId).equal('ownerId', userId); final article = await query.findOne(); if (article == null) return null; - article - ..title = dto.title - ..description = dto.description - ..imageUrl = dto.imageUrl; + // article + // ..title = dto.title + // ..description = dto.description + // ..imageUrl = dto.imageUrl; + + return article; - return await article.save(); + // return await article.save(); } - Future deleteArticle(int userId, int articleId) => DB.query
().whereEqual('id', articleId).delete(); + Future deleteArticle(int userId, int articleId) => DB.query
().equal('id', articleId).delete(); Future getRandomImage(String searchText) async { try { diff --git a/lib/src/services/auth_service.dart b/lib/src/services/auth_service.dart index aa82be2..9fee3a5 100644 --- a/lib/src/services/auth_service.dart +++ b/lib/src/services/auth_service.dart @@ -1,10 +1,11 @@ import 'dart:io'; -import 'package:backend/src/models/models.dart'; import 'package:collection/collection.dart'; import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart'; import 'package:yaroo/http/http.dart'; +import '../models/user/user.dart'; + class AuthService { final String jwtKey; final String issuer; @@ -14,7 +15,7 @@ class AuthService { JWTKey get _jwtKey => SecretKey(jwtKey); String getAccessTokenForUser(User user) { - final jwt = JWT(user.toJson(), issuer: issuer, subject: user.id!.toString(), jwtId: 'access-token'); + final jwt = JWT(user.toJson(), issuer: issuer, subject: user.id.toString(), jwtId: 'access-token'); return jwt.sign(_jwtKey, algorithm: JWTAlgorithm.HS256, expiresIn: Duration(hours: 1)); } diff --git a/lib/src/services/services.dart b/lib/src/services/services.dart index aa73102..22bbc5c 100644 --- a/lib/src/services/services.dart +++ b/lib/src/services/services.dart @@ -1,5 +1,4 @@ library services; -export 'user_service.dart'; export 'auth_service.dart'; export 'article_service.dart'; diff --git a/lib/src/services/user_service.dart b/lib/src/services/user_service.dart deleted file mode 100644 index f77cb60..0000000 --- a/lib/src/services/user_service.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:yaroorm/yaroorm.dart'; -import 'package:backend/src/models/models.dart'; - -class UserService { - Future newUser(String name, String email, String password) async { - return User(name, email, password: password).save(); - } - - Future getUser(int userId) async { - return DB.query().get(userId); - } -} diff --git a/pubspec.lock b/pubspec.lock index c1d8b4c..09e0385 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -403,21 +403,13 @@ packages: source: hosted version: "0.6.7" json_annotation: - dependency: "direct main" + dependency: transitive description: name: json_annotation sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted version: "4.8.1" - json_serializable: - dependency: "direct dev" - description: - name: json_serializable - sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 - url: "https://pub.dev" - source: hosted - version: "6.7.1" lints: dependency: "direct dev" description: @@ -698,14 +690,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" - source_helper: - dependency: transitive - description: - name: source_helper - sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" - url: "https://pub.dev" - source: hosted - version: "1.3.4" source_map_stack_trace: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 31e2256..f4ba99b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,7 +24,6 @@ dependencies: logger: ^2.0.2+1 dart_jsonwebtoken: ^2.12.2 - json_annotation: ^4.8.1 dependency_overrides: reflectable: @@ -36,7 +35,6 @@ dependency_overrides: dev_dependencies: lints: ^3.0.0 test: ^1.24.0 - json_serializable: ^6.7.1 melos: ^3.2.0 build_runner: yaroorm_builder: diff --git a/test/backend_test.dart b/test/backend_test.dart index d2b01f3..b687a96 100644 --- a/test/backend_test.dart +++ b/test/backend_test.dart @@ -2,6 +2,8 @@ import 'dart:convert'; import 'dart:io'; import 'package:backend/backend.dart'; +import 'package:backend/src/models/article/article.dart'; +import 'package:backend/src/models/user/user.dart'; import 'package:yaroo/yaroo.dart'; import 'package:yaroorm/yaroorm.dart'; import '../database/config.dart' as orm; @@ -92,7 +94,7 @@ void main() { }); test('should error on existing email', () async { - final randomUser = await DB.query().get(); + final randomUser = await UserQuery.get(); expect(randomUser, isA()); await testAgent @@ -181,7 +183,7 @@ void main() { authCookie = result.headers[HttpHeaders.setCookieHeader]; expect(authCookie, isNotNull); - await DB.query
().whereEqual('ownerId', currentUser!.id).delete(); + await ArticleQuery.equal('ownerId', currentUser!.id).delete(); }); group('Users', () { @@ -201,11 +203,7 @@ void main() { .expectHeader(HttpHeaders.contentTypeHeader, 'application/json; charset=utf-8') .expectBodyCustom( (body) => User.fromJson(jsonDecode(body)['user']), - isA().having( - (user) => [user.id, user.createdAt, user.updatedAt].every((e) => e != null), - 'user with properties', - isTrue, - ), + isA(), ) .test(); }); @@ -215,7 +213,7 @@ void main() { expect(randomUser, isA()); await testAgent - .get('$usersApiPath/${randomUser!.id!}') + .get('$usersApiPath/${randomUser!.id}') .expectStatus(HttpStatus.ok) .expectHeader(HttpHeaders.contentTypeHeader, 'application/json; charset=utf-8') .expectBodyCustom((body) => jsonDecode(body)['user'], randomUser.toJson()) @@ -323,7 +321,7 @@ void main() { }); test('should update article', () async { - final article = await DB.query
().whereEqual('ownerId', currentUser!.id!).findOne(); + final article = await ArticleQuery.equal('ownerId', currentUser!.id).findOne(); expect(article, isA
()); expect(article!.title, isNot('Honey')); @@ -367,7 +365,7 @@ void main() { }); test('should delete article', () async { - final article = await DB.query
().whereEqual('ownerId', currentUser!.id!).findOne(); + final article = await ArticleQuery.equal('ownerId', currentUser!.id).findOne(); expect(article, isA
()); await testAgent @@ -376,7 +374,7 @@ void main() { .expectJsonBody({'message': 'Article deleted'}) .test(); - expect(await DB.query
().get(article.id!), isNull); + expect(await DB.query
().get(article.id), isNull); }); }); @@ -401,7 +399,7 @@ void main() { }); test('should show article without auth', () async { - final article = await DB.query
().whereEqual('ownerId', currentUser!.id!).findOne(); + final article = await ArticleQuery.equal('ownerId', currentUser!.id).findOne(); expect(article, isA
()); await testAgent From 5fea52ffa8830457696cfbb1f09cb42fe48f363b Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Sat, 13 Apr 2024 16:16:55 +0000 Subject: [PATCH 05/13] use new orm structure --- .vscode/settings.json | 6 ++- analysis_options.yaml | 2 +- .../migrations/create_articles_table.dart | 12 +----- lib/src/controllers/auth_controller.dart | 9 +++-- lib/src/controllers/user_controller.dart | 4 +- lib/src/models/article/article.dart | 3 ++ lib/src/services/article_service.dart | 39 ++++++++++++------- pubspec.lock | 38 +++++++++--------- pubspec.yaml | 9 +++-- 9 files changed, 65 insertions(+), 57 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 1a87504..14a5d44 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,8 @@ { "dart.lineLength": 120, "[dart]": { - "editor.rulers": [120], + "editor.rulers": [ + 120 + ], } -} +} \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index c364757..05c54d5 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -22,7 +22,7 @@ include: package:lints/recommended.yaml analyzer: exclude: - "**.reflectable.dart" - - "**.g.dart" + # - "**.g.dart" # For more information about the core and recommended set of lints, see # https://dart.dev/go/core-lints diff --git a/database/migrations/create_articles_table.dart b/database/migrations/create_articles_table.dart index 86d924a..90a8eaa 100644 --- a/database/migrations/create_articles_table.dart +++ b/database/migrations/create_articles_table.dart @@ -1,20 +1,10 @@ import 'package:backend/src/models/article/article.dart'; -import 'package:backend/src/models/user/user.dart'; import 'package:yaroorm/yaroorm.dart'; class CreateArticlesTable extends Migration { @override void up(List schemas) { - final arc = ArticleSchema - ..foreign( - column: 'ownerId', - onKey: (fkey) => fkey.actions( - onDelete: ForeignKeyAction.cascade, - onUpdate: ForeignKeyAction.cascade, - ), - ); - - schemas.add(arc); + schemas.add(ArticleSchema); } @override diff --git a/lib/src/controllers/auth_controller.dart b/lib/src/controllers/auth_controller.dart index 5f05903..cc807dc 100644 --- a/lib/src/controllers/auth_controller.dart +++ b/lib/src/controllers/auth_controller.dart @@ -2,11 +2,12 @@ import 'dart:io'; import 'package:yaroo/http/http.dart'; import 'package:yaroo/http/meta.dart'; -import 'package:backend/src/dto/dto.dart'; -import 'package:backend/src/services/services.dart'; + import 'package:bcrypt/bcrypt.dart'; +import '../dto/dto.dart'; import '../models/user/user.dart'; +import '../services/services.dart'; class AuthController extends HTTPController { final AuthService _authService; @@ -14,7 +15,7 @@ class AuthController extends HTTPController { AuthController(this._authService); Future login(@body LoginUserDTO data) async { - final user = await UserQuery.equal('email', data.email).findOne(); + final user = await UserQuery.findByEmail(data.email); if (user == null) return invalidLogin; final match = BCrypt.checkpw(data.password, user.password); @@ -27,7 +28,7 @@ class AuthController extends HTTPController { } Future register(@body CreateUserDTO data) async { - final existing = await UserQuery.equal('email', data.email).findOne(); + final existing = await UserQuery.findByEmail(data.email); if (existing != null) { return response.json(_makeError(['Email already taken']), statusCode: HttpStatus.badRequest); } diff --git a/lib/src/controllers/user_controller.dart b/lib/src/controllers/user_controller.dart index a594c0e..366bdda 100644 --- a/lib/src/controllers/user_controller.dart +++ b/lib/src/controllers/user_controller.dart @@ -12,12 +12,12 @@ class UserController extends HTTPController { } Future index() async { - final result = await UserQuery.all(); + final result = await UserQuery.findMany(); return jsonResponse(result); } Future show(@param int userId) async { - final user = await UserQuery.get(userId); + final user = await UserQuery.findById(userId); if (user == null) return notFound('User not found'); return jsonResponse({'user': user.toJson()}); } diff --git a/lib/src/models/article/article.dart b/lib/src/models/article/article.dart index 2714a88..8e0cd5c 100644 --- a/lib/src/models/article/article.dart +++ b/lib/src/models/article/article.dart @@ -1,5 +1,7 @@ import 'package:yaroorm/yaroorm.dart'; +import '../user/user.dart'; + part 'article.g.dart'; @Table('articles', converters: [dateTimeConverter, booleanConverter]) @@ -12,6 +14,7 @@ class Article extends Entity { final String? imageUrl; + @reference(User, name: 'owner_id', onDelete: ForeignKeyAction.cascade) final int ownerId; @createdAtCol diff --git a/lib/src/services/article_service.dart b/lib/src/services/article_service.dart index 5fd6f8f..de4248c 100644 --- a/lib/src/services/article_service.dart +++ b/lib/src/services/article_service.dart @@ -12,13 +12,20 @@ import '../models/user/user.dart'; class ArticleService { Future> getArticles({String? ownerId}) async { - final query = DB.query
().orderByDesc('updatedAt'); - if (ownerId == null) return query.all(); + if (ownerId == null) { + return DB.query
().findMany( + orderBy: [OrderArticleBy.updatedAt(OrderDirection.desc)], + ); + } - return query.equal('ownerId', ownerId).findMany(); + return DB.query
().where((article) => article.ownerId(int.parse(ownerId))).findMany( + orderBy: [ + OrderArticleBy.updatedAt(OrderDirection.desc), + ], + ); } - Future getArticle(int articleId) => DB.query
().get(articleId); + Future getArticle(int articleId) => DB.query
().findById(articleId); Future
createArticle(User user, CreateArticleDTO data, {String? imageUrl}) async { imageUrl ??= await getRandomImage(data.title); @@ -32,22 +39,26 @@ class ArticleService { } Future updateArticle(User user, int articleId, CreateArticleDTO dto) async { - final userId = user.id; - final query = DB.query
().equal('id', articleId).equal('ownerId', userId); + final query = DB.query
().where((article) => article.and([ + article.id(articleId), + article.ownerId(user.id), + ])); + final article = await query.findOne(); if (article == null) return null; - // article - // ..title = dto.title - // ..description = dto.description - // ..imageUrl = dto.imageUrl; - - return article; + await query.update( + title: value(dto.title), + description: value(dto.description), + imageUrl: value(dto.imageUrl), + ); - // return await article.save(); + return query.findOne(); } - Future deleteArticle(int userId, int articleId) => DB.query
().equal('id', articleId).delete(); + Future deleteArticle(int userId, int articleId) { + return DB.query
().where((article) => article.id(articleId)).delete(); + } Future getRandomImage(String searchText) async { try { diff --git a/pubspec.lock b/pubspec.lock index 09e0385..0ecd490 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -217,22 +217,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" - copy_with_extension: - dependency: transitive - description: - name: copy_with_extension - sha256: fbcf890b0c34aedf0894f91a11a579994b61b4e04080204656b582708b5b1125 - url: "https://pub.dev" - source: hosted - version: "5.0.4" - copy_with_extension_gen: - dependency: "direct dev" - description: - name: copy_with_extension_gen - sha256: "51cd11094096d40824c8da629ca7f16f3b7cea5fc44132b679617483d43346b0" - url: "https://pub.dev" - source: hosted - version: "5.0.4" coverage: dependency: transitive description: @@ -403,13 +387,21 @@ packages: source: hosted version: "0.6.7" json_annotation: - dependency: transitive + dependency: "direct main" description: name: json_annotation sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted version: "4.8.1" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + url: "https://pub.dev" + source: hosted + version: "6.7.1" lints: dependency: "direct dev" description: @@ -690,6 +682,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" source_map_stack_trace: dependency: transitive description: @@ -966,14 +966,14 @@ packages: yaroo_cli: dependency: "direct overridden" description: - path: "../yaroorm/packages/yaroo_cli" + path: "../yaroorm/packages/orm_cli" relative: true source: path version: "1.0.0" yaroorm: dependency: "direct main" description: - path: "../yaroorm/packages/yaroorm" + path: "../yaroorm/packages/orm" relative: true source: path version: "0.0.2" diff --git a/pubspec.yaml b/pubspec.yaml index f4ba99b..76bfd41 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,24 +19,25 @@ dependencies: url: https://github.com/codekeyz/yaroo.git path: packages/yaroo yaroorm: - path: ../yaroorm/packages/yaroorm + path: ../yaroorm/packages/orm collection: ^1.18.0 logger: ^2.0.2+1 dart_jsonwebtoken: ^2.12.2 + json_annotation: ^4.8.1 dependency_overrides: reflectable: yaroo_cli: - path: ../yaroorm/packages/yaroo_cli + path: ../yaroorm/packages/orm_cli yaroorm: - path: ../yaroorm/packages/yaroorm + path: ../yaroorm/packages/orm dev_dependencies: lints: ^3.0.0 test: ^1.24.0 + json_serializable: ^6.7.1 melos: ^3.2.0 build_runner: yaroorm_builder: path: ../yaroorm/packages/generator - copy_with_extension_gen: ^5.0.4 From 0bea25ee0aab579d5639bc1e74a082e88b0bbdeb Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Sat, 13 Apr 2024 16:17:18 +0000 Subject: [PATCH 06/13] tiny fix --- lib/app/middlewares/api_auth_middleware.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app/middlewares/api_auth_middleware.dart b/lib/app/middlewares/api_auth_middleware.dart index 3f4577e..5f11a4d 100644 --- a/lib/app/middlewares/api_auth_middleware.dart +++ b/lib/app/middlewares/api_auth_middleware.dart @@ -13,7 +13,7 @@ class ApiAuthMiddleware extends Middleware { final userId = _authService.validateRequest(req); if (userId == null) return next(res.unauthorized()); - final user = await UserQuery.get(userId); + final user = await UserQuery.findById(userId); if (user == null) return next(res.unauthorized()); return next(req..auth = user); From b1ad8d20d18e18694efcd00a5cd4bbc595c97df4 Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Sun, 14 Apr 2024 06:29:56 +0000 Subject: [PATCH 07/13] wip --- lib/src/services/article_service.dart | 8 ++++---- pubspec.lock | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/src/services/article_service.dart b/lib/src/services/article_service.dart index de4248c..f23cab2 100644 --- a/lib/src/services/article_service.dart +++ b/lib/src/services/article_service.dart @@ -11,14 +11,14 @@ import 'package:http/http.dart' as http; import '../models/user/user.dart'; class ArticleService { - Future> getArticles({String? ownerId}) async { + Future> getArticles({int? ownerId}) async { if (ownerId == null) { - return DB.query
().findMany( + return ArticleQuery.findMany( orderBy: [OrderArticleBy.updatedAt(OrderDirection.desc)], ); } - return DB.query
().where((article) => article.ownerId(int.parse(ownerId))).findMany( + return ArticleQuery.where((article) => article.ownerId(ownerId)).findMany( orderBy: [ OrderArticleBy.updatedAt(OrderDirection.desc), ], @@ -39,7 +39,7 @@ class ArticleService { } Future updateArticle(User user, int articleId, CreateArticleDTO dto) async { - final query = DB.query
().where((article) => article.and([ + final query = ArticleQuery.where((article) => article.and([ article.id(articleId), article.ownerId(user.id), ])); diff --git a/pubspec.lock b/pubspec.lock index 0ecd490..7dea12f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -550,10 +550,10 @@ packages: dependency: transitive description: name: postgres - sha256: b743c8b1d4af6e2840fa1e2ce2d3376b829d097b6db7340a1154effac69cc738 + sha256: bd1df6d2f4ad71aef92dc59e867e3ba9ec22cf2212a81cf9d35aa061ce80b1ae url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.2.0" process: dependency: transitive description: @@ -750,10 +750,10 @@ packages: dependency: transitive description: name: sqflite_common_ffi - sha256: "754927d82de369a6b9e760fb60640aa81da650f35ffd468d5a992814d6022908" + sha256: "35d2fce1e971707c227cc4775cc017d5eafe06c2654c3435ebd5c3ad6c170f5f" url: "https://pub.dev" source: hosted - version: "2.3.2+1" + version: "2.3.0+4" sqlite3: dependency: transitive description: From 6b8bdd8c666a59dcc1cefb37cc76098751ba319b Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Sun, 14 Apr 2024 12:20:52 +0000 Subject: [PATCH 08/13] use new improvements from orm --- lib/src/controllers/auth_controller.dart | 9 ++++++--- lib/src/services/article_service.dart | 15 ++++++++++----- test/backend_test.dart | 24 ++++++++++++------------ 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/src/controllers/auth_controller.dart b/lib/src/controllers/auth_controller.dart index cc807dc..ee33574 100644 --- a/lib/src/controllers/auth_controller.dart +++ b/lib/src/controllers/auth_controller.dart @@ -28,9 +28,12 @@ class AuthController extends HTTPController { } Future register(@body CreateUserDTO data) async { - final existing = await UserQuery.findByEmail(data.email); - if (existing != null) { - return response.json(_makeError(['Email already taken']), statusCode: HttpStatus.badRequest); + final userExists = await UserQuery.where((user) => user.email(data.email)).exists(); + if (userExists) { + return response.json( + _makeError(['Email already taken']), + statusCode: HttpStatus.badRequest, + ); } final hashedPass = BCrypt.hashpw(data.password, BCrypt.gensalt()); diff --git a/lib/src/services/article_service.dart b/lib/src/services/article_service.dart index f23cab2..8a9f8fa 100644 --- a/lib/src/services/article_service.dart +++ b/lib/src/services/article_service.dart @@ -14,7 +14,10 @@ class ArticleService { Future> getArticles({int? ownerId}) async { if (ownerId == null) { return ArticleQuery.findMany( - orderBy: [OrderArticleBy.updatedAt(OrderDirection.desc)], + orderBy: [ + OrderArticleBy.title(OrderDirection.asc), + OrderArticleBy.updatedAt(OrderDirection.desc), + ], ); } @@ -25,7 +28,7 @@ class ArticleService { ); } - Future getArticle(int articleId) => DB.query
().findById(articleId); + Future getArticle(int articleId) => ArticleQuery.findById(articleId); Future
createArticle(User user, CreateArticleDTO data, {String? imageUrl}) async { imageUrl ??= await getRandomImage(data.title); @@ -44,8 +47,7 @@ class ArticleService { article.ownerId(user.id), ])); - final article = await query.findOne(); - if (article == null) return null; + if (!(await query.exists())) return null; await query.update( title: value(dto.title), @@ -57,7 +59,10 @@ class ArticleService { } Future deleteArticle(int userId, int articleId) { - return DB.query
().where((article) => article.id(articleId)).delete(); + return ArticleQuery.where((article) => article.and([ + article.id(articleId), + article.ownerId(userId), + ])).delete(); } Future getRandomImage(String searchText) async { diff --git a/test/backend_test.dart b/test/backend_test.dart index b687a96..6c0cfdb 100644 --- a/test/backend_test.dart +++ b/test/backend_test.dart @@ -94,7 +94,7 @@ void main() { }); test('should error on existing email', () async { - final randomUser = await UserQuery.get(); + final randomUser = await UserQuery.findOne(); expect(randomUser, isA()); await testAgent @@ -127,7 +127,7 @@ void main() { }); test('should error on in-valid credentials', () async { - final randomUser = await DB.query().get(); + final randomUser = await UserQuery.findOne(); expect(randomUser, isA()); final email = randomUser!.email; @@ -150,7 +150,7 @@ void main() { }); test('should success on valid credentials', () async { - final randomUser = await DB.query().get(); + final randomUser = await UserQuery.findOne(); expect(randomUser, isA()); final baseTest = testAgent.post(path, { @@ -172,7 +172,7 @@ void main() { User? currentUser; setUpAll(() async { - currentUser = await DB.query().get(); + currentUser = await UserQuery.findOne(); expect(currentUser, isA()); final result = await testAgent.post('$baseAPIPath/auth/login', { @@ -183,7 +183,7 @@ void main() { authCookie = result.headers[HttpHeaders.setCookieHeader]; expect(authCookie, isNotNull); - await ArticleQuery.equal('ownerId', currentUser!.id).delete(); + await ArticleQuery.where((article) => article.ownerId(currentUser!.id)).delete(); }); group('Users', () { @@ -209,7 +209,7 @@ void main() { }); test('should get user `/users/` without auth', () async { - final randomUser = await DB.query().get(); + final randomUser = await UserQuery.findOne(); expect(randomUser, isA()); await testAgent @@ -321,7 +321,7 @@ void main() { }); test('should update article', () async { - final article = await ArticleQuery.equal('ownerId', currentUser!.id).findOne(); + final article = await ArticleQuery.where((article) => article.ownerId(currentUser!.id)).findOne(); expect(article, isA
()); expect(article!.title, isNot('Honey')); @@ -354,7 +354,7 @@ void main() { .test(); const fakeId = 234239389239; - final article = await DB.query
().get(fakeId); + final article = await ArticleQuery.findById(fakeId); expect(article, isNull); await testAgent @@ -365,7 +365,7 @@ void main() { }); test('should delete article', () async { - final article = await ArticleQuery.equal('ownerId', currentUser!.id).findOne(); + final article = await ArticleQuery.findByOwnerId(currentUser!.id); expect(article, isA
()); await testAgent @@ -374,7 +374,7 @@ void main() { .expectJsonBody({'message': 'Article deleted'}) .test(); - expect(await DB.query
().get(article.id), isNull); + expect(await ArticleQuery.findById(article.id), isNull); }); }); @@ -399,7 +399,7 @@ void main() { }); test('should show article without auth', () async { - final article = await ArticleQuery.equal('ownerId', currentUser!.id).findOne(); + final article = await ArticleQuery.findByOwnerId(currentUser!.id); expect(article, isA
()); await testAgent @@ -410,7 +410,7 @@ void main() { }); test('should get Articles without auth', () async { - final articles = await DB.query
().all(); + final articles = await ArticleQuery.findMany(); expect(articles, isNotEmpty); await testAgent From 8c6f2df96493c44adefb3035560ada39ca0bf7f6 Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Wed, 17 Apr 2024 22:28:53 +0000 Subject: [PATCH 09/13] all tests passing --- lib/src/models/article/article.dart | 4 +++- lib/src/models/user/user.dart | 6 ++++-- pubspec.lock | 4 ++-- test/backend_test.dart | 5 ++++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/src/models/article/article.dart b/lib/src/models/article/article.dart index 8e0cd5c..a4d496f 100644 --- a/lib/src/models/article/article.dart +++ b/lib/src/models/article/article.dart @@ -5,7 +5,7 @@ import '../user/user.dart'; part 'article.g.dart'; @Table('articles', converters: [dateTimeConverter, booleanConverter]) -class Article extends Entity { +class Article extends Entity
{ @primaryKey final int id; @@ -33,6 +33,8 @@ class Article extends Entity { required this.updatedAt, }); + BelongsTo get owner => belongsTo(); + Map toJson() => { 'id': id, 'createdAt': createdAt.toIso8601String(), diff --git a/lib/src/models/user/user.dart b/lib/src/models/user/user.dart index ef49242..a6b5b1c 100644 --- a/lib/src/models/user/user.dart +++ b/lib/src/models/user/user.dart @@ -1,9 +1,11 @@ import 'package:yaroorm/yaroorm.dart'; +import '../article/article.dart'; + part 'user.g.dart'; @Table('users') -class User extends Entity { +class User extends Entity { @primaryKey final int id; @@ -28,7 +30,7 @@ class User extends Entity { required this.updatedAt, }); - // HasMany
get articles => hasMany
(); + HasMany get articles => hasMany
(); Map toJson() => { 'id': id, diff --git a/pubspec.lock b/pubspec.lock index 7dea12f..da86f7a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -245,10 +245,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + sha256: "6d691edde054969f0e0f26abb1b30834b5138b963793e56f69d3a9a4435e6352" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.0" dotenv: dependency: transitive description: diff --git a/test/backend_test.dart b/test/backend_test.dart index 6c0cfdb..1b4d205 100644 --- a/test/backend_test.dart +++ b/test/backend_test.dart @@ -15,6 +15,9 @@ void main() { DB.init(orm.config); + Query.addTypeDef(userTypeData); + Query.addTypeDef
(articleTypeData); + late Spookie testAgent; setUpAll(() async { @@ -183,7 +186,7 @@ void main() { authCookie = result.headers[HttpHeaders.setCookieHeader]; expect(authCookie, isNotNull); - await ArticleQuery.where((article) => article.ownerId(currentUser!.id)).delete(); + await currentUser!.articles.delete(); }); group('Users', () { From 2e37a913eea2766eb2e8e793cc489618b7e751dc Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Wed, 17 Apr 2024 22:30:28 +0000 Subject: [PATCH 10/13] tiny fix --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1b73bd2..be989c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .dart_tool/ *.g.dart *.sqlite -*.entity.dart _yoorm_tool/ From 51287d411b0e831e3462f72ab18d6532ee360654 Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Wed, 17 Apr 2024 22:31:31 +0000 Subject: [PATCH 11/13] tiny fix --- analysis_options.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 05c54d5..02ab9fa 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -22,7 +22,6 @@ include: package:lints/recommended.yaml analyzer: exclude: - "**.reflectable.dart" - # - "**.g.dart" # For more information about the core and recommended set of lints, see # https://dart.dev/go/core-lints From 19b33ec75a76312fd86611cd11a4ebfc4d6efc9b Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Wed, 17 Apr 2024 22:32:05 +0000 Subject: [PATCH 12/13] remove test code --- bin/create_user.dart | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 bin/create_user.dart diff --git a/bin/create_user.dart b/bin/create_user.dart deleted file mode 100644 index 06fc690..0000000 --- a/bin/create_user.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:backend/src/models/article/article.dart'; -import 'package:backend/src/models/user/user.dart'; -import 'package:yaroorm/yaroorm.dart'; - -import '../database/config.dart'; - -void main() async { - DB.init(config); - - Query.addTypeDef(userTypeData); - Query.addTypeDef
(articleTypeData); - - final totalUsers = await UserQuery.max('id'); - print(totalUsers); - - // final user = await UserQuery.create( - // name: 'Felix Angelo', - // email: 'felix@angelo.com', - // password: 'hello1234', - // ); - - // print(user.toJson()); -} From c6e26871e8c1dad9aa2a7c43b0fcbc6460bec456 Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Wed, 17 Apr 2024 22:32:55 +0000 Subject: [PATCH 13/13] restore db config switching --- database/config.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/database/config.dart b/database/config.dart index f94572b..3c8cd1b 100644 --- a/database/config.dart +++ b/database/config.dart @@ -1,3 +1,4 @@ +import 'package:backend/src/utils/utils.dart'; import 'package:path/path.dart' as path; import 'package:yaroo/yaroo.dart'; import 'package:yaroorm/yaroorm.dart'; @@ -6,7 +7,7 @@ import './migrations/create_articles_table.dart'; import './migrations/create_users_table.dart'; final config = YaroormConfig( - 'test_db', + isDebugMode ? 'test_db' : 'mysql', connections: [ DatabaseConnection('test_db', DatabaseDriverType.sqlite, database: path.absolute('database', 'db.sqlite')), DatabaseConnection(