Updated orm generator

This commit is contained in:
thomashii 2021-08-01 18:55:01 +08:00
parent 3fde227c94
commit 8885a6b1c3
7 changed files with 112 additions and 51 deletions

10
.gitignore vendored
View file

@ -40,11 +40,10 @@ pubspec.lock
## VsCode ## VsCode
.vscode/ .vscode/
#.vscode/* !.vscode/settings.json
#!.vscode/settings.json !.vscode/tasks.json
#!.vscode/tasks.json !.vscode/launch.json
#!.vscode/launch.json !.vscode/extensions.json
#!.vscode/extensions.json
# IntelliJ # IntelliJ
.idea/ .idea/
@ -75,3 +74,4 @@ logs/
*.pem *.pem
.DS_Store .DS_Store
server_log.txt server_log.txt
ormapp/

View file

@ -2,15 +2,14 @@
## Short Term Goal ## Short Term Goal
* Migrate all modules to support NNBD * Fixing issues
* Fix issues and failed unit test * ORM source code generator
* ORM
* OAuth2 * OAuth2
* Proxy * Proxy
* Update examples * Update examples
* Update User Guide * Update User Guide
* Update `Angel3` website * Update website
* Generate performance metric * Performance testing
## Long Term Goal ## Long Term Goal

View file

@ -1,5 +1,13 @@
# Change Log # Change Log
## 4.0.1
* Added `useNullSafetySyntax: true` to `DartEmitter`
* Updated `*Migration` class generator to produce NNBD code
* Updated `*Query` class generator to produce NNBD code
* Updated `*QueryWhere` class generator to produce NNBD code
* Updated `*QueryValues` class generator to produce NNBD code
## 4.0.0 ## 4.0.0
* Fixed `BuildContext` cast error * Fixed `BuildContext` cast error

View file

