Moor: Primary key not inferred when using Dart tables with inheritance

Created on 3 Apr 2020  路  2Comments  路  Source: simolus3/moor

What was I trying to do?

Setting a primary key on a Table by overriding the primaryKey property of the Table class.

What did I expect to happen?

I have the following code:

my_database.dart

part 'my_database.g.dart';

LazyDatabase _openConnection() {
  return LazyDatabase(() async {
    final dbFolder = await getApplicationDocumentsDirectory();
    final file = File(join(dbFolder.path, 'dev_db.sqlite'));
    print('SQLite File Path: ${file.path}');
    if (kDebugMode) {
      // Does not run in Profile or Release Mode
      if (file.existsSync()) {
        await file.delete();
      }
    }

    return VmDatabase(file, logStatements: true);
  });
}

@UseMoor(
  tables: [Projects],
  daos: [ProjectsDao],
)
class MyDatabase extends _$MyDatabase {
  MyDatabase() : super(_openConnection());

  @override
  int get schemaVersion => 1;

  @override
  MigrationStrategy get migration {
    return MigrationStrategy(
      beforeOpen: (OpeningDetails details) async {
        await customStatement('PRAGMA foreign_keys = ON');
      },
    );
  }
}

projects.dart

class Projects extends EntityWithUuid {
  TextColumn get name => text()();
  TextColumn get client => text().nullable()();
}

entity_with_uuid.dart

abstract class EntityWithUuid extends Table {
  TextColumn get id =>
      text().clientDefault(() => GetIt.instance.get<Uuid>().v4())();

  @override
  Set<Column> get primaryKey => {id};
}

I expected the primary key of the projects table to be the id column

What actually happens?

When the application starts, the following is logged in the console:

flutter: Moor: Sent CREATE TABLE IF NOT EXISTS projects (is_playground_entity INTEGER NOT NULL DEFAULT 0 CHECK (is_playground_entity in (0, 1)), id VARCHAR NOT NULL, name VARCHAR NOT NULL, client VARCHAR NULL, color INTEGER NOT NULL, total_worktime VARCHAR NULL, total_earned VARCHAR NULL, time_goal VARCHAR NULL, budget_goal VARCHAR NULL, goal_type INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (id)); with args []

I noticed that even though I set Set<Column> get primaryKey => {id};, PRIMARY KEY is not set on the id attribute. I verified this using a SQLite browser as well.

In addition, I also got rid of using the EntityWithUuid abstract class you see above, just to make sure it wasn't my code that was causing the problem.

Eventually, I resorted to doing:

@override
  List<String> get customConstraints => [
        'PRIMARY KEY (id)',
      ];

on the table, which works.

Wanted to make sure there isn't any bugs with Set<Column> get primaryKey => {id};. Perhaps I'm doing something wrong in my code?

bug generator

All 2 comments

Thanks for the report. This is a bug in the generator that will be fixed in the next version.

Until that's released, another workaround (apart from overriding customConstraints) is duplicating the primaryKey getter in the child class:

class Projects extends EntityWithUuid {
  TextColumn get name => text()();
  TextColumn get client => text().nullable()();

  @override
  Set<Column> get primaryKey => {id};
}

Not ideal, but at least you don't have to touch generated code which can be very fragile.

Gotcha, thanks for another workaround example. Appreciate the quick response!

Was this page helpful?
0 / 5 - 0 ratings