dart-backend / angel

A polished, production-ready backend framework in Dart for the VM, AOT, and Flutter.
https://github.com/dukefirehawk/angel
BSD 3-Clause "New" or "Revised" License
171 stars 22 forks source link

ORM relation hasMany don't generate #76

Open jaumard opened 1 year ago

jaumard commented 1 year ago

Hey, I didn't find any examples of complex relation between tables except the doc. I have an existing database where I want to plug a Dart server. I've tried this:


import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_serialize/angel3_serialize.dart';

part 'shop.g.dart';

@Orm(tableName: 'contracts_shop', generateMigrations: false)
@serializable
abstract class _Shop {
  /// A unique identifier corresponding to this item.
  @Column(indexType: IndexType.primaryKey)
  int? id;

  String get name;

  int? get industryId;

  DateTime get added;

  @HasMany(foreignKey: 'mx_cashadvancepropos_shop_id_5f99e2ca_fk_contracts')
  List<_Supplier> get suppliers;
}

@Orm(tableName: 'suppliers_supplier', generateMigrations: false)
@serializable
abstract class _Supplier {
  /// A unique identifier corresponding to this item.
  @Column(indexType: IndexType.primaryKey)
  int? id;

  @BelongsTo(foreignKey: 'mx_cashadvancepropos_shop_id_5f99e2ca_fk_contracts')
  _Shop get shop;

  String get fullName;

  String get email;

  String get iban;

  String get accountName;

  String? get phoneNumber;

  @Column(defaultValue: true)
  bool get isEnabled;

  DateTime get lastMod;

  DateTime get added;
}

But the generation command gives:

_Shop has no field that maps to the name "mx_cashadvancepropos_shop_id_5f99e2ca_fk_contracts", but _Supplier has a @HasMany() relation that expects such a field.
dukefirehawk commented 1 year ago

I've make some adjustments on the two classes.

A couple of notes:

  1. Turning on migration can make debugging easier since can see what are the structure of the generated tables. They are not automatically executed anyway.
  2. HasMany -> foreignKey refers to Foreign Table primary key or any valid field
  3. BelongsTo -> foreignKey refers to Foreign Table primary key or any valid field
  4. Shop should be nullable type. This is a limitation as non-nullable Shop would need a default Shop to be assigned in order to remain non-nullable. There is no easy way to do this. This is one area where reflection would be very helpful.
import 'package:angel3_migration/angel3_migration.dart';
import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_serialize/angel3_serialize.dart';
import 'package:optional/optional.dart';

part 'shop.g.dart';

@Orm(tableName: 'contracts_shop')
@serializable
abstract class _Shop {
  /// A unique identifier corresponding to this item.
  @Column(indexType: IndexType.primaryKey)
  int? id;

  String get name;

  int? get industryId;

  DateTime get added;

  @HasMany(foreignKey: 'id')
  List<_Supplier> get suppliers;
}

@Orm(tableName: 'suppliers_supplier')
@serializable
abstract class _Supplier {
  /// A unique identifier corresponding to this item.
  @Column(indexType: IndexType.primaryKey)
  int? id;

  @BelongsTo(foreignKey: 'id')
  _Shop? get shop;

  String get fullName;

  String get email;

  String get iban;

  String get accountName;

  String? get phoneNumber;

  @Column(defaultValue: true)
  bool get isEnabled;

  DateTime get lastMod;

  DateTime get added;
}
alguintu commented 6 months ago

Trying to get basic relationships to work and hitting a hard wall using the latest releases:

part 'franchise.g.dart';

@orm
@serializable
abstract class _Franchise extends Model {
  String get name;

  @hasMany
  List<Zone>? get zones;
  // List<_Zone> get zones; fails to import zone as well
}
part 'zone.g.dart';

@orm
@serializable
abstract class _Zone extends Model {
  @belongsTo
  Franchise? get franchise;

  String get name;

  @DefaultsTo(0.1)
  double get franchiseRate;

  @DefaultsTo(false)
  bool get isActive;

  @DefaultsTo(false)
  bool get isSuspended;
}

I can't figure out what I'm doing wrong if any, and the documentation does not have an example for @hasMany. The moment I introduce any relationship, either hasMany or belongsTo, the generator stops:

[INFO] ------------------------------------------------------------------------
[INFO] Starting Build
[INFO] Updating asset graph completed, took 1ms
[SEVERE] angel3_serialize_generator:angel_serialize on lib/src/models/franchise/franchise.dart:

Tried to construct class "TypeReference" with null for non-nullable field "symbol".
[SEVERE] angel3_serialize_generator:angel_serialize on lib/src/models/franchise/franchise.dart:

Null check operator used on a null value
[SEVERE] angel3_orm_generator:angel3_orm on lib/src/models/franchise/franchise.dart:

Tried to construct class "TypeReference" with null for non-nullable field "symbol".
[INFO] Running build completed, took 76ms
[INFO] Caching finalized dependency graph completed, took 22ms
[SEVERE] Failed after 101ms
[INFO] ------------------------------------------------------------------------
[WARNING] build_resolvers:transitive_digests on lib/src/models/franchise/franchise.dart:
Unable to read asset, could not compute transitive deps: halo|lib/src/models/franchise/franchise.g.dart

This may cause less efficient builds, see the following doc for help:
https://github.com/dart-lang/build/blob/master/docs/faq.md#unable-to-read-asset-could-not-compute-transitive-deps
[WARNING] build_resolvers:transitive_digests on bin/migrate.dart:
Unable to read asset, could not compute transitive deps: halo|lib/src/models/franchise/franchise.g.dart

This may cause less efficient builds, see the following doc for help:
https://github.com/dart-lang/build/blob/master/docs/faq.md#unable-to-read-asset-could-not-compute-transitive-deps
[INFO] Running build completed, took 95ms
[INFO] Caching finalized dependency graph completed, took 23ms
[SEVERE] Failed after 121ms
dukefirehawk commented 6 months ago

At the moment, models with relationship need to be defined in the same file. This is a known limitation and pain point that will be addressed soon. The following revised code should work. Noted on the document, it will be updated.

import 'package:angel3_migration/angel3_migration.dart';
import 'package:angel3_serialize/angel3_serialize.dart';
import 'package:angel3_orm/angel3_orm.dart';
import 'package:optional/optional.dart';

part 'franchise.g.dart';

@orm
@serializable
abstract class _Zone extends Model {
  @belongsTo
  _Franchise? get franchise;

  String get name;

  @DefaultsTo(0.1)
  double get franchiseRate;

  @DefaultsTo(false)
  bool get isActive;

  @DefaultsTo(false)
  bool get isSuspended;
}

@orm
@serializable
abstract class _Franchise extends Model {
  String get name;

  @hasMany
  List<_Zone> get zones;
}