Migrated angel_orm_generator

This commit is contained in:
thomashii@dukefirehawk.com 2021-05-02 19:33:32 +08:00
parent d2af68779e
commit af36c3b339
8 changed files with 214 additions and 209 deletions

View file

@ -31,8 +31,8 @@
* Created basic-sdk-2.12.x_nnbd template (1/1 test passed) <= Milestone 1 * Created basic-sdk-2.12.x_nnbd template (1/1 test passed) <= Milestone 1
* Migrated angel_serialize to 4.0.0 (0/0 test passed) * Migrated angel_serialize to 4.0.0 (0/0 test passed)
* Migrated angel_serialize_generator to 4.0.0 (33/33 tests passed) * Migrated angel_serialize_generator to 4.0.0 (33/33 tests passed)
* Updated angel_orm to 3.0.0 (0/0 tests passed) * Migrated angel_orm to 3.0.0 (0/0 tests passed)
* Updated angel_migration to 3.0.0 (0/0 tests passed) * Migrated angel_migration to 3.0.0 (0/0 tests passed)
* Added inflection2 and migrated to 1.0.0 (28/32 tests passed) * Added inflection2 and migrated to 1.0.0 (28/32 tests passed)
* Updated angel_orm_generator to 3.0.0 (in progress) * Updated angel_orm_generator to 3.0.0 (in progress)
* Updated angel_migration_runner to 3.0.0 (in progress) * Updated angel_migration_runner to 3.0.0 (in progress)

View file

