Updated orm generator
This commit is contained in:
parent
3fde227c94
commit
8885a6b1c3
7 changed files with 112 additions and 51 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -40,11 +40,10 @@ pubspec.lock
|
|||
|
||||
## VsCode
|
||||
.vscode/
|
||||
#.vscode/*
|
||||
#!.vscode/settings.json
|
||||
#!.vscode/tasks.json
|
||||
#!.vscode/launch.json
|
||||
#!.vscode/extensions.json
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# IntelliJ
|
||||
.idea/
|
||||
|
@ -75,3 +74,4 @@ logs/
|
|||
*.pem
|
||||
.DS_Store
|
||||
server_log.txt
|
||||
ormapp/
|
9
TODO.md
9
TODO.md
|
@ -2,15 +2,14 @@
|
|||
|
||||
## Short Term Goal
|
||||
|
||||
* Migrate all modules to support NNBD
|
||||
* Fix issues and failed unit test
|
||||
* ORM
|
||||
* Fixing issues
|
||||
* ORM source code generator
|
||||
* OAuth2
|
||||
* Proxy
|
||||
* Update examples
|
||||
* Update User Guide
|
||||
* Update `Angel3` website
|
||||
* Generate performance metric
|
||||
* Update website
|
||||
* Performance testing
|
||||
|
||||
## Long Term Goal
|
||||
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
# 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
|
||||
|
||||
* Fixed `BuildContext` cast error
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 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)
|
||||
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||
|
||||
|
|
|
@ -45,17 +45,25 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
|
|||
var resolver = buildStep.resolver;
|
||||
var ctx = await buildOrmContext({}, element, annotation, buildStep,
|
||||
resolver, autoSnakeCaseNames != false);
|
||||
var lib = generateMigrationLibrary(ctx, element, resolver, buildStep);
|
||||
//if (lib == null) return null;
|
||||
return DartFormatter().format(lib.accept(DartEmitter()).toString());
|
||||
|
||||
if (ctx == null) {
|
||||
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) {
|
||||
return Library((lib) {
|
||||
lib.body.add(Class((clazz) {
|
||||
clazz
|
||||
..name = '${ctx!.buildContext.modelClassName}Migration'
|
||||
..name = '${ctx.buildContext.modelClassName}Migration'
|
||||
..extend = refer('Migration')
|
||||
..methods
|
||||
.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) {
|
||||
var autoIdAndDateFields = const TypeChecker.fromRuntime(Model)
|
||||
.isAssignableFromType(ctx!.buildContext.clazz.thisType);
|
||||
.isAssignableFromType(ctx.buildContext.clazz.thisType);
|
||||
meth
|
||||
..name = 'up'
|
||||
..returns = refer('void')
|
||||
..annotations.add(refer('override'))
|
||||
..requiredParameters.add(_schemaParam);
|
||||
|
||||
|
@ -125,9 +134,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
|
|||
switch (col.type) {
|
||||
case ColumnType.varChar:
|
||||
methodName = 'varChar';
|
||||
if (col.length != null) {
|
||||
named['length'] = literal(col.length);
|
||||
}
|
||||
break;
|
||||
case ColumnType.serial:
|
||||
methodName = 'serial';
|
||||
|
@ -179,6 +186,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
|
|||
}
|
||||
|
||||
var field = table.property(methodName).call(positional, named);
|
||||
|
||||
var cascade = <Expression>[];
|
||||
|
||||
var defaultValue = ctx.buildContext.defaults[name];
|
||||
|
@ -226,12 +234,23 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
|
|||
}
|
||||
|
||||
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) {
|
||||
b
|
||||
..write('..')
|
||||
..writeln(ex.accept(DartEmitter()));
|
||||
..writeln(
|
||||
ex.accept(DartEmitter(useNullSafetySyntax: true)));
|
||||
}
|
||||
}
|
||||
|
||||
field = CodeExpression(Code(b.toString()));
|
||||
|
@ -290,6 +309,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
|
|||
return Method((b) {
|
||||
b
|
||||
..name = 'down'
|
||||
..returns = refer('void')
|
||||
..annotations.add(refer('override'))
|
||||
..requiredParameters.add(_schemaParam)
|
||||
..body = Block((b) {
|
||||
|
|
|
@ -41,27 +41,39 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
if (element is ClassElement) {
|
||||
var ctx = await buildOrmContext({}, element, annotation, buildStep,
|
||||
buildStep.resolver, autoSnakeCaseNames);
|
||||
if (ctx == null) {
|
||||
throw 'Invalid ORM build context';
|
||||
}
|
||||
var lib = buildOrmLibrary(buildStep.inputId, ctx);
|
||||
return lib.accept(DartEmitter()).toString();
|
||||
|
||||
return lib.accept(DartEmitter(useNullSafetySyntax: true)).toString();
|
||||
} else {
|
||||
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) {
|
||||
// Create `FooQuery` class
|
||||
// Create `FooQueryWhere` class
|
||||
lib.body.add(buildQueryClass(ctx));
|
||||
|
||||
// Create `FooQueryWhere` class
|
||||
lib.body.add(buildWhereClass(ctx));
|
||||
|
||||
// Create `FooQueryValues` class
|
||||
lib.body.add(buildValuesClass(ctx));
|
||||
});
|
||||
}
|
||||
|
||||
Class buildQueryClass(OrmBuildContext? ctx) {
|
||||
Class buildQueryClass(OrmBuildContext ctx) {
|
||||
return Class((clazz) {
|
||||
var rc = ctx!.buildContext.modelClassNameRecase;
|
||||
var rc = ctx.buildContext.modelClassNameRecase;
|
||||
|
||||
var queryWhereType = refer('${rc.pascalCase}QueryWhere');
|
||||
var nullableQueryWhereType = TypeReference((b) => b
|
||||
..symbol = '${rc.pascalCase}QueryWhere'
|
||||
..isNullable = true);
|
||||
|
||||
clazz
|
||||
..name = '${rc.pascalCase}Query'
|
||||
..extend = TypeReference((b) {
|
||||
|
@ -78,6 +90,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
b
|
||||
..name = 'casts'
|
||||
..annotations.add(refer('override'))
|
||||
..returns = TypeReference((b) => b
|
||||
..symbol = 'Map'
|
||||
..types.add(refer('String'))
|
||||
..types.add(refer('String')))
|
||||
..type = MethodType.getter
|
||||
..body = Block((b) {
|
||||
var args = <String?, Expression>{};
|
||||
|
@ -110,6 +126,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
clazz.methods.add(Method((m) {
|
||||
m
|
||||
..name = 'tableName'
|
||||
..returns = refer('String')
|
||||
..annotations.add(refer('override'))
|
||||
..type = MethodType.getter
|
||||
..body = Block((b) {
|
||||
|
@ -121,6 +138,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
clazz.methods.add(Method((m) {
|
||||
m
|
||||
..name = 'fields'
|
||||
..returns = TypeReference((b) => b
|
||||
..symbol = 'List'
|
||||
..types.add(TypeReference(
|
||||
(b) => b..symbol = 'String'))) //refer('List<String>')
|
||||
..annotations.add(refer('override'))
|
||||
..type = MethodType.getter
|
||||
..body = Block((b) {
|
||||
|
@ -136,7 +157,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
clazz.fields.add(Field((b) {
|
||||
b
|
||||
..name = '_where'
|
||||
..type = queryWhereType;
|
||||
..type = nullableQueryWhereType;
|
||||
}));
|
||||
|
||||
// Add where getter
|
||||
|
@ -144,10 +165,11 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
b
|
||||
..name = 'where'
|
||||
..type = MethodType.getter
|
||||
..returns = queryWhereType
|
||||
..returns = nullableQueryWhereType
|
||||
..annotations.add(refer('override'))
|
||||
..body = Block((b) => b.addExpression(refer('_where').returned));
|
||||
}));
|
||||
|
||||
// newWhereClause()
|
||||
clazz.methods.add(Method((b) {
|
||||
b
|
||||
|
@ -158,12 +180,14 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
queryWhereType.newInstance([refer('this')]).returned));
|
||||
}));
|
||||
|
||||
// Add deserialize()
|
||||
// Add parseRow()
|
||||
clazz.methods.add(Method((m) {
|
||||
m
|
||||
..name = 'parseRow'
|
||||
..static = true
|
||||
..returns = ctx.buildContext.modelClassType
|
||||
..returns = TypeReference((b) => b
|
||||
..symbol = '${rc.pascalCase}'
|
||||
..isNullable = true) //refer('${rc.pascalCase}?')
|
||||
..requiredParameters.add(Parameter((b) => b
|
||||
..name = 'row'
|
||||
..type = refer('List')))
|
||||
|
@ -225,7 +249,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
.call([skipToList]);
|
||||
if (relation.type == RelationshipType.hasMany) {
|
||||
parsed = literalList([parsed]);
|
||||
var pp = parsed.accept(DartEmitter());
|
||||
var pp = parsed.accept(DartEmitter(useNullSafetySyntax: true));
|
||||
parsed = CodeExpression(
|
||||
Code('$pp.where((x) => x != null).toList()'));
|
||||
}
|
||||
|
@ -233,7 +257,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
refer('model').property('copyWith').call([], {name: parsed});
|
||||
var block =
|
||||
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 }';
|
||||
b.statements.add(Code(ifStr));
|
||||
i += relation.foreign!.effectiveFields.length;
|
||||
|
@ -243,15 +268,19 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
});
|
||||
}));
|
||||
|
||||
// deserialize
|
||||
clazz.methods.add(Method((m) {
|
||||
m
|
||||
..name = 'deserialize'
|
||||
..returns = refer('Optional<${rc.pascalCase}>')
|
||||
..annotations.add(refer('override'))
|
||||
..requiredParameters.add(Parameter((b) => b
|
||||
..name = 'row'
|
||||
..type = refer('List')))
|
||||
..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
|
||||
..named = true
|
||||
..name = 'parent'
|
||||
..type = refer('Query')))
|
||||
..type = refer('Query?')))
|
||||
..optionalParameters.add(Parameter((b) => b
|
||||
..named = true
|
||||
..name = 'trampoline'
|
||||
..type = TypeReference((b) => b
|
||||
..symbol = 'Set'
|
||||
..types.add(refer('String')))))
|
||||
..type = refer('Set<String>?')))
|
||||
//TypeReference((b) => b
|
||||
//..symbol = 'Set'
|
||||
//..types.add(refer('String')))))
|
||||
..initializers.add(Code('super(parent: parent)'))
|
||||
..body = Block((b) {
|
||||
b.statements.addAll([
|
||||
Code('trampoline ??= Set();'),
|
||||
Code('trampoline ??= <String>{};'),
|
||||
Code('trampoline.add(tableName);'),
|
||||
]);
|
||||
|
||||
|
@ -444,7 +474,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
if (ctx.relations.values.any((r) => r.type == RelationshipType.hasMany)) {
|
||||
for (var methodName in const ['get', 'update', 'delete']) {
|
||||
clazz.methods.add(Method((b) {
|
||||
var type = ctx.buildContext.modelClassType.accept(DartEmitter());
|
||||
var type = ctx.buildContext.modelClassType
|
||||
.accept(DartEmitter(useNullSafetySyntax: true));
|
||||
b
|
||||
..name = methodName
|
||||
..annotations.add(refer('override'))
|
||||
|
@ -460,8 +491,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
// This is only allowed with lists.
|
||||
var field =
|
||||
ctx.buildContext.fields.firstWhere((f) => f.name == name);
|
||||
var typeLiteral =
|
||||
convertTypeReference(field.type).accept(DartEmitter());
|
||||
var typeLiteral = convertTypeReference(field.type)
|
||||
.accept(DartEmitter(useNullSafetySyntax: true));
|
||||
merge.add('''
|
||||
$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) {
|
||||
var rc = ctx!.buildContext.modelClassNameRecase;
|
||||
var rc = ctx.buildContext.modelClassNameRecase;
|
||||
clazz
|
||||
..name = '${rc.pascalCase}QueryWhere'
|
||||
..extend = refer('QueryWhere');
|
||||
|
@ -508,6 +539,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
clazz.methods.add(Method((m) {
|
||||
m
|
||||
..name = 'expressionBuilders'
|
||||
..returns = refer('List<SqlExpressionBuilder>')
|
||||
..annotations.add(refer('override'))
|
||||
..type = MethodType.getter
|
||||
..body = Block((b) {
|
||||
|
@ -601,9 +633,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
});
|
||||
}
|
||||
|
||||
Class buildValuesClass(OrmBuildContext? ctx) {
|
||||
Class buildValuesClass(OrmBuildContext ctx) {
|
||||
return Class((clazz) {
|
||||
var rc = ctx!.buildContext.modelClassNameRecase;
|
||||
var rc = ctx.buildContext.modelClassNameRecase;
|
||||
|
||||
clazz
|
||||
..name = '${rc.pascalCase}QueryValues'
|
||||
..extend = refer('MapQueryValues');
|
||||
|
@ -612,6 +645,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
clazz.methods.add(Method((b) {
|
||||
b
|
||||
..name = 'casts'
|
||||
..returns = refer('Map<String, String>')
|
||||
..annotations.add(refer('override'))
|
||||
..type = MethodType.getter
|
||||
..body = Block((b) {
|
||||
|
@ -725,10 +759,11 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
}
|
||||
|
||||
var cond = prop.notEqualTo(literalNull);
|
||||
var condStr = cond.accept(DartEmitter());
|
||||
var condStr =
|
||||
cond.accept(DartEmitter(useNullSafetySyntax: true));
|
||||
var blkStr =
|
||||
Block((b) => b.addExpression(target.assign(parsedId)))
|
||||
.accept(DartEmitter());
|
||||
.accept(DartEmitter(useNullSafetySyntax: true));
|
||||
var ifStmt = Code('if ($condStr) { $blkStr }');
|
||||
b.statements.add(ifStmt);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: angel3_orm_generator
|
||||
version: 4.0.0
|
||||
version: 4.0.1
|
||||
description: Code generators for Angel3 ORM. Generates query builder classes.
|
||||
homepage: https://angel3-framework.web.app/
|
||||
repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/orm/angel_orm_generator
|
||||
|
@ -26,7 +26,6 @@ dependencies:
|
|||
dev_dependencies:
|
||||
angel3_framework: ^4.0.0
|
||||
angel3_migration: ^4.0.0
|
||||
#angel_test: ^1.0.0
|
||||
build_runner: ^2.0.1
|
||||
pedantic: ^1.11.0
|
||||
postgres: ^2.3.2
|
||||
|
|
Loading…
Reference in a new issue