Skip to content

Commit

Permalink
chore: Look for field annotations in constructor if not on class field (
Browse files Browse the repository at this point in the history
#82)

* _

* _

* _

* bump version
  • Loading branch information
codekeyz authored Nov 5, 2024
1 parent c974488 commit bd66e52
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 26 deletions.
9 changes: 5 additions & 4 deletions lib/src/database/entity/entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class Table {
});
}

@Target({TargetKind.field})
@Target({TargetKind.field, TargetKind.parameter})
class TableColumn {
final String? name;
final bool nullable;
Expand All @@ -126,23 +126,24 @@ class TableColumn {
const TableColumn({this.name, this.nullable = false, this.unique = false});
}

@Target({TargetKind.field})
@Target({TargetKind.field, TargetKind.parameter})
class PrimaryKey extends TableColumn {
final bool autoIncrement;
const PrimaryKey({this.autoIncrement = false, super.name});
}

@Target({TargetKind.field})
@Target({TargetKind.field, TargetKind.parameter})
class CreatedAtColumn extends TableColumn {
const CreatedAtColumn() : super(name: 'createdAt', nullable: false);
}

@Target({TargetKind.field})
@Target({TargetKind.field, TargetKind.parameter})
class UpdatedAtColumn extends TableColumn {
const UpdatedAtColumn() : super(name: 'updatedAt', nullable: false);
}

/// Use this to reference other entities
@Target({TargetKind.field, TargetKind.parameter})
class bindTo {
final Type type;
final Symbol? on;
Expand Down
78 changes: 57 additions & 21 deletions packages/yaroorm_cli/lib/src/builder/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -238,26 +238,35 @@ final class ParsedEntityClass {
this.getters = const [],
});

factory ParsedEntityClass.parse(ClassElement element, {ConstantReader? reader}) {
final className = element.name;
final tableName = getTableName(element);
final fields = element.fields.where(_allowedTypes).toList(growable: false);
factory ParsedEntityClass.parse(ClassElement clazz, {ConstantReader? reader}) {
final className = clazz.name;
final tableName = getTableName(clazz);

final primaryKey = _getFieldAnnotationByType(fields, orm.PrimaryKey);
final createdAt = _getFieldAnnotationByType(fields, orm.CreatedAtColumn);
final updatedAt = _getFieldAnnotationByType(fields, orm.UpdatedAtColumn);

// Check should have primary key
if (primaryKey == null) {
throw Exception("${element.name} Entity doesn't have primary key");
}
final fields = switch (clazz.supertype?.element) {
null => clazz.fields.where(_allowedTypes).toList(growable: false),
_ => [...clazz.fields, ...(clazz.supertype!.element as ClassElement).fields]
.where(_allowedTypes)
.toList(growable: false)
};

// Validate un-named class constructor
final primaryConstructor = element.constructors.firstWhereOrNull((e) => e.name == "");
final primaryConstructor = clazz.constructors.firstWhereOrNull((e) => e.name == "");
if (primaryConstructor == null) {
throw InvalidGenerationSource(
'$className Entity does not have a default constructor',
element: element,
element: clazz,
);
}

final primaryKey = _getFieldAnnotationByType(primaryConstructor, fields, orm.PrimaryKey);
final createdAt = _getFieldAnnotationByType(primaryConstructor, fields, orm.CreatedAtColumn);
final updatedAt = _getFieldAnnotationByType(primaryConstructor, fields, orm.UpdatedAtColumn);

// Check should have primary key
if (primaryKey == null) {
throw InvalidGenerationSource(
'$className Entity does not have a primary key',
element: clazz,
);
}

Expand All @@ -274,7 +283,7 @@ final class ParsedEntityClass {
.where((e) => ![primaryKey.field, createdAt?.field, updatedAt?.field].contains(e))
.toList(growable: false);

final fieldsWithBindings = _getFieldsAndReaders(normalFields, orm.bindTo);
final fieldsWithBindings = _getFieldsAndReaders(primaryConstructor, normalFields, orm.bindTo);

final Map<Symbol, ({ParsedEntityClass entity, Symbol field, ConstantReader reader})> bindings = {};

Expand Down Expand Up @@ -306,11 +315,11 @@ final class ParsedEntityClass {
return ParsedEntityClass(
tableName,
className,
element,
clazz,
allFields: fields,
bindings: bindings,
normalFields: normalFields,
getters: element.fields.where((e) => e.getter?.isSynthetic == false).toList(),
getters: clazz.fields.where((e) => e.getter?.isSynthetic == false).toList(),
primaryKey: primaryKey,
constructor: primaryConstructor,
createdAtField: createdAt,
Expand All @@ -322,19 +331,46 @@ final class ParsedEntityClass {
return field.getter?.isSynthetic ?? false;
}

static FieldElementAndReader? _getFieldAnnotationByType(List<FieldElement> fields, Type type) {
static FieldElementAndReader? _getFieldAnnotationByType(
ConstructorElement constructor,
List<FieldElement> fields,
Type type,
) {
final checker = typeChecker(type);

for (final field in fields) {
final result = typeChecker(type).firstAnnotationOf(field, throwOnUnresolved: false);
final fieldInConstructor = constructor.children
.firstWhereOrNull((e) => e.name == field.name && e is SuperFormalParameterElement && e.metadata.isNotEmpty);

var result = checker.firstAnnotationOf(field, throwOnUnresolved: false);

if (result == null && fieldInConstructor != null) {
result = checker.firstAnnotationOf(fieldInConstructor);
}

if (result != null) {
return (field: field, reader: ConstantReader(result));
}
}
return null;
}

static Iterable<FieldElementAndReader> _getFieldsAndReaders(List<FieldElement> fields, Type type) sync* {
static Iterable<FieldElementAndReader> _getFieldsAndReaders(
ConstructorElement constructor,
List<FieldElement> fields,
Type type,
) sync* {
final checker = typeChecker(type);

for (final field in fields) {
final result = typeChecker(type).firstAnnotationOf(field, throwOnUnresolved: false);
final fieldInConstructor = constructor.children
.firstWhereOrNull((e) => e.name == field.name && e is SuperFormalParameterElement && e.metadata.isNotEmpty);
var result = checker.firstAnnotationOf(field, throwOnUnresolved: false);

if (result == null && fieldInConstructor != null) {
result = checker.firstAnnotationOf(fieldInConstructor);
}

if (result == null) continue;
yield (field: field, reader: ConstantReader(result));
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: yaroorm
description: Easy migrations, query-builder & ORM for Postgres, SQLite, MySQL & MariaDB.
version: 0.0.3+1
version: 0.0.3+2
homepage: https://docs.yaroo.dev/orm/quickstart
repository: https://github.com/codekeyz/yaroo

Expand Down

0 comments on commit bd66e52

Please sign in to comment.