Skip to content

Commit

Permalink
Enable manager references with modular codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
simolus3 committed Jan 4, 2025
1 parent cda9f27 commit 4b285d7
Show file tree
Hide file tree
Showing 4 changed files with 338 additions and 50 deletions.
90 changes: 56 additions & 34 deletions drift_dev/lib/src/writer/manager/manager_templates.dart
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,9 @@ class _ManagerCodeTemplates {
db: db,
explicitlyWatchedTables: [
${reverseRelations.map((relation) {
return "if (${relation.fieldName}) db.${relation.referencedTable.dbGetterName}";
final table =
leaf.referenceElement(relation.referencedTable, 'db');
return "if (${relation.fieldName}) ${leaf.dartCode(table)}";
}).join(',')}
],
addJoins: ${forwardRelations.isEmpty ? 'null' : """
Expand Down Expand Up @@ -436,7 +438,7 @@ class _ManagerCodeTemplates {

return """${leaf.drift("ColumnFilters")}<$type> get $filterName => \$composableBuilder(
column: \$table.$columnGetter,
builder: (column) =>
builder: (column) =>
${leaf.drift("ColumnFilters")}(column));
""";
}
Expand All @@ -453,7 +455,7 @@ class _ManagerCodeTemplates {
return """
${leaf.drift("ColumnWithTypeConverterFilters")}<$converterType,$nonNullableConverterType,$type> get $filterName => \$composableBuilder(
column: \$table.$columnGetter,
builder: (column) =>
builder: (column) =>
${leaf.drift("ColumnWithTypeConverterFilters")}(column));
""";
}
Expand Down Expand Up @@ -489,7 +491,7 @@ class _ManagerCodeTemplates {

return """${leaf.drift("ColumnOrderings")}<$type> get $filterName => \$composableBuilder(
column: \$table.$columnGetter,
builder: (column) =>
builder: (column) =>
${leaf.drift("ColumnOrderings")}(column));
""";
}
Expand Down Expand Up @@ -517,7 +519,7 @@ class _ManagerCodeTemplates {
getCurrentColumn: (t) => t.${relation.currentColumn.nameInDart},
referencedTable: ${_referenceTableFromComposer(relation.referencedTable, leaf)},
getReferencedColumn: (t) => t.${relation.referencedColumn.nameInDart},
builder: (joinBuilder,{\$addJoinBuilderToRootComposer,\$removeJoinBuilderFromRootComposer }) =>
builder: (joinBuilder,{\$addJoinBuilderToRootComposer,\$removeJoinBuilderFromRootComposer }) =>
$composerName(
\$db: \$db,
\$table: ${_referenceTableFromComposer(relation.referencedTable, leaf)},
Expand All @@ -534,8 +536,12 @@ class _ManagerCodeTemplates {
/// as the table manager and is not used outside of the file
///
/// E.g. `$UserTableProcessedTableManager`
String processedTableManagerTypedefName(DriftTable table) {
return '\$${table.entityInfoName}ProcessedTableManager';
String processedTableManagerTypedefName(DriftTable table, TextEmitter leaf,
{bool forDefinition = false}) {
final name = '\$${table.entityInfoName}ProcessedTableManager';
return forDefinition
? name
: leaf.dartCode(leaf.generatedElement(table, name));
}

/// Code for a processed table manager typedef
Expand All @@ -545,20 +551,28 @@ class _ManagerCodeTemplates {
required TextEmitter leaf,
required List<_Relation> relations,
}) {
return """typedef ${processedTableManagerTypedefName(table)} = ${leaf.drift("ProcessedTableManager")}${_tableManagerTypeArguments(table, dbClassName, leaf, relations)};""";
return """typedef ${processedTableManagerTypedefName(table, leaf, forDefinition: true)} = ${leaf.drift("ProcessedTableManager")}${_tableManagerTypeArguments(table, dbClassName, leaf, relations)};""";
}

/// Name of the class which is used to represent a rows references
///
/// If there are no relations, or if generation is modular, we will generate a base class instead.
String rowReferencesClassName(
{required DriftTable table,
required List<_Relation> relations,
required String dbClassName,
required TextEmitter leaf,
required bool withTypeArgs}) {
if (!_scope.generationOptions.isModular && relations.isNotEmpty) {
return '\$${table.entityInfoName}References';
String rowReferencesClassName({
required DriftTable table,
required List<_Relation> relations,
required String dbClassName,
required TextEmitter leaf,
required bool withTypeArgs,
bool forDefinition = false,
}) {
if (relations.isNotEmpty) {
final basename = '\$${table.entityInfoName}References';

if (forDefinition) {
return basename;
} else {
return leaf.dartCode(leaf.generatedElement(table, basename));
}
} else {
if (withTypeArgs) {
return "${leaf.drift('BaseReferences')}<${databaseType(leaf, dbClassName)},${tableClassWithPrefix(table, leaf)},${rowClassWithPrefix(table, leaf)}>";
Expand Down Expand Up @@ -590,11 +604,16 @@ class _ManagerCodeTemplates {
relations: relations,
dbClassName: dbClassName,
leaf: leaf,
withTypeArgs: false);
withTypeArgs: false,
forDefinition: true);

final body = relations.map(
(relation) {
final dbName = databaseType(leaf, dbClassName);
final referencedTable = leaf
.dartCode(leaf.referenceElement(relation.referencedTable, 'db'));
final currentTable =
leaf.dartCode(leaf.referenceElement(relation.currentTable, 'db'));

if (relation.isReverse) {
final aliasedTableMethod = """
Expand All @@ -603,51 +622,54 @@ class _ManagerCodeTemplates {
List<${rowClassWithPrefix(relation.referencedTable, leaf)}>
> _${relation.fieldName}Table($dbName db) =>
${leaf.drift("MultiTypedResultKey")}.fromTable(
db.${relation.referencedTable.dbGetterName},
$referencedTable,
aliasName: ${leaf.drift("\$_aliasNameGenerator")}(
db.${relation.currentTable.dbGetterName}.${relation.currentColumn.nameInDart},
db.${relation.referencedTable.dbGetterName}.${relation.referencedColumn.nameInDart})
$currentTable.${relation.currentColumn.nameInDart},
$referencedTable.${relation.referencedColumn.nameInDart})
);""";

return """
$aliasedTableMethod
${processedTableManagerTypedefName(relation.referencedTable)} get ${relation.fieldName} {
${processedTableManagerTypedefName(relation.referencedTable, leaf)} get ${relation.fieldName} {
final manager = ${rootTableManagerWithPrefix(relation.referencedTable, leaf)}(
\$_db, \$_db.${relation.referencedTable.dbGetterName}
\$_db, ${leaf.dartCode(leaf.referenceElement(relation.referencedTable, r'$_db'))}
).filter(
(f) => f.${relation.referencedColumn.nameInDart}.${relation.currentColumn.nameInDart}(
\$_item.${relation.currentColumn.nameInDart}
)
);
final cache = \$_typedResult.readTableOrNull(_${relation.fieldName}Table(\$_db));
return ProcessedTableManager(manager.\$state.copyWith(prefetchedData: cache));
return ${leaf.drift("ProcessedTableManager")}(manager.\$state.copyWith(prefetchedData: cache));
}
""";
} else {
final referenceTableType =
tableClassWithPrefix(relation.referencedTable, leaf);

final aliasedTableMethod = """
static $referenceTableType _${relation.fieldName}Table($dbName db) =>
db.${relation.referencedTable.dbGetterName}.createAlias(${leaf.drift("\$_aliasNameGenerator")}(
db.${relation.currentTable.dbGetterName}.${relation.currentColumn.nameInDart},
db.${relation.referencedTable.dbGetterName}.${relation.referencedColumn.nameInDart}));
static $referenceTableType _${relation.fieldName}Table($dbName db) =>
$referencedTable.createAlias(${leaf.drift("\$_aliasNameGenerator")}(
$currentTable.${relation.currentColumn.nameInDart},
$referencedTable.${relation.referencedColumn.nameInDart}));
""";

var currentColumnOnItem =
'\$_item.${relation.currentColumn.nameInDart}';
if (relation.currentColumn.nullableInDart) {
currentColumnOnItem += '!';
}

return """
$aliasedTableMethod
${processedTableManagerTypedefName(relation.referencedTable)}${relation.currentColumn.nullable ? "?" : ""} get ${relation.fieldName} {
${processedTableManagerTypedefName(relation.referencedTable, leaf)}${relation.currentColumn.nullable ? "?" : ""} get ${relation.fieldName} {
${relation.currentColumn.nullable ? "if (\$_item.${relation.currentColumn.nameInDart} == null) return null;" : ""}
final manager = ${rootTableManagerWithPrefix(relation.referencedTable, leaf)}(\$_db, \$_db.${relation.referencedTable.dbGetterName}).filter((f) => f.${relation.referencedColumn.nameInDart}(\$_item.${relation.currentColumn.nameInDart}!));
final manager = ${rootTableManagerWithPrefix(relation.referencedTable, leaf)}(\$_db, ${leaf.dartCode(leaf.referenceElement(relation.referencedTable, r'$_db'))}).filter((f) => f.${relation.referencedColumn.nameInDart}($currentColumnOnItem));
final item = \$_typedResult.readTableOrNull(_${relation.fieldName}Table(\$_db));
if (item == null) return manager;
return ProcessedTableManager(manager.\$state.copyWith(prefetchedData: [item]));
return ${leaf.drift("ProcessedTableManager")}(manager.\$state.copyWith(prefetchedData: [item]));
}
""";
}
Expand All @@ -660,7 +682,7 @@ class _ManagerCodeTemplates {
${tableClassWithPrefix(table, leaf)},
${rowClassWithPrefix(table, leaf)}> {
$rowClassWithReferencesName(super.\$_db, super.\$_table, super.\$_typedResult);
$body
}""";
Expand Down
4 changes: 2 additions & 2 deletions drift_dev/lib/src/writer/manager/table_manager_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class _TableManagerWriter {
final fieldNameCount = allFieldNames
.where((fieldName) => fieldName == relation.fieldName)
.length;
if (fieldNameCount != 1) {
if (fieldNameCount != 1 && table.id.isDefinedInDart) {
print(
"Duplicate orderings/filters detected for field \"${relation.fieldName}\" on table \"${table.entityInfoName}\"."
" Filter and orderings for this field wont be generated."
Expand Down Expand Up @@ -170,7 +170,7 @@ class _TableManagerWriter {
.add(_templates.relatedAnnotations(leaf: leaf, relation: relation));
}

if (!scope.generationOptions.isModular && relations.isNotEmpty) {
if (relations.isNotEmpty) {
leaf.write(_templates.rowReferencesClass(
table: table,
relations: relations,
Expand Down
94 changes: 88 additions & 6 deletions examples/modular/lib/src/posts.drift.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,47 @@ typedef $PostsUpdateCompanionBuilder = i1.PostsCompanion Function({
i0.Value<String?> content,
});

final class $PostsReferences
extends i0.BaseReferences<i0.GeneratedDatabase, i1.Posts, i1.Post> {
$PostsReferences(super.$_db, super.$_table, super.$_typedResult);

static i2.Users _authorTable(i0.GeneratedDatabase db) =>
i3.ReadDatabaseContainer(db).resultSet<i2.Users>('users').createAlias(
i0.$_aliasNameGenerator(
i3.ReadDatabaseContainer(db).resultSet<i1.Posts>('posts').author,
i3.ReadDatabaseContainer(db).resultSet<i2.Users>('users').id));

i2.$UsersProcessedTableManager get author {
final manager = i2
.$UsersTableManager(
$_db, i3.ReadDatabaseContainer($_db).resultSet<i2.Users>('users'))
.filter((f) => f.id($_item.author));
final item = $_typedResult.readTableOrNull(_authorTable($_db));
if (item == null) return manager;
return i0.ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}

static i0.MultiTypedResultKey<i1.Likes, List<i1.Like>> _likesRefsTable(
i0.GeneratedDatabase db) =>
i0.MultiTypedResultKey.fromTable(
i3.ReadDatabaseContainer(db).resultSet<i1.Likes>('likes'),
aliasName: i0.$_aliasNameGenerator(
i3.ReadDatabaseContainer(db).resultSet<i1.Posts>('posts').id,
i3.ReadDatabaseContainer(db).resultSet<i1.Likes>('likes').post));

i1.$LikesProcessedTableManager get likesRefs {
final manager = i1
.$LikesTableManager(
$_db, i3.ReadDatabaseContainer($_db).resultSet<i1.Likes>('likes'))
.filter((f) => f.post.id($_item.id));

final cache = $_typedResult.readTableOrNull(_likesRefsTable($_db));
return i0.ProcessedTableManager(
manager.$state.copyWith(prefetchedData: cache));
}
}

class $PostsFilterComposer extends i0.Composer<i0.GeneratedDatabase, i1.Posts> {
$PostsFilterComposer({
required super.$db,
Expand Down Expand Up @@ -184,7 +225,7 @@ class $PostsTableManager extends i0.RootTableManager<
i1.$PostsAnnotationComposer,
$PostsCreateCompanionBuilder,
$PostsUpdateCompanionBuilder,
(i1.Post, i0.BaseReferences<i0.GeneratedDatabase, i1.Posts, i1.Post>),
(i1.Post, i1.$PostsReferences),
i1.Post,
i0.PrefetchHooks Function({bool author, bool likesRefs})> {
$PostsTableManager(i0.GeneratedDatabase db, i1.Posts table)
Expand Down Expand Up @@ -218,7 +259,8 @@ class $PostsTableManager extends i0.RootTableManager<
content: content,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
.map((e) =>
(e.readTable(table), i1.$PostsReferences(db, table, e)))
.toList(),
prefetchHooksCallback: null,
));
Expand All @@ -233,7 +275,7 @@ typedef $PostsProcessedTableManager = i0.ProcessedTableManager<
i1.$PostsAnnotationComposer,
$PostsCreateCompanionBuilder,
$PostsUpdateCompanionBuilder,
(i1.Post, i0.BaseReferences<i0.GeneratedDatabase, i1.Posts, i1.Post>),
(i1.Post, i1.$PostsReferences),
i1.Post,
i0.PrefetchHooks Function({bool author, bool likesRefs})>;
typedef $LikesCreateCompanionBuilder = i1.LikesCompanion Function({
Expand All @@ -247,6 +289,45 @@ typedef $LikesUpdateCompanionBuilder = i1.LikesCompanion Function({
i0.Value<int> rowid,
});

final class $LikesReferences
extends i0.BaseReferences<i0.GeneratedDatabase, i1.Likes, i1.Like> {
$LikesReferences(super.$_db, super.$_table, super.$_typedResult);

static i1.Posts _postTable(i0.GeneratedDatabase db) =>
i3.ReadDatabaseContainer(db).resultSet<i1.Posts>('posts').createAlias(
i0.$_aliasNameGenerator(
i3.ReadDatabaseContainer(db).resultSet<i1.Likes>('likes').post,
i3.ReadDatabaseContainer(db).resultSet<i1.Posts>('posts').id));

i1.$PostsProcessedTableManager get post {
final manager = i1
.$PostsTableManager(
$_db, i3.ReadDatabaseContainer($_db).resultSet<i1.Posts>('posts'))
.filter((f) => f.id($_item.post));
final item = $_typedResult.readTableOrNull(_postTable($_db));
if (item == null) return manager;
return i0.ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}

static i2.Users _likedByTable(i0.GeneratedDatabase db) =>
i3.ReadDatabaseContainer(db).resultSet<i2.Users>('users').createAlias(
i0.$_aliasNameGenerator(
i3.ReadDatabaseContainer(db).resultSet<i1.Likes>('likes').likedBy,
i3.ReadDatabaseContainer(db).resultSet<i2.Users>('users').id));

i2.$UsersProcessedTableManager get likedBy {
final manager = i2
.$UsersTableManager(
$_db, i3.ReadDatabaseContainer($_db).resultSet<i2.Users>('users'))
.filter((f) => f.id($_item.likedBy));
final item = $_typedResult.readTableOrNull(_likedByTable($_db));
if (item == null) return manager;
return i0.ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}
}

class $LikesFilterComposer extends i0.Composer<i0.GeneratedDatabase, i1.Likes> {
$LikesFilterComposer({
required super.$db,
Expand Down Expand Up @@ -417,7 +498,7 @@ class $LikesTableManager extends i0.RootTableManager<
i1.$LikesAnnotationComposer,
$LikesCreateCompanionBuilder,
$LikesUpdateCompanionBuilder,
(i1.Like, i0.BaseReferences<i0.GeneratedDatabase, i1.Likes, i1.Like>),
(i1.Like, i1.$LikesReferences),
i1.Like,
i0.PrefetchHooks Function({bool post, bool likedBy})> {
$LikesTableManager(i0.GeneratedDatabase db, i1.Likes table)
Expand Down Expand Up @@ -451,7 +532,8 @@ class $LikesTableManager extends i0.RootTableManager<
rowid: rowid,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
.map((e) =>
(e.readTable(table), i1.$LikesReferences(db, table, e)))
.toList(),
prefetchHooksCallback: null,
));
Expand All @@ -466,7 +548,7 @@ typedef $LikesProcessedTableManager = i0.ProcessedTableManager<
i1.$LikesAnnotationComposer,
$LikesCreateCompanionBuilder,
$LikesUpdateCompanionBuilder,
(i1.Like, i0.BaseReferences<i0.GeneratedDatabase, i1.Likes, i1.Like>),
(i1.Like, i1.$LikesReferences),
i1.Like,
i0.PrefetchHooks Function({bool post, bool likedBy})>;

Expand Down
Loading

0 comments on commit 4b285d7

Please sign in to comment.