@ -8,12 +8,12 @@ part 'main.g.dart';
main() async { main() async {
var query = EmployeeQuery() var query = EmployeeQuery()
..where.firstName.equals('Rich') ..where!.firstName.equals('Rich')
..where.lastName.equals('Person') ..where!.lastName.equals('Person')
..orWhere((w) => w.salary.greaterThanOrEqualTo(75000)) ..orWhere((w) => w!.salary.greaterThanOrEqualTo(75000))
..join('companies', 'company_id', 'id'); ..join('companies', 'company_id', 'id');
var richPerson = await query.getOne(_FakeExecutor()); var richPerson = await (query.getOne(_FakeExecutor()) as FutureOr<Employee>);
print(richPerson.toJson()); print(richPerson.toJson());
} }
@ -22,7 +22,7 @@ class _FakeExecutor extends QueryExecutor {
@override @override
Future<List<List>> query( Future<List<List>> query(
String tableName, String query, Map<String, dynamic> substitutionValues, String tableName, String? query, Map<String, dynamic> substitutionValues,
[returningFields]) async { [returningFields]) async {
var now = DateTime.now(); var now = DateTime.now();
print( print(
@ -41,12 +41,12 @@ class _FakeExecutor extends QueryExecutor {
@orm @orm
@serializable @serializable
abstract class _Employee extends Model { abstract class _Employee extends Model {
String get firstName; String? get firstName;
String get lastName; String? get lastName;
@Column(indexType: IndexType.unique) @Column(indexType: IndexType.unique)
String uniqueId; String? uniqueId;
double get salary; double? get salary;
} }

View file

@ -8,9 +8,9 @@ part of 'main.dart';
class EmployeeMigration extends Migration { class EmployeeMigration extends Migration {
@override @override
up(Schema schema) { void up(Schema schema) {
schema.create('employees', (table) { schema.create('employees', (table) {
table.serial('id')..primaryKey(); table.serial('id').primaryKey();
table.timeStamp('created_at'); table.timeStamp('created_at');
table.timeStamp('updated_at'); table.timeStamp('updated_at');
table.varChar('unique_id'); table.varChar('unique_id');
@ -21,7 +21,7 @@ class EmployeeMigration extends Migration {
} }
@override @override
down(Schema schema) { void down(Schema schema) {
schema.drop('employees'); schema.drop('employees');
} }
} }
@ -30,8 +30,8 @@ class EmployeeMigration extends Migration {
// OrmGenerator // OrmGenerator
// ************************************************************************** // **************************************************************************
class EmployeeQuery extends Query<Employee, EmployeeQueryWhere> { class EmployeeQuery extends Query<Employee?, EmployeeQueryWhere?> {
EmployeeQuery({Set<String> trampoline}) { EmployeeQuery({Set<String>? trampoline}) {
trampoline ??= Set(); trampoline ??= Set();
trampoline.add(tableName); trampoline.add(tableName);
_where = EmployeeQueryWhere(this); _where = EmployeeQueryWhere(this);
@ -40,7 +40,7 @@ class EmployeeQuery extends Query<Employee, EmployeeQueryWhere> {
@override @override
final EmployeeQueryValues values = EmployeeQueryValues(); final EmployeeQueryValues values = EmployeeQueryValues();
EmployeeQueryWhere _where; EmployeeQueryWhere? _where;
@override @override
get casts { get casts {
@ -66,7 +66,7 @@ class EmployeeQuery extends Query<Employee, EmployeeQueryWhere> {
} }
@override @override
EmployeeQueryWhere get where { EmployeeQueryWhere? get where {
return _where; return _where;
} }
@ -75,15 +75,15 @@ class EmployeeQuery extends Query<Employee, EmployeeQueryWhere> {
return EmployeeQueryWhere(this); return EmployeeQueryWhere(this);
} }
static Employee parseRow(List row) { static Employee? parseRow(List row) {
if (row.every((x) => x == null)) return null; if (row.every((x) => x == null)) return null;
var model = Employee( var model = Employee(
id: (row[0] as String), id: (row[0] as String?),
createdAt: (row[1] as DateTime), createdAt: (row[1] as DateTime?),
updatedAt: (row[2] as DateTime), updatedAt: (row[2] as DateTime?),
uniqueId: (row[3] as String), uniqueId: (row[3] as String?),
firstName: (row[4] as String), firstName: (row[4] as String?),
lastName: (row[5] as String), lastName: (row[5] as String?),
salary: double.tryParse(row[6].toString())); salary: double.tryParse(row[6].toString()));
return model; return model;
} }
@ -130,41 +130,41 @@ class EmployeeQueryValues extends MapQueryValues {
return {'salary': 'decimal'}; return {'salary': 'decimal'};
} }
String get id { String? get id {
return (values['id'] as String); return (values['id'] as String?);
} }
set id(String value) => values['id'] = value; set id(String? value) => values['id'] = value;
DateTime get createdAt { DateTime? get createdAt {
return (values['created_at'] as DateTime); return (values['created_at'] as DateTime?);
} }
set createdAt(DateTime value) => values['created_at'] = value; set createdAt(DateTime? value) => values['created_at'] = value;
DateTime get updatedAt { DateTime? get updatedAt {
return (values['updated_at'] as DateTime); return (values['updated_at'] as DateTime?);
} }
set updatedAt(DateTime value) => values['updated_at'] = value; set updatedAt(DateTime? value) => values['updated_at'] = value;
String get uniqueId { String? get uniqueId {
return (values['unique_id'] as String); return (values['unique_id'] as String?);
} }
set uniqueId(String value) => values['unique_id'] = value; set uniqueId(String? value) => values['unique_id'] = value;
String get firstName { String? get firstName {
return (values['first_name'] as String); return (values['first_name'] as String?);
} }
set firstName(String value) => values['first_name'] = value; set firstName(String? value) => values['first_name'] = value;
String get lastName { String? get lastName {
return (values['last_name'] as String); return (values['last_name'] as String?);
} }
set lastName(String value) => values['last_name'] = value; set lastName(String? value) => values['last_name'] = value;
double get salary { double? get salary {
return double.tryParse((values['salary'] as String)); return double.tryParse((values['salary'] as String));
} }
set salary(double value) => values['salary'] = value.toString(); set salary(double? value) => values['salary'] = value.toString();
void copyFrom(Employee model) { void copyFrom(Employee model) {
id = model.id; id = model.id;
createdAt = model.createdAt; createdAt = model.createdAt;
@ -193,36 +193,36 @@ class Employee extends _Employee {
/// A unique identifier corresponding to this item. /// A unique identifier corresponding to this item.
@override @override
String id; String? id;
/// The time at which this item was created. /// The time at which this item was created.
@override @override
DateTime createdAt; DateTime? createdAt;
/// The last time at which this item was updated. /// The last time at which this item was updated.
@override @override
DateTime updatedAt; DateTime? updatedAt;
@override @override
String uniqueId; String? uniqueId;
@override @override
final String firstName; final String? firstName;
@override @override
final String lastName; final String? lastName;
@override @override
final double salary; final double? salary;
Employee copyWith( Employee copyWith(
{String id, {String? id,
DateTime createdAt, DateTime? createdAt,
DateTime updatedAt, DateTime? updatedAt,
String uniqueId, String? uniqueId,
String firstName, String? firstName,
String lastName, String? lastName,
double salary}) { double? salary}) {
return Employee( return Employee(
id: id ?? this.id, id: id ?? this.id,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
@ -284,32 +284,29 @@ class EmployeeSerializer extends Codec<Employee, Map> {
const EmployeeSerializer(); const EmployeeSerializer();
@override @override
get encoder => const EmployeeEncoder(); EmployeeEncoder get encoder => const EmployeeEncoder();
@override @override
get decoder => const EmployeeDecoder(); EmployeeDecoder get decoder => const EmployeeDecoder();
static Employee fromMap(Map map) { static Employee fromMap(Map map) {
return Employee( return Employee(
id: map['id'] as String, id: map['id'] as String?,
createdAt: map['created_at'] != null createdAt: map['created_at'] != null
? (map['created_at'] is DateTime ? (map['created_at'] is DateTime
? (map['created_at'] as DateTime) ? (map['created_at'] as DateTime?)
: DateTime.parse(map['created_at'].toString())) : DateTime.parse(map['created_at'].toString()))
: null, : null,
updatedAt: map['updated_at'] != null updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime ? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime) ? (map['updated_at'] as DateTime?)
: DateTime.parse(map['updated_at'].toString())) : DateTime.parse(map['updated_at'].toString()))
: null, : null,
uniqueId: map['unique_id'] as String, uniqueId: map['unique_id'] as String?,
firstName: map['first_name'] as String, firstName: map['first_name'] as String?,
lastName: map['last_name'] as String, lastName: map['last_name'] as String?,
salary: map['salary'] as double); salary: map['salary'] as double?);
} }
static Map<String, dynamic> toMap(_Employee model) { static Map<String, dynamic> toMap(_Employee model) {
if (model == null) {
return null;
}
return { return {
'id': model.id, 'id': model.id,
'created_at': model.createdAt?.toIso8601String(), 'created_at': model.createdAt?.toIso8601String(),

View file

@ -29,7 +29,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
const MigrationGenerator({this.autoSnakeCaseNames = true}); const MigrationGenerator({this.autoSnakeCaseNames = true});
@override @override
Future<String> generateForAnnotatedElement( Future<String?> generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) async { Element element, ConstantReader annotation, BuildStep buildStep) async {
if (element is! ClassElement) { if (element is! ClassElement) {
throw 'Only classes can be annotated with @ORM().'; throw 'Only classes can be annotated with @ORM().';
@ -43,20 +43,19 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
} }
var resolver = await buildStep.resolver; var resolver = await buildStep.resolver;
var ctx = await buildOrmContext({}, element as ClassElement, annotation, var ctx = await buildOrmContext({}, element, annotation, buildStep,
buildStep, resolver, autoSnakeCaseNames != false); resolver, autoSnakeCaseNames != false);
var lib = generateMigrationLibrary( var lib = generateMigrationLibrary(ctx, element, resolver, buildStep);
ctx, element as ClassElement, resolver, buildStep);
if (lib == null) return null; if (lib == null) return null;
return DartFormatter().format(lib.accept(DartEmitter()).toString()); return DartFormatter().format(lib.accept(DartEmitter()).toString());
} }
Library generateMigrationLibrary(OrmBuildContext ctx, ClassElement element, 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)]);
@ -64,10 +63,10 @@ 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'
..annotations.add(refer('override')) ..annotations.add(refer('override'))
@ -80,7 +79,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
..body = Block((closureBody) { ..body = Block((closureBody) {
var table = refer('table'); var table = refer('table');
List<String> dup = []; List<String?> dup = [];
ctx.columns.forEach((name, col) { ctx.columns.forEach((name, col) {
// Skip custom-expression columns. // Skip custom-expression columns.
if (col.hasExpression) return; if (col.hasExpression) return;
@ -103,7 +102,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
(autoIdAndDateFields != false && name == 'id'))) { (autoIdAndDateFields != false && name == 'id'))) {
// Check for relationships that might duplicate // Check for relationships that might duplicate
for (var rName in ctx.relations.keys) { for (var rName in ctx.relations.keys) {
var relationship = ctx.relations[rName]; var relationship = ctx.relations[rName]!;
if (relationship.localKey == key) return; if (relationship.localKey == key) return;
} }
} }
@ -111,7 +110,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
dup.add(key); dup.add(key);
} }
String methodName; String? methodName;
List<Expression> positional = [literal(key)]; List<Expression> positional = [literal(key)];
Map<String, Expression> named = {}; Map<String, Expression> named = {};
@ -159,13 +158,13 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
if (col.length == null) { if (col.length == null) {
methodName = 'declare'; methodName = 'declare';
provColumn = columnTypeType.newInstance([ provColumn = columnTypeType.newInstance([
literal(col.type.name), literal(col.type!.name),
]); ]);
} else { } else {
methodName = 'declareColumn'; methodName = 'declareColumn';
provColumn = colType.newInstance([], { provColumn = colType.newInstance([], {
'type': columnTypeType.newInstance([ 'type': columnTypeType.newInstance([
literal(col.type.name), literal(col.type!.name),
]), ]),
'length': literal(col.length), 'length': literal(col.length),
}); });
@ -183,10 +182,10 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
if (defaultValue != null && !defaultValue.isNull) { if (defaultValue != null && !defaultValue.isNull) {
var type = defaultValue.type; var type = defaultValue.type;
Expression defaultExpr; Expression? defaultExpr;
if (const TypeChecker.fromRuntime(RawSql) if (const TypeChecker.fromRuntime(RawSql)
.isAssignableFromType(defaultValue.type)) { .isAssignableFromType(defaultValue.type!)) {
var value = var value =
ConstantReader(defaultValue).read('value').stringValue; ConstantReader(defaultValue).read('value').stringValue;
defaultExpr = defaultExpr =
@ -195,7 +194,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
// Default to enum index. // Default to enum index.
try { try {
var index = var index =
ConstantReader(defaultValue).read('index')?.intValue; ConstantReader(defaultValue).read('index').intValue;
if (index != null) defaultExpr = literalNum(index); if (index != null) defaultExpr = literalNum(index);
} catch (_) { } catch (_) {
// Extremely weird error occurs here: `Not an instance of int`. // Extremely weird error occurs here: `Not an instance of int`.
@ -203,7 +202,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
} }
} else { } else {
defaultExpr = CodeExpression( defaultExpr = CodeExpression(
Code(dartObjectToString(defaultValue)), Code(dartObjectToString(defaultValue)!),
); );
} }
@ -250,7 +249,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
var columnTypeType = refer('ColumnType'); var columnTypeType = refer('ColumnType');
var key = relationship.localKey; var key = relationship.localKey;
var keyType = relationship var keyType = relationship
.foreign.columns[relationship.foreignKey].type.name; .foreign!.columns[relationship.foreignKey!]!.type!.name;
var field = table.property('declare').call([ var field = table.property('declare').call([
literal(key), literal(key),
@ -284,7 +283,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
}); });
} }
Method buildDownMigration(OrmBuildContext ctx) { Method buildDownMigration(OrmBuildContext? ctx) {
return Method((b) { return Method((b) {
b b
..name = 'down' ..name = 'down'
@ -293,7 +292,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
..body = Block((b) { ..body = Block((b) {
var named = <String, Expression>{}; var named = <String, Expression>{};
if (ctx.relations.values.any((r) => if (ctx!.relations.values.any((r) =>
r.type == RelationshipType.hasOne || r.type == RelationshipType.hasOne ||
r.type == RelationshipType.hasMany || r.type == RelationshipType.hasMany ||
r.isManyToMany)) { r.isManyToMany)) {
@ -302,7 +301,7 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
b.addExpression(_schema b.addExpression(_schema
.property('drop') .property('drop')
.call([literalString(ctx.tableName)], named)); .call([literalString(ctx.tableName!)], named));
}); });
}); });
} }

View file

@ -10,6 +10,7 @@ import 'package:angel_serialize_generator/angel_serialize_generator.dart';
import 'package:angel_serialize_generator/build_context.dart'; import 'package:angel_serialize_generator/build_context.dart';
import 'package:angel_serialize_generator/context.dart'; import 'package:angel_serialize_generator/context.dart';
import 'package:build/build.dart'; import 'package:build/build.dart';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:inflection2/inflection2.dart'; import 'package:inflection2/inflection2.dart';
import 'package:recase/recase.dart'; import 'package:recase/recase.dart';
import 'package:source_gen/source_gen.dart'; import 'package:source_gen/source_gen.dart';
@ -19,21 +20,21 @@ import 'readers.dart';
bool isHasRelation(Relationship r) => bool isHasRelation(Relationship r) =>
r.type == RelationshipType.hasOne || r.type == RelationshipType.hasMany; r.type == RelationshipType.hasOne || r.type == RelationshipType.hasMany;
bool isSpecialId(OrmBuildContext ctx, FieldElement field) { bool isSpecialId(OrmBuildContext? ctx, FieldElement field) {
return return
// field is ShimFieldImpl && // field is ShimFieldImpl &&
field is! RelationFieldImpl && field is! RelationFieldImpl &&
(field.name == 'id' && (field.name == 'id' &&
const TypeChecker.fromRuntime(Model) const TypeChecker.fromRuntime(Model)
.isAssignableFromType(ctx.buildContext.clazz.thisType)); .isAssignableFromType(ctx!.buildContext.clazz.thisType));
} }
Element _findElement(FieldElement field) { Element _findElement(FieldElement field) {
return (field.setter == null ? field.getter : field) ?? field; return (field.setter == null ? field.getter : field) ?? field;
} }
FieldElement findPrimaryFieldInList( FieldElement? findPrimaryFieldInList(
OrmBuildContext ctx, Iterable<FieldElement> fields) { OrmBuildContext? ctx, Iterable<FieldElement> fields) {
for (var field_ in fields) { for (var field_ in fields) {
var field = field_ is RelationFieldImpl ? field_.originalField : field_; var field = field_ is RelationFieldImpl ? field_.originalField : field_;
var element = _findElement(field); var element = _findElement(field);
@ -51,39 +52,38 @@ FieldElement findPrimaryFieldInList(
} }
} }
var specialId = var specialId = fields.firstWhereOrNull((f) => isSpecialId(ctx, f));
fields.firstWhere((f) => isSpecialId(ctx, f), orElse: () => null);
// print( // print(
// 'Special ID on ${ctx.buildContext.originalClassName} => ${specialId?.name}'); // 'Special ID on ${ctx.buildContext.originalClassName} => ${specialId?.name}');
return specialId; return specialId;
} }
Future<OrmBuildContext> buildOrmContext( Future<OrmBuildContext?> buildOrmContext(
Map<String, OrmBuildContext> cache, Map<String, OrmBuildContext> cache,
ClassElement clazz, ClassElement clazz,
ConstantReader annotation, ConstantReader annotation,
BuildStep buildStep, BuildStep buildStep,
Resolver resolver, Resolver resolver,
bool autoSnakeCaseNames, bool? autoSnakeCaseNames,
{bool heedExclude = true}) async { {bool heedExclude = true}) async {
// Check for @generatedSerializable // Check for @generatedSerializable
// ignore: unused_local_variable // ignore: unused_local_variable
DartObject generatedSerializable; DartObject? generatedSerializable;
while ((generatedSerializable = while ((generatedSerializable =
const TypeChecker.fromRuntime(GeneratedSerializable) const TypeChecker.fromRuntime(GeneratedSerializable)
.firstAnnotationOf(clazz)) != .firstAnnotationOf(clazz)) !=
null) { null) {
clazz = clazz.supertype.element; clazz = clazz.supertype!.element;
} }
var id = clazz.location.components.join('-'); var id = clazz.location!.components.join('-');
if (cache.containsKey(id)) { if (cache.containsKey(id)) {
return cache[id]; return cache[id];
} }
var buildCtx = await buildContext( var buildCtx = await (buildContext(
clazz, annotation, buildStep, resolver, autoSnakeCaseNames, clazz, annotation, buildStep, resolver, autoSnakeCaseNames!,
heedExclude: heedExclude); heedExclude: heedExclude) as FutureOr<BuildContext>);
var ormAnnotation = reviveORMAnnotation(annotation); var ormAnnotation = reviveORMAnnotation(annotation);
// print( // print(
// 'tableName (${annotation.objectValue.type.name}) => ${ormAnnotation.tableName} from ${clazz.name} (${annotation.revive().namedArguments})'); // 'tableName (${annotation.objectValue.type.name}) => ${ormAnnotation.tableName} from ${clazz.name} (${annotation.revive().namedArguments})');
@ -98,7 +98,7 @@ Future<OrmBuildContext> buildOrmContext(
// Read all fields // Read all fields
for (var field in buildCtx.fields) { for (var field in buildCtx.fields) {
// Check for column annotation... // Check for column annotation...
Column column; Column? column;
var element = _findElement(field); var element = _findElement(field);
var columnAnnotation = columnTypeChecker.firstAnnotationOf(element); var columnAnnotation = columnTypeChecker.firstAnnotationOf(element);
// print('${element.name} => $columnAnnotation'); // print('${element.name} => $columnAnnotation');
@ -134,7 +134,7 @@ Future<OrmBuildContext> buildOrmContext(
// Try to find a relationship // Try to find a relationship
var el = _findElement(field); var el = _findElement(field);
el ??= field; //el ??= field;
var ann = relationshipTypeChecker.firstAnnotationOf(el); var ann = relationshipTypeChecker.firstAnnotationOf(el);
if (ann != null) { if (ann != null) {
@ -146,7 +146,7 @@ Future<OrmBuildContext> buildOrmContext(
var foreignTable = cr.peek('foreignTable')?.stringValue; var foreignTable = cr.peek('foreignTable')?.stringValue;
var cascadeOnDelete = cr.peek('cascadeOnDelete')?.boolValue == true; var cascadeOnDelete = cr.peek('cascadeOnDelete')?.boolValue == true;
var through = cr.peek('through')?.typeValue; var through = cr.peek('through')?.typeValue;
OrmBuildContext foreign, throughContext; OrmBuildContext? foreign, throughContext;
if (foreignTable == null) { if (foreignTable == null) {
// if (!isModelClass(field.type) && // if (!isModelClass(field.type) &&
@ -166,7 +166,7 @@ Future<OrmBuildContext> buildOrmContext(
const TypeChecker.fromRuntime(List) const TypeChecker.fromRuntime(List)
.isAssignableFromType(refType) && .isAssignableFromType(refType) &&
refType.typeArguments.length == 1) { refType.typeArguments.length == 1) {
refType = (refType as InterfaceType).typeArguments[0]; refType = refType.typeArguments[0];
} }
var modelType = firstModelAncestor(refType) ?? refType; var modelType = firstModelAncestor(refType) ?? refType;
@ -175,7 +175,7 @@ Future<OrmBuildContext> buildOrmContext(
cache, cache,
modelType.element as ClassElement, modelType.element as ClassElement,
ConstantReader(const TypeChecker.fromRuntime(Orm) ConstantReader(const TypeChecker.fromRuntime(Orm)
.firstAnnotationOf(modelType.element)), .firstAnnotationOf(modelType.element!)),
buildStep, buildStep,
resolver, resolver,
autoSnakeCaseNames); autoSnakeCaseNames);
@ -186,14 +186,14 @@ Future<OrmBuildContext> buildOrmContext(
cache, cache,
through.element, through.element,
ConstantReader(const TypeChecker.fromRuntime(Serializable) ConstantReader(const TypeChecker.fromRuntime(Serializable)
.firstAnnotationOf(modelType.element)), .firstAnnotationOf(modelType.element!)),
buildStep, buildStep,
resolver, resolver,
autoSnakeCaseNames); autoSnakeCaseNames);
} }
var ormAnn = const TypeChecker.fromRuntime(Orm) var ormAnn = const TypeChecker.fromRuntime(Orm)
.firstAnnotationOf(modelType.element); .firstAnnotationOf(modelType.element!);
if (ormAnn != null) { if (ormAnn != null) {
foreignTable = foreignTable =
@ -201,7 +201,7 @@ Future<OrmBuildContext> buildOrmContext(
} }
foreignTable ??= foreignTable ??=
pluralize(foreign.buildContext.modelClassNameRecase.snakeCase); pluralize(foreign!.buildContext.modelClassNameRecase.snakeCase);
} on StackOverflowError { } on StackOverflowError {
throw UnsupportedError( throw UnsupportedError(
'There is an infinite cycle between ${clazz.name} and ${field.type.name}. This triggered a stack overflow.'); 'There is an infinite cycle between ${clazz.name} and ${field.type.name}. This triggered a stack overflow.');
@ -233,7 +233,7 @@ Future<OrmBuildContext> buildOrmContext(
foreignKey ??= '${rc.snakeCase}_$localKey'; foreignKey ??= '${rc.snakeCase}_$localKey';
} else if (type == RelationshipType.belongsTo) { } else if (type == RelationshipType.belongsTo) {
foreignKey ??= foreignKey ??=
ctx.buildContext.resolveFieldName(keyName(foreign, 'foreign key')); ctx.buildContext.resolveFieldName(keyName(foreign!, 'foreign key'));
localKey ??= '${rcc.snakeCase}_$foreignKey'; localKey ??= '${rcc.snakeCase}_$foreignKey';
} }
@ -271,7 +271,7 @@ Future<OrmBuildContext> buildOrmContext(
// 'foreignKey=$foreignKey, localKey=$localKey'); // 'foreignKey=$foreignKey, localKey=$localKey');
if (relation.type == RelationshipType.belongsTo) { if (relation.type == RelationshipType.belongsTo) {
var name = ReCase(relation.localKey).camelCase; var name = ReCase(relation.localKey!).camelCase;
ctx.buildContext.aliases[name] = relation.localKey; ctx.buildContext.aliases[name] = relation.localKey;
if (!ctx.effectiveFields.any((f) => f.name == field.name)) { if (!ctx.effectiveFields.any((f) => f.name == field.name)) {
@ -290,7 +290,7 @@ Future<OrmBuildContext> buildOrmContext(
ctx.relations[field.name] = relation; ctx.relations[field.name] = relation;
} else { } else {
if (column?.type == null) { if (column.type == null) {
throw 'Cannot infer SQL column type for field "${ctx.buildContext.originalClassName}.${field.name}" with type "${field.type.displayName}".'; throw 'Cannot infer SQL column type for field "${ctx.buildContext.originalClassName}.${field.name}" with type "${field.type.displayName}".';
} }
@ -315,7 +315,7 @@ Future<OrmBuildContext> buildOrmContext(
return ctx; return ctx;
} }
ColumnType inferColumnType(DartType type) { ColumnType? inferColumnType(DartType type) {
if (const TypeChecker.fromRuntime(String).isAssignableFromType(type)) { if (const TypeChecker.fromRuntime(String).isAssignableFromType(type)) {
return ColumnType.varChar; return ColumnType.varChar;
} }
@ -345,18 +345,18 @@ ColumnType inferColumnType(DartType type) {
} }
Column reviveColumn(ConstantReader cr) { Column reviveColumn(ConstantReader cr) {
ColumnType columnType; ColumnType? columnType;
var indexTypeObj = cr.peek('indexType')?.objectValue; var indexTypeObj = cr.peek('indexType')?.objectValue;
indexTypeObj ??= cr.revive().namedArguments['indexType']; indexTypeObj ??= cr.revive().namedArguments['indexType'];
var columnObj = var columnObj =
cr.peek('type')?.objectValue?.getField('name')?.toStringValue(); cr.peek('type')?.objectValue.getField('name')?.toStringValue();
var indexType = IndexType.values[ var indexType = IndexType.values[
indexTypeObj?.getField('index')?.toIntValue() ?? IndexType.none.index]; indexTypeObj?.getField('index')?.toIntValue() ?? IndexType.none.index];
if (const TypeChecker.fromRuntime(PrimaryKey) if (const TypeChecker.fromRuntime(PrimaryKey)
.isAssignableFromType(cr.objectValue.type)) { .isAssignableFromType(cr.objectValue.type!)) {
indexType = IndexType.primaryKey; indexType = IndexType.primaryKey;
} }
@ -365,7 +365,7 @@ Column reviveColumn(ConstantReader cr) {
} }
return Column( return Column(
isNullable: cr.peek('isNullable')?.boolValue, isNullable: cr.peek('isNullable')?.boolValue ?? false,
length: cr.peek('length')?.intValue, length: cr.peek('length')?.intValue,
type: columnType, type: columnType,
indexType: indexType, indexType: indexType,
@ -378,7 +378,7 @@ const TypeChecker relationshipTypeChecker =
class OrmBuildContext { class OrmBuildContext {
final BuildContext buildContext; final BuildContext buildContext;
final Orm ormAnnotation; final Orm ormAnnotation;
final String tableName; final String? tableName;
final Map<String, Column> columns = {}; final Map<String, Column> columns = {};
final List<FieldElement> effectiveFields = []; final List<FieldElement> effectiveFields = [];
@ -411,13 +411,13 @@ class RelationFieldImpl extends ShimFieldImpl {
String get originalFieldName => originalField.name; String get originalFieldName => originalField.name;
PropertyAccessorElement get getter => originalField.getter; PropertyAccessorElement? get getter => originalField.getter;
} }
InterfaceType firstModelAncestor(DartType type) { InterfaceType? firstModelAncestor(DartType? type) {
if (type is InterfaceType) { if (type is InterfaceType) {
if (type.superclass != null && if (type.superclass != null &&
const TypeChecker.fromRuntime(Model).isExactlyType(type.superclass)) { const TypeChecker.fromRuntime(Model).isExactlyType(type.superclass!)) {
return type; return type;
} else { } else {
return type.superclass == null return type.superclass == null

View file

@ -31,7 +31,7 @@ TypeReference futureOf(String type) {
/// Builder that generates `.orm.g.dart`, with an abstract `FooOrm` class. /// Builder that generates `.orm.g.dart`, with an abstract `FooOrm` class.
class OrmGenerator extends GeneratorForAnnotation<Orm> { class OrmGenerator extends GeneratorForAnnotation<Orm> {
final bool autoSnakeCaseNames; final bool? autoSnakeCaseNames;
OrmGenerator({this.autoSnakeCaseNames}); OrmGenerator({this.autoSnakeCaseNames});
@ -48,7 +48,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
} }
} }
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 // Create `FooQueryWhere` class
@ -58,9 +58,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
}); });
} }
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');
clazz clazz
..name = '${rc.pascalCase}Query' ..name = '${rc.pascalCase}Query'
@ -80,7 +80,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..type = MethodType.getter ..type = MethodType.getter
..body = Block((b) { ..body = Block((b) {
var args = <String, Expression>{}; var args = <String?, Expression>{};
for (var field in ctx.effectiveFields) { for (var field in ctx.effectiveFields) {
var name = ctx.buildContext.resolveFieldName(field.name); var name = ctx.buildContext.resolveFieldName(field.name);
@ -113,7 +113,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..type = MethodType.getter ..type = MethodType.getter
..body = Block((b) { ..body = Block((b) {
b.addExpression(literalString(ctx.tableName).returned); b.addExpression(literalString(ctx.tableName!).returned);
}); });
})); }));
@ -126,7 +126,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..body = Block((b) { ..body = Block((b) {
var names = ctx.effectiveFields var names = ctx.effectiveFields
.map((f) => .map((f) =>
literalString(ctx.buildContext.resolveFieldName(f.name))) literalString(ctx.buildContext.resolveFieldName(f.name)!))
.toList(); .toList();
b.addExpression(literalConstList(names).returned); b.addExpression(literalConstList(names).returned);
}); });
@ -168,7 +168,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..name = 'row' ..name = 'row'
..type = refer('List'))) ..type = refer('List')))
..body = Block((b) { ..body = Block((b) {
int i = 0; var i = 0;
var args = <String, Expression>{}; var args = <String, Expression>{};
for (var field in ctx.effectiveFields) { for (var field in ctx.effectiveFields) {
@ -211,12 +211,12 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
RelationshipType.belongsTo, RelationshipType.belongsTo,
RelationshipType.hasMany RelationshipType.hasMany
].contains(relation.type)) return; ].contains(relation.type)) return;
var foreign = relation.foreign; var foreign = relation.foreign!;
var skipToList = refer('row') var skipToList = refer('row')
.property('skip') .property('skip')
.call([literalNum(i)]) .call([literalNum(i)])
.property('take') .property('take')
.call([literalNum(relation.foreign.effectiveFields.length)]) .call([literalNum(relation.foreign!.effectiveFields.length)])
.property('toList') .property('toList')
.call([]); .call([]);
var parsed = refer( var parsed = refer(
@ -236,7 +236,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
var blockStr = block.accept(DartEmitter()); var blockStr = block.accept(DartEmitter());
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;
}); });
b.addExpression(refer('model').returned); b.addExpression(refer('model').returned);
@ -277,10 +277,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
// Add any manual SQL expressions. // Add any manual SQL expressions.
ctx.columns.forEach((name, col) { ctx.columns.forEach((name, col) {
if (col != null && col.hasExpression) { if (col.hasExpression) {
var lhs = refer('expressions').index( var lhs = refer('expressions').index(
literalString(ctx.buildContext.resolveFieldName(name))); literalString(ctx.buildContext.resolveFieldName(name)!));
var rhs = literalString(col.expression); var rhs = literalString(col.expression!);
b.addExpression(lhs.assign(rhs)); b.addExpression(lhs.assign(rhs));
} }
}); });
@ -301,13 +301,15 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
// 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 = relation.foreign.effectiveFields.map((f) => var additionalStrs = relation.foreign!.effectiveFields.map(
relation.foreign.buildContext.resolveFieldName(f.name)); (f) => relation.foreign!.buildContext
var additionalFields = additionalStrs.map(literalString); .resolveFieldName(f.name));
var additionalFields = additionalStrs
.map(literalString as Expression Function(String?));
var joinArgs = [relation.localKey, relation.foreignKey] var joinArgs = [relation.localKey, relation.foreignKey]
.map(literalString) .map(literalString as Function(String?))
.toList(); .toList() as List<Expression>;
// In the case of a many-to-many, we don't generate a subquery field, // In the case of a many-to-many, we don't generate a subquery field,
// as it easily leads to stack overflows. // as it easily leads to stack overflows.
@ -318,10 +320,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
// FROM users // FROM users
// LEFT JOIN role_users ON role_users.user_id=users.id) // LEFT JOIN role_users ON role_users.user_id=users.id)
var foreignFields = additionalStrs var foreignFields = additionalStrs
.map((f) => '${relation.foreign.tableName}.$f'); .map((f) => '${relation.foreign!.tableName}.$f');
var b = StringBuffer('(SELECT '); var b = StringBuffer('(SELECT ');
// role_users.role_id // role_users.role_id
b.write('${relation.throughContext.tableName}'); b.write('${relation.throughContext!.tableName}');
b.write('.${relation.foreignKey}'); b.write('.${relation.foreignKey}');
// , <user_fields> // , <user_fields>
b.write(foreignFields.isEmpty b.write(foreignFields.isEmpty
@ -329,39 +331,39 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
: ', ' + foreignFields.join(', ')); : ', ' + foreignFields.join(', '));
// FROM users // FROM users
b.write(' FROM '); b.write(' FROM ');
b.write(relation.foreign.tableName); b.write(relation.foreign!.tableName);
// LEFT JOIN role_users // LEFT JOIN role_users
b.write(' LEFT JOIN ${relation.throughContext.tableName}'); b.write(' LEFT JOIN ${relation.throughContext!.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).
var throughRelation = var throughRelation =
relation.throughContext.relations.values.firstWhere((e) { relation.throughContext!.relations.values.firstWhere((e) {
return e.foreignTable == relation.foreign.tableName; return e.foreignTable == relation.foreign!.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
// _RoleUser has no relation pointing to _User. // _RoleUser has no relation pointing to _User.
var b = StringBuffer(); var b = StringBuffer();
b.write(ctx.buildContext.modelClassName); b.write(ctx.buildContext.modelClassName);
b.write('has a many-to-many relationship to '); b.write('has a many-to-many relationship to ');
b.write(relation.foreign.buildContext.modelClassName); b.write(relation.foreign!.buildContext.modelClassName);
b.write(' through '); b.write(' through ');
b.write( b.write(
relation.throughContext.buildContext.modelClassName); relation.throughContext!.buildContext.modelClassName);
b.write(', but '); b.write(', but ');
b.write( b.write(
relation.throughContext.buildContext.modelClassName); relation.throughContext!.buildContext.modelClassName);
b.write('has no relation pointing to '); b.write('has no relation pointing to ');
b.write(relation.foreign.buildContext.modelClassName); b.write(relation.foreign!.buildContext.modelClassName);
b.write('.'); b.write('.');
throw b.toString(); throw b.toString();
}); });
// ON role_users.user_id=users.id) // ON role_users.user_id=users.id)
b.write(' ON '); b.write(' ON ');
b.write('${relation.throughContext.tableName}'); b.write('${relation.throughContext!.tableName}');
b.write('.'); b.write('.');
b.write(throughRelation.localKey); b.write(throughRelation.localKey);
b.write('='); b.write('=');
b.write(relation.foreign.tableName); b.write(relation.foreign!.tableName);
b.write('.'); b.write('.');
b.write(throughRelation.foreignKey); b.write(throughRelation.foreignKey);
b.write(')'); b.write(')');
@ -377,7 +379,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
// There'll be a private `_field`, and then a getter, named `field`, // There'll be a private `_field`, and then a getter, named `field`,
// that returns the subquery object. // that returns the subquery object.
var foreignQueryType = refer( var foreignQueryType = refer(
foreign.buildContext.modelClassNameRecase.pascalCase + foreign!.buildContext.modelClassNameRecase.pascalCase +
'Query'); 'Query');
clazz clazz
..fields.add(Field((b) => b ..fields.add(Field((b) => b
@ -415,7 +417,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
if (manyToMany.isNotEmpty) { if (manyToMany.isNotEmpty) {
var outExprs = manyToMany.map<Expression>((e) { var outExprs = manyToMany.map<Expression>((e) {
var foreignTableName = e.value.throughContext.tableName; var foreignTableName = e.value.throughContext!.tableName;
return CodeExpression(Code(''' return CodeExpression(Code('''
(!( (!(
trampoline.contains('${ctx.tableName}') trampoline.contains('${ctx.tableName}')
@ -495,9 +497,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');
@ -519,7 +521,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
// Add builders for each field // Add builders for each field
for (var field in ctx.effectiveNormalFields) { for (var field in ctx.effectiveNormalFields) {
var name = field.name; String? name = field.name;
var args = <Expression>[]; var args = <Expression>[];
DartType type; DartType type;
Reference builderType; Reference builderType;
@ -535,7 +537,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
isSpecialId(ctx, field)) { isSpecialId(ctx, field)) {
builderType = TypeReference((b) => b builderType = TypeReference((b) => b
..symbol = 'NumericSqlExpressionBuilder' ..symbol = 'NumericSqlExpressionBuilder'
..types.add(refer(isSpecialId(ctx, field) ? 'int' : type.name))); ..types.add(refer(isSpecialId(ctx, field)
? 'int'
: type.getDisplayString(withNullability: true))));
} else if (type is InterfaceType && type.element.isEnum) { } else if (type is InterfaceType && type.element.isEnum) {
builderType = TypeReference((b) => b builderType = TypeReference((b) => b
..symbol = 'EnumSqlExpressionBuilder' ..symbol = 'EnumSqlExpressionBuilder'
@ -555,7 +559,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
.isAssignableFromType(type)) { .isAssignableFromType(type)) {
builderType = refer('ListSqlExpressionBuilder'); builderType = refer('ListSqlExpressionBuilder');
} else if (ctx.relations.containsKey(field.name)) { } else if (ctx.relations.containsKey(field.name)) {
var relation = ctx.relations[field.name]; var relation = ctx.relations[field.name]!;
if (relation.type != RelationshipType.belongsTo) { if (relation.type != RelationshipType.belongsTo) {
continue; continue;
} else { } else {
@ -566,7 +570,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
} }
} else { } else {
throw UnsupportedError( throw UnsupportedError(
'Cannot generate ORM code for field of type ${field.type.name}.'); 'Cannot generate ORM code for field of type ${field.type.getDisplayString(withNullability: false)}.');
} }
clazz.fields.add(Field((b) { clazz.fields.add(Field((b) {
@ -579,7 +583,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
refer(field.name) refer(field.name)
.assign(builderType.newInstance([ .assign(builderType.newInstance([
refer('query'), refer('query'),
literalString(ctx.buildContext.resolveFieldName(field.name)) literalString(ctx.buildContext.resolveFieldName(field.name)!)
].followedBy(args))) ].followedBy(args)))
.code, .code,
); );
@ -597,9 +601,9 @@ 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');
@ -611,7 +615,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..annotations.add(refer('override')) ..annotations.add(refer('override'))
..type = MethodType.getter ..type = MethodType.getter
..body = Block((b) { ..body = Block((b) {
var args = <String, Expression>{}; var args = <String?, Expression>{};
for (var field in ctx.effectiveFields) { for (var field in ctx.effectiveFields) {
var fType = field.type; var fType = field.type;
@ -637,7 +641,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
var type = convertTypeReference(field.type); var type = convertTypeReference(field.type);
clazz.methods.add(Method((b) { clazz.methods.add(Method((b) {
var value = refer('values').index(literalString(name)); var value = refer('values').index(literalString(name!));
if (fType is InterfaceType && fType.element.isEnum) { if (fType is InterfaceType && fType.element.isEnum) {
var asInt = value.asA(refer('int')); var asInt = value.asA(refer('int'));
@ -682,7 +686,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..name = 'value' ..name = 'value'
..type = type)) ..type = type))
..body = ..body =
refer('values').index(literalString(name)).assign(value).code; refer('values').index(literalString(name!)).assign(value).code;
})); }));
} }
@ -709,7 +713,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
var prop = refer('model').property(original); var prop = refer('model').property(original);
// Add only if present // Add only if present
var target = refer('values').index(literalString( var target = refer('values').index(literalString(
ctx.buildContext.resolveFieldName(field.name))); ctx.buildContext.resolveFieldName(field.name)!));
var foreign = field.relationship.throughContext ?? var foreign = field.relationship.throughContext ??
field.relationship.foreign; field.relationship.foreign;
var foreignField = field.relationship.findForeignField(ctx); var foreignField = field.relationship.findForeignField(ctx);

View file

@ -20,21 +20,21 @@ class ColumnReader {
bool get isNullable => reader.peek('isNullable')?.boolValue ?? true; bool get isNullable => reader.peek('isNullable')?.boolValue ?? true;
int get length => reader.peek('length')?.intValue; int? get length => reader.peek('length')?.intValue;
DartObject get defaultValue => reader.peek('defaultValue')?.objectValue; DartObject? get defaultValue => reader.peek('defaultValue')?.objectValue;
} }
class RelationshipReader { class RelationshipReader {
final int type; final int type;
final String localKey; final String? localKey;
final String foreignKey; final String? foreignKey;
final String foreignTable; final String? foreignTable;
final bool cascadeOnDelete; final bool? cascadeOnDelete;
final DartType through; final DartType? through;
final OrmBuildContext foreign; final OrmBuildContext? foreign;
final OrmBuildContext throughContext; final OrmBuildContext? throughContext;
final JoinType joinType; final JoinType? joinType;
const RelationshipReader(this.type, const RelationshipReader(this.type,
{this.localKey, {this.localKey,
@ -72,16 +72,16 @@ class RelationshipReader {
orElse: () { orElse: () {
throw '${ctx.buildContext.clazz.name} has no field that maps to the name "$localKey", ' throw '${ctx.buildContext.clazz.name} has no field that maps to the name "$localKey", '
'but it has a @HasMany() relation that expects such a field.'; 'but it has a @HasMany() relation that expects such a field.';
}); } as FieldElement Function()?);
} }
FieldElement findForeignField(OrmBuildContext ctx) { FieldElement findForeignField(OrmBuildContext? ctx) {
var foreign = throughContext ?? this.foreign; var foreign = throughContext ?? this.foreign!;
return foreign.effectiveFields.firstWhere( return foreign.effectiveFields.firstWhere(
(f) => foreign.buildContext.resolveFieldName(f.name) == foreignKey, (f) => foreign.buildContext.resolveFieldName(f.name) == foreignKey,
orElse: () { orElse: () {
throw '${foreign.buildContext.clazz.name} has no field that maps to the name "$foreignKey", ' throw '${foreign.buildContext.clazz.name} has no field that maps to the name "$foreignKey", '
'but ${ctx.buildContext.clazz.name} has a @HasMany() relation that expects such a field.'; 'but ${ctx!.buildContext.clazz.name} has a @HasMany() relation that expects such a field.';
}); } as FieldElement Function()?);
} }
} }

View file

@ -4,54 +4,59 @@ description: Code generators for Angel's ORM. Generates query builder classes.
homepage: https://github.com/dukefirehawk/angel homepage: https://github.com/dukefirehawk/angel
publish_to: none publish_to: none
environment: environment:
sdk: '>=2.10.0 <3.0.0' sdk: '>=2.12.0 <3.0.0'
dependencies: dependencies:
analyzer: ">=0.35.0 <2.0.0" analyzer: ^1.5.0
angel_model: angel_model:
git: git:
url: https://github.com/dukefirehawk/angel.git url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x ref: sdk-2.12.x_nnbd
path: packages/model path: packages/model
angel_serialize: angel_serialize:
git: git:
url: https://github.com/dukefirehawk/angel.git url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x ref: sdk-2.12.x_nnbd
path: packages/serialize/angel_serialize path: packages/serialize/angel_serialize
angel_orm: angel_orm:
git: git:
url: https://github.com/dukefirehawk/angel.git url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x ref: sdk-2.12.x_nnbd
path: packages/orm/angel_orm path: packages/orm/angel_orm
angel_serialize_generator: angel_serialize_generator:
git: git:
url: https://github.com/dukefirehawk/angel.git url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x ref: sdk-2.12.x_nnbd
path: packages/serialize/angel_serialize_generator path: packages/serialize/angel_serialize_generator
build: ^1.0.0 inflection2:
build_config: ^0.4.0 git:
code_builder: ^3.0.0 url: https://github.com/dukefirehawk/angel.git
dart_style: ^1.0.0 ref: sdk-2.12.x_nnbd
inflection2: ^0.4.2 path: packages/inflection2
meta: ^1.0.0 build: ^2.0.1
path: ^1.0.0 build_config: ^1.0.0
recase: ^3.0.1 code_builder: ^4.0.0
source_gen: ^0.9.0 dart_style: ^2.0.1
meta: ^1.3.0
path: ^1.8.0
recase: ^4.0.0
source_gen: ^1.0.0
collection: ^1.15.0-nullsafety.4
dev_dependencies: dev_dependencies:
angel_framework: angel_framework:
git: git:
url: https://github.com/dukefirehawk/angel.git url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x ref: sdk-2.12.x_nnbd
path: packages/framework path: packages/framework
angel_migration: angel_migration:
git: git:
url: https://github.com/dukefirehawk/angel.git url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x ref: sdk-2.12.x_nnbd
path: packages/orm/angel_migration path: packages/orm/angel_migration
#angel_test: ^1.0.0 #angel_test: ^1.0.0
build_runner: ^1.11.5 build_runner: ^2.0.1
collection: ^1.0.0 collection: ^1.15.0
pedantic: ^1.11.0 pedantic: ^1.11.0
postgres: ^2.2.0 postgres: ^2.3.2
# git: # git:
# url: https://github.com/dukefirehawk/postgresql-dart # url: https://github.com/dukefirehawk/postgresql-dart
test: ^1.16.5 test: ^1.17.3