Updated orm generator
This commit is contained in:
parent
d2c6750225
commit
c989df244c
1 changed files with 47 additions and 17 deletions
|
@ -17,6 +17,7 @@ var floatTypes = [
|
||||||
const ColumnType('double precision'),
|
const ColumnType('double precision'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// ORM Builder
|
||||||
Builder ormBuilder(BuilderOptions options) {
|
Builder ormBuilder(BuilderOptions options) {
|
||||||
return SharedPartBuilder([
|
return SharedPartBuilder([
|
||||||
OrmGenerator(
|
OrmGenerator(
|
||||||
|
@ -73,6 +74,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
var rc = ctx.buildContext.modelClassNameRecase;
|
var rc = ctx.buildContext.modelClassNameRecase;
|
||||||
|
|
||||||
var queryWhereType = refer('${rc.pascalCase}QueryWhere');
|
var queryWhereType = refer('${rc.pascalCase}QueryWhere');
|
||||||
|
|
||||||
|
log.info('Generating ${rc.pascalCase}QueryWhere');
|
||||||
|
|
||||||
var nullableQueryWhereType = TypeReference((b) => b
|
var nullableQueryWhereType = TypeReference((b) => b
|
||||||
..symbol = '${rc.pascalCase}QueryWhere'
|
..symbol = '${rc.pascalCase}QueryWhere'
|
||||||
..isNullable = true);
|
..isNullable = true);
|
||||||
|
@ -144,8 +148,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
..name = 'fields'
|
..name = 'fields'
|
||||||
..returns = TypeReference((b) => b
|
..returns = TypeReference((b) => b
|
||||||
..symbol = 'List'
|
..symbol = 'List'
|
||||||
..types.add(TypeReference(
|
..types.add(TypeReference((b) => b..symbol = 'String')))
|
||||||
(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) {
|
||||||
|
@ -202,7 +205,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
for (var field in ctx.effectiveFields) {
|
for (var field in ctx.effectiveFields) {
|
||||||
var fType = field.type;
|
var fType = field.type;
|
||||||
Reference type = convertTypeReference(field.type);
|
Reference type = convertTypeReference(field.type);
|
||||||
if (isSpecialId(ctx, field)) type = refer('int');
|
if (isSpecialId(ctx, field)) {
|
||||||
|
type = refer('int');
|
||||||
|
}
|
||||||
|
|
||||||
var expr = (refer('row').index(literalNum(i++)));
|
var expr = (refer('row').index(literalNum(i++)));
|
||||||
if (isSpecialId(ctx, field)) {
|
if (isSpecialId(ctx, field)) {
|
||||||
|
@ -230,6 +235,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
|
|
||||||
b.statements
|
b.statements
|
||||||
.add(Code('if (row.every((x) => x == null)) { return null; }'));
|
.add(Code('if (row.every((x) => x == null)) { return null; }'));
|
||||||
|
|
||||||
b.addExpression(ctx.buildContext.modelClassType
|
b.addExpression(ctx.buildContext.modelClassType
|
||||||
.newInstance([], args).assignVar('model'));
|
.newInstance([], args).assignVar('model'));
|
||||||
|
|
||||||
|
@ -239,13 +245,14 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
RelationshipType.belongsTo,
|
RelationshipType.belongsTo,
|
||||||
RelationshipType.hasMany
|
RelationshipType.hasMany
|
||||||
].contains(relation.type)) {
|
].contains(relation.type)) {
|
||||||
|
//log.warning('Unsupported relationship for field $name');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//log.fine('Process relationship');
|
//log.fine('Process relationship');
|
||||||
var foreign = relation.foreign;
|
var foreign = relation.foreign;
|
||||||
if (foreign == null) {
|
if (foreign == null) {
|
||||||
log.warning('Foreign is null');
|
log.warning('Foreign relationship for field $name is null');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//log.fine('Detected relationship ${RelationshipType.belongsTo}');
|
//log.fine('Detected relationship ${RelationshipType.belongsTo}');
|
||||||
|
@ -257,16 +264,23 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
.call([literalNum(foreign.effectiveFields.length)])
|
.call([literalNum(foreign.effectiveFields.length)])
|
||||||
.property('toList')
|
.property('toList')
|
||||||
.call([]);
|
.call([]);
|
||||||
|
|
||||||
var parsed = refer(
|
var parsed = refer(
|
||||||
'${foreign.buildContext.modelClassNameRecase.pascalCase}Query')
|
'${foreign.buildContext.modelClassNameRecase.pascalCase}Query')
|
||||||
.property('parseRow')
|
.property('parseRow')
|
||||||
.call([skipToList]);
|
.call([skipToList]);
|
||||||
|
|
||||||
|
var baseClass = '${foreign.buildContext.originalClassName}';
|
||||||
|
// Assume: baseclass starts with "_"
|
||||||
|
//'_${foreign.buildContext.modelClassNameRecase.pascalCase}';
|
||||||
|
|
||||||
if (relation.type == RelationshipType.hasMany) {
|
if (relation.type == RelationshipType.hasMany) {
|
||||||
parsed = literalList([parsed]);
|
parsed = literalList([parsed.asA(refer(baseClass))]);
|
||||||
var pp = parsed.accept(DartEmitter(useNullSafetySyntax: true));
|
var pp = parsed.accept(DartEmitter(useNullSafetySyntax: true));
|
||||||
parsed = CodeExpression(
|
parsed = CodeExpression(Code('$pp'));
|
||||||
Code('$pp.where((x) => x != null).toList()'));
|
//Code('$pp.where((x) => x != null).toList()'));
|
||||||
}
|
}
|
||||||
|
|
||||||
var expr =
|
var expr =
|
||||||
refer('model').property('copyWith').call([], {name: parsed});
|
refer('model').property('copyWith').call([], {name: parsed});
|
||||||
var block =
|
var block =
|
||||||
|
@ -337,7 +351,6 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Note: this is where subquery fields for relations are added.
|
// Note: this is where subquery fields for relations are added.
|
||||||
|
|
||||||
ctx.relations.forEach((fieldName, relation) {
|
ctx.relations.forEach((fieldName, relation) {
|
||||||
//var name = ctx.buildContext.resolveFieldName(fieldName);
|
//var name = ctx.buildContext.resolveFieldName(fieldName);
|
||||||
if (relation.type == RelationshipType.belongsTo ||
|
if (relation.type == RelationshipType.belongsTo ||
|
||||||
|
@ -354,9 +367,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
}
|
}
|
||||||
var relationContext =
|
var relationContext =
|
||||||
relation.throughContext ?? relation.foreign;
|
relation.throughContext ?? relation.foreign;
|
||||||
log.fine(
|
|
||||||
'$fieldName relation.throughContext => ${relation.throughContext?.tableName} relation.foreign => ${relation.foreign?.tableName}');
|
|
||||||
|
|
||||||
|
//log.fine(
|
||||||
|
// '$fieldName relation.throughContext => ${relation.throughContext?.tableName} relation.foreign => ${relation.foreign?.tableName}');
|
||||||
// If this is a many-to-many, add the fields from the other object.
|
// If this is a many-to-many, add the fields from the other object.
|
||||||
var additionalStrs = relationForeign.effectiveFields.map((f) =>
|
var additionalStrs = relationForeign.effectiveFields.map((f) =>
|
||||||
relationForeign.buildContext.resolveFieldName(f.name));
|
relationForeign.buildContext.resolveFieldName(f.name));
|
||||||
|
@ -400,12 +413,12 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
b.write(' LEFT JOIN ${relationContext?.tableName}');
|
b.write(' LEFT JOIN ${relationContext?.tableName}');
|
||||||
// Figure out which field on the "through" table points to users (foreign)
|
// Figure out which field on the "through" table points to users (foreign)
|
||||||
|
|
||||||
log.fine('$fieldName query => ${b.toString()}');
|
//log.fine('$fieldName query => ${b.toString()}');
|
||||||
|
|
||||||
var throughRelation =
|
var throughRelation =
|
||||||
relationContext?.relations.values.firstWhere((e) {
|
relationContext?.relations.values.firstWhere((e) {
|
||||||
log.fine(
|
//log.fine(
|
||||||
'ForeignTable(Rel) => ${e.foreignTable}, ${relationForeign.tableName}');
|
// 'ForeignTable(Rel) => ${e.foreignTable}, ${relationForeign.tableName}');
|
||||||
return e.foreignTable == relationForeign.tableName;
|
return e.foreignTable == relationForeign.tableName;
|
||||||
}, orElse: () {
|
}, orElse: () {
|
||||||
// _Role has a many-to-many to _User through _RoleUser, but
|
// _Role has a many-to-many to _User through _RoleUser, but
|
||||||
|
@ -518,6 +531,13 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
.accept(DartEmitter(useNullSafetySyntax: true));
|
.accept(DartEmitter(useNullSafetySyntax: true));
|
||||||
b
|
b
|
||||||
..name = methodName
|
..name = methodName
|
||||||
|
..returns = TypeReference((b) => b
|
||||||
|
..symbol = 'Future'
|
||||||
|
..types.add(TypeReference((b) => b
|
||||||
|
..symbol = 'List'
|
||||||
|
..types.add(TypeReference((b) => b
|
||||||
|
..symbol = '$type'
|
||||||
|
..isNullable = false)))))
|
||||||
..annotations.add(refer('override'))
|
..annotations.add(refer('override'))
|
||||||
..requiredParameters.add(Parameter((b) => b
|
..requiredParameters.add(Parameter((b) => b
|
||||||
..name = 'executor'
|
..name = 'executor'
|
||||||
|
@ -531,13 +551,14 @@ 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 = convertTypeReference(field.type)
|
var typeLiteral = convertTypeReference(field.type)
|
||||||
.accept(DartEmitter(useNullSafetySyntax: true))
|
.accept(DartEmitter(useNullSafetySyntax: true))
|
||||||
.toString()
|
.toString()
|
||||||
.replaceAll('?', '');
|
.replaceAll('?', '');
|
||||||
|
|
||||||
merge.add('''
|
merge.add('''
|
||||||
$name: $typeLiteral.from(l.$name ?? [])..addAll(model.$name ?? [])
|
$name: $typeLiteral.from(l.$name)..addAll(model.$name)
|
||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -546,6 +567,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
|
|
||||||
var keyName =
|
var keyName =
|
||||||
findPrimaryFieldInList(ctx, ctx.buildContext.fields)?.name;
|
findPrimaryFieldInList(ctx, ctx.buildContext.fields)?.name;
|
||||||
|
|
||||||
if (keyName == null) {
|
if (keyName == null) {
|
||||||
throw '${ctx.buildContext.originalClassName} has no defined primary key.\n'
|
throw '${ctx.buildContext.originalClassName} has no defined primary key.\n'
|
||||||
'@HasMany and @ManyToMany relations require a primary key to be defined on the model.';
|
'@HasMany and @ManyToMany relations require a primary key to be defined on the model.';
|
||||||
|
@ -575,6 +597,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;
|
||||||
|
|
||||||
|
log.info('Generating ${rc.pascalCase}QueryWhere');
|
||||||
|
|
||||||
clazz
|
clazz
|
||||||
..name = '${rc.pascalCase}QueryWhere'
|
..name = '${rc.pascalCase}QueryWhere'
|
||||||
..extend = refer('QueryWhere');
|
..extend = refer('QueryWhere');
|
||||||
|
@ -625,7 +650,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
builderType = TypeReference((b) => b
|
builderType = TypeReference((b) => b
|
||||||
..symbol = 'EnumSqlExpressionBuilder'
|
..symbol = 'EnumSqlExpressionBuilder'
|
||||||
..types.add(convertTypeReference(type)));
|
..types.add(convertTypeReference(type)));
|
||||||
args.add(CodeExpression(Code('(v) => v.index')));
|
|
||||||
|
var question =
|
||||||
|
type.nullabilitySuffix == NullabilitySuffix.question ? '?' : '';
|
||||||
|
args.add(CodeExpression(Code('(v) => v$question.index as int')));
|
||||||
} else if (const TypeChecker.fromRuntime(String).isExactlyType(type)) {
|
} else if (const TypeChecker.fromRuntime(String).isExactlyType(type)) {
|
||||||
builderType = refer('StringSqlExpressionBuilder');
|
builderType = refer('StringSqlExpressionBuilder');
|
||||||
} else if (const TypeChecker.fromRuntime(bool).isExactlyType(type)) {
|
} else if (const TypeChecker.fromRuntime(bool).isExactlyType(type)) {
|
||||||
|
@ -642,7 +670,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
|
|
||||||
// Detect relationship
|
// Detect relationship
|
||||||
} else if (name.endsWith('Id')) {
|
} else if (name.endsWith('Id')) {
|
||||||
log.fine('Relationship detected = $name');
|
//log.fine('Relationship detected = $name');
|
||||||
var relation = ctx.relations[name.replaceAll('Id', '')];
|
var relation = ctx.relations[name.replaceAll('Id', '')];
|
||||||
if (relation != null) {
|
if (relation != null) {
|
||||||
//if (relation?.type != RelationshipType.belongsTo) {
|
//if (relation?.type != RelationshipType.belongsTo) {
|
||||||
|
@ -710,6 +738,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
return Class((clazz) {
|
return Class((clazz) {
|
||||||
var rc = ctx.buildContext.modelClassNameRecase;
|
var rc = ctx.buildContext.modelClassNameRecase;
|
||||||
|
|
||||||
|
log.info('Generating ${rc.pascalCase}QueryValues');
|
||||||
|
|
||||||
clazz
|
clazz
|
||||||
..name = '${rc.pascalCase}QueryValues'
|
..name = '${rc.pascalCase}QueryValues'
|
||||||
..extend = refer('MapQueryValues');
|
..extend = refer('MapQueryValues');
|
||||||
|
@ -829,7 +859,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
// Added null safety check
|
// Added null safety check
|
||||||
var parsedId = prop.property(foreignField.name);
|
var parsedId = prop.property(foreignField.name);
|
||||||
|
|
||||||
log.fine('Foreign field => ${foreignField.name}');
|
//log.fine('Foreign field => ${foreignField.name}');
|
||||||
if (foreignField.type.nullabilitySuffix ==
|
if (foreignField.type.nullabilitySuffix ==
|
||||||
NullabilitySuffix.question) {
|
NullabilitySuffix.question) {
|
||||||
parsedId = prop.nullSafeProperty(foreignField.name);
|
parsedId = prop.nullSafeProperty(foreignField.name);
|
||||||
|
|
Loading…
Reference in a new issue