@ -1,6 +1,6 @@
# Angel3 ORM Generator # Angel3 ORM Generator
[![version](https://img.shields.io/badge/pub-v4.0.0-brightgreen)](https://pub.dartlang.org/packages/angel3_orm_generator) [![version](https://img.shields.io/badge/pub-v4.0.1-brightgreen)](https://pub.dartlang.org/packages/angel3_orm_generator)
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety) [![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion) [![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)

View file

@ -45,17 +45,25 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
var resolver = buildStep.resolver; var resolver = buildStep.resolver;
var ctx = await buildOrmContext({}, element, annotation, buildStep, var ctx = await buildOrmContext({}, element, annotation, buildStep,
resolver, autoSnakeCaseNames != false); resolver, autoSnakeCaseNames != false);
var lib = generateMigrationLibrary(ctx, element, resolver, buildStep);
//if (lib == null) return null; if (ctx == null) {
return DartFormatter().format(lib.accept(DartEmitter()).toString()); throw 'Invalid ORM build context';
} }
Library generateMigrationLibrary(OrmBuildContext? ctx, ClassElement element, // Create `FooMigration` class
var lib = generateMigrationLibrary(ctx, element, resolver, buildStep);
//if (lib == null) return null;
return DartFormatter()
.format(lib.accept(DartEmitter(useNullSafetySyntax: true)).toString());
}
Library generateMigrationLibrary(OrmBuildContext ctx, ClassElement element,
Resolver resolver, BuildStep buildStep) { Resolver resolver, BuildStep buildStep) {
return Library((lib) { return Library((lib) {
lib.body.add(Class((clazz) { lib.body.add(Class((clazz) {
clazz clazz
..name = '${ctx!.buildContext.modelClassName}Migration' ..name = '${ctx.buildContext.modelClassName}Migration'
..extend = refer('Migration') ..extend = refer('Migration')
..methods ..methods
.addAll([buildUpMigration(ctx, lib), buildDownMigration(ctx)]); .addAll([buildUpMigration(ctx, lib), buildDownMigration(ctx)]);
@ -63,12 +71,13 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
}); });
} }
Method buildUpMigration(OrmBuildContext? ctx, LibraryBuilder lib) { Method buildUpMigration(OrmBuildContext ctx, LibraryBuilder lib) {
return Method((meth) { return Method((meth) {
var autoIdAndDateFields = const TypeChecker.fromRuntime(Model) var autoIdAndDateFields = const TypeChecker.fromRuntime(Model)
.isAssignableFromType(ctx!.buildContext.clazz.thisType); .isAssignableFromType(ctx.buildContext.clazz.thisType);
meth meth
..name = 'up' ..name = 'up'
..returns = refer('void')
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..requiredParameters.add(_schemaParam); ..requiredParameters.add(_schemaParam);
@ -125,9 +134,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
switch (col.type) { switch (col.type) {
case ColumnType.varChar: case ColumnType.varChar:
methodName = 'varChar'; methodName = 'varChar';
if (col.length != null) {
named['length'] = literal(col.length); named['length'] = literal(col.length);
}
break; break;
case ColumnType.serial: case ColumnType.serial:
methodName = 'serial'; methodName = 'serial';
@ -179,6 +186,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
} }
var field = table.property(methodName).call(positional, named); var field = table.property(methodName).call(positional, named);
var cascade = <Expression>[]; var cascade = <Expression>[];
var defaultValue = ctx.buildContext.defaults[name]; var defaultValue = ctx.buildContext.defaults[name];
@ -226,12 +234,23 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
} }
if (cascade.isNotEmpty) { if (cascade.isNotEmpty) {
var b = StringBuffer()..writeln(field.accept(DartEmitter())); var b = StringBuffer()
..writeln(
field.accept(DartEmitter(useNullSafetySyntax: true)));
if (cascade.length == 1) {
var ex = cascade[0];
b
..write('.')
..writeln(
ex.accept(DartEmitter(useNullSafetySyntax: true)));
} else {
for (var ex in cascade) { for (var ex in cascade) {
b b
..write('..') ..write('..')
..writeln(ex.accept(DartEmitter())); ..writeln(
ex.accept(DartEmitter(useNullSafetySyntax: true)));
}
} }
field = CodeExpression(Code(b.toString())); field = CodeExpression(Code(b.toString()));
@ -290,6 +309,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
return Method((b) { return Method((b) {
b b
..name = 'down' ..name = 'down'
..returns = refer('void')
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..requiredParameters.add(_schemaParam) ..requiredParameters.add(_schemaParam)
..body = Block((b) { ..body = Block((b) {

View file

@ -41,27 +41,39 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
if (element is ClassElement) { if (element is ClassElement) {
var ctx = await buildOrmContext({}, element, annotation, buildStep, var ctx = await buildOrmContext({}, element, annotation, buildStep,
buildStep.resolver, autoSnakeCaseNames); buildStep.resolver, autoSnakeCaseNames);
if (ctx == null) {
throw 'Invalid ORM build context';
}
var lib = buildOrmLibrary(buildStep.inputId, ctx); var lib = buildOrmLibrary(buildStep.inputId, ctx);
return lib.accept(DartEmitter()).toString();
return lib.accept(DartEmitter(useNullSafetySyntax: true)).toString();
} else { } else {
throw 'The @Orm() annotation can only be applied to classes.'; throw 'The @Orm() annotation can only be applied to classes.';
} }
} }
Library buildOrmLibrary(AssetId inputId, OrmBuildContext? ctx) { Library buildOrmLibrary(AssetId inputId, OrmBuildContext ctx) {
return Library((lib) { return Library((lib) {
// Create `FooQuery` class // Create `FooQuery` class
// Create `FooQueryWhere` class
lib.body.add(buildQueryClass(ctx)); lib.body.add(buildQueryClass(ctx));
// Create `FooQueryWhere` class
lib.body.add(buildWhereClass(ctx)); lib.body.add(buildWhereClass(ctx));
// Create `FooQueryValues` class
lib.body.add(buildValuesClass(ctx)); lib.body.add(buildValuesClass(ctx));
}); });
} }
Class buildQueryClass(OrmBuildContext? ctx) { Class buildQueryClass(OrmBuildContext ctx) {
return Class((clazz) { return Class((clazz) {
var rc = ctx!.buildContext.modelClassNameRecase; var rc = ctx.buildContext.modelClassNameRecase;
var queryWhereType = refer('${rc.pascalCase}QueryWhere'); var queryWhereType = refer('${rc.pascalCase}QueryWhere');
var nullableQueryWhereType = TypeReference((b) => b
..symbol = '${rc.pascalCase}QueryWhere'
..isNullable = true);
clazz clazz
..name = '${rc.pascalCase}Query' ..name = '${rc.pascalCase}Query'
..extend = TypeReference((b) { ..extend = TypeReference((b) {
@ -78,6 +90,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
b b
..name = 'casts' ..name = 'casts'
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..returns = TypeReference((b) => b
..symbol = 'Map'
..types.add(refer('String'))
..types.add(refer('String')))
..type = MethodType.getter ..type = MethodType.getter
..body = Block((b) { ..body = Block((b) {
var args = <String?, Expression>{}; var args = <String?, Expression>{};
@ -110,6 +126,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
clazz.methods.add(Method((m) { clazz.methods.add(Method((m) {
m m
..name = 'tableName' ..name = 'tableName'
..returns = refer('String')
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..type = MethodType.getter ..type = MethodType.getter
..body = Block((b) { ..body = Block((b) {
@ -121,6 +138,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
clazz.methods.add(Method((m) { clazz.methods.add(Method((m) {
m m
..name = 'fields' ..name = 'fields'
..returns = TypeReference((b) => b
..symbol = 'List'
..types.add(TypeReference(
(b) => b..symbol = 'String'))) //refer('List<String>')
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..type = MethodType.getter ..type = MethodType.getter
..body = Block((b) { ..body = Block((b) {
@ -136,7 +157,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
clazz.fields.add(Field((b) { clazz.fields.add(Field((b) {
b b
..name = '_where' ..name = '_where'
..type = queryWhereType; ..type = nullableQueryWhereType;
})); }));
// Add where getter // Add where getter
@ -144,10 +165,11 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
b b
..name = 'where' ..name = 'where'
..type = MethodType.getter ..type = MethodType.getter
..returns = queryWhereType ..returns = nullableQueryWhereType
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..body = Block((b) => b.addExpression(refer('_where').returned)); ..body = Block((b) => b.addExpression(refer('_where').returned));
})); }));
// newWhereClause() // newWhereClause()
clazz.methods.add(Method((b) { clazz.methods.add(Method((b) {
b b
@ -158,12 +180,14 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
queryWhereType.newInstance([refer('this')]).returned)); queryWhereType.newInstance([refer('this')]).returned));
})); }));
// Add deserialize() // Add parseRow()
clazz.methods.add(Method((m) { clazz.methods.add(Method((m) {
m m
..name = 'parseRow' ..name = 'parseRow'
..static = true ..static = true
..returns = ctx.buildContext.modelClassType ..returns = TypeReference((b) => b
..symbol = '${rc.pascalCase}'
..isNullable = true) //refer('${rc.pascalCase}?')
..requiredParameters.add(Parameter((b) => b ..requiredParameters.add(Parameter((b) => b
..name = 'row' ..name = 'row'
..type = refer('List'))) ..type = refer('List')))
@ -225,7 +249,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
.call([skipToList]); .call([skipToList]);
if (relation.type == RelationshipType.hasMany) { if (relation.type == RelationshipType.hasMany) {
parsed = literalList([parsed]); parsed = literalList([parsed]);
var pp = parsed.accept(DartEmitter()); var pp = parsed.accept(DartEmitter(useNullSafetySyntax: true));
parsed = CodeExpression( parsed = CodeExpression(
Code('$pp.where((x) => x != null).toList()')); Code('$pp.where((x) => x != null).toList()'));
} }
@ -233,7 +257,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
refer('model').property('copyWith').call([], {name: parsed}); refer('model').property('copyWith').call([], {name: parsed});
var block = var block =
Block((b) => b.addExpression(refer('model').assign(expr))); Block((b) => b.addExpression(refer('model').assign(expr)));
var blockStr = block.accept(DartEmitter()); var blockStr =
block.accept(DartEmitter(useNullSafetySyntax: true));
var ifStr = 'if (row.length > $i) { $blockStr }'; var ifStr = 'if (row.length > $i) { $blockStr }';
b.statements.add(Code(ifStr)); b.statements.add(Code(ifStr));
i += relation.foreign!.effectiveFields.length; i += relation.foreign!.effectiveFields.length;
@ -243,15 +268,19 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
}); });
})); }));
// deserialize
clazz.methods.add(Method((m) { clazz.methods.add(Method((m) {
m m
..name = 'deserialize' ..name = 'deserialize'
..returns = refer('Optional<${rc.pascalCase}>')
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..requiredParameters.add(Parameter((b) => b ..requiredParameters.add(Parameter((b) => b
..name = 'row' ..name = 'row'
..type = refer('List'))) ..type = refer('List')))
..body = Block((b) { ..body = Block((b) {
b.addExpression(refer('parseRow').call([refer('row')]).returned); b.addExpression(refer('Optional.ofNullable').call([
refer('parseRow').call([refer('row')])
]).returned);
}); });
})); }));
@ -261,17 +290,18 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..optionalParameters.add(Parameter((b) => b ..optionalParameters.add(Parameter((b) => b
..named = true ..named = true
..name = 'parent' ..name = 'parent'
..type = refer('Query'))) ..type = refer('Query?')))
..optionalParameters.add(Parameter((b) => b ..optionalParameters.add(Parameter((b) => b
..named = true ..named = true
..name = 'trampoline' ..name = 'trampoline'
..type = TypeReference((b) => b ..type = refer('Set<String>?')))
..symbol = 'Set' //TypeReference((b) => b
..types.add(refer('String'))))) //..symbol = 'Set'
//..types.add(refer('String')))))
..initializers.add(Code('super(parent: parent)')) ..initializers.add(Code('super(parent: parent)'))
..body = Block((b) { ..body = Block((b) {
b.statements.addAll([ b.statements.addAll([
Code('trampoline ??= Set();'), Code('trampoline ??= <String>{};'),
Code('trampoline.add(tableName);'), Code('trampoline.add(tableName);'),
]); ]);
@ -444,7 +474,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
if (ctx.relations.values.any((r) => r.type == RelationshipType.hasMany)) { if (ctx.relations.values.any((r) => r.type == RelationshipType.hasMany)) {
for (var methodName in const ['get', 'update', 'delete']) { for (var methodName in const ['get', 'update', 'delete']) {
clazz.methods.add(Method((b) { clazz.methods.add(Method((b) {
var type = ctx.buildContext.modelClassType.accept(DartEmitter()); var type = ctx.buildContext.modelClassType
.accept(DartEmitter(useNullSafetySyntax: true));
b b
..name = methodName ..name = methodName
..annotations.add(refer('override')) ..annotations.add(refer('override'))
@ -460,8 +491,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
// This is only allowed with lists. // This is only allowed with lists.
var field = var field =
ctx.buildContext.fields.firstWhere((f) => f.name == name); ctx.buildContext.fields.firstWhere((f) => f.name == name);
var typeLiteral = var typeLiteral = convertTypeReference(field.type)
convertTypeReference(field.type).accept(DartEmitter()); .accept(DartEmitter(useNullSafetySyntax: true));
merge.add(''' merge.add('''
$name: $typeLiteral.from(l.$name ?? [])..addAll(model.$name ?? []) $name: $typeLiteral.from(l.$name ?? [])..addAll(model.$name ?? [])
'''); ''');
@ -497,9 +528,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
}); });
} }
Class buildWhereClass(OrmBuildContext? ctx) { Class buildWhereClass(OrmBuildContext ctx) {
return Class((clazz) { return Class((clazz) {
var rc = ctx!.buildContext.modelClassNameRecase; var rc = ctx.buildContext.modelClassNameRecase;
clazz clazz
..name = '${rc.pascalCase}QueryWhere' ..name = '${rc.pascalCase}QueryWhere'
..extend = refer('QueryWhere'); ..extend = refer('QueryWhere');
@ -508,6 +539,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
clazz.methods.add(Method((m) { clazz.methods.add(Method((m) {
m m
..name = 'expressionBuilders' ..name = 'expressionBuilders'
..returns = refer('List<SqlExpressionBuilder>')
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..type = MethodType.getter ..type = MethodType.getter
..body = Block((b) { ..body = Block((b) {
@ -601,9 +633,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
}); });
} }
Class buildValuesClass(OrmBuildContext? ctx) { Class buildValuesClass(OrmBuildContext ctx) {
return Class((clazz) { return Class((clazz) {
var rc = ctx!.buildContext.modelClassNameRecase; var rc = ctx.buildContext.modelClassNameRecase;
clazz clazz
..name = '${rc.pascalCase}QueryValues' ..name = '${rc.pascalCase}QueryValues'
..extend = refer('MapQueryValues'); ..extend = refer('MapQueryValues');
@ -612,6 +645,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
clazz.methods.add(Method((b) { clazz.methods.add(Method((b) {
b b
..name = 'casts' ..name = 'casts'
..returns = refer('Map<String, String>')
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..type = MethodType.getter ..type = MethodType.getter
..body = Block((b) { ..body = Block((b) {
@ -725,10 +759,11 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
} }
var cond = prop.notEqualTo(literalNull); var cond = prop.notEqualTo(literalNull);
var condStr = cond.accept(DartEmitter()); var condStr =
cond.accept(DartEmitter(useNullSafetySyntax: true));
var blkStr = var blkStr =
Block((b) => b.addExpression(target.assign(parsedId))) Block((b) => b.addExpression(target.assign(parsedId)))
.accept(DartEmitter()); .accept(DartEmitter(useNullSafetySyntax: true));
var ifStmt = Code('if ($condStr) { $blkStr }'); var ifStmt = Code('if ($condStr) { $blkStr }');
b.statements.add(ifStmt); b.statements.add(ifStmt);
} }

View file

@ -1,5 +1,5 @@
name: angel3_orm_generator name: angel3_orm_generator
version: 4.0.0 version: 4.0.1
description: Code generators for Angel3 ORM. Generates query builder classes. description: Code generators for Angel3 ORM. Generates query builder classes.
homepage: https://angel3-framework.web.app/ homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/orm/angel_orm_generator repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/orm/angel_orm_generator
@ -26,7 +26,6 @@ dependencies:
dev_dependencies: dev_dependencies:
angel3_framework: ^4.0.0 angel3_framework: ^4.0.0
angel3_migration: ^4.0.0 angel3_migration: ^4.0.0
#angel_test: ^1.0.0
build_runner: ^2.0.1 build_runner: ^2.0.1
pedantic: ^1.11.0 pedantic: ^1.11.0
postgres: ^2.3.2 postgres: ^2.3.2