Skip to content

Commit

Permalink
Merge branch 'relations' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmartos96 committed Jun 21, 2024
2 parents 1e26a99 + 971d0ad commit 6fc260b
Show file tree
Hide file tree
Showing 21 changed files with 391 additions and 274 deletions.
6 changes: 4 additions & 2 deletions packages/electricsql/lib/drivers/drift.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/// drift Driver
library driver_drift;

export '../src/client/conversions/custom_types.dart';

export '../src/drivers/drift/custom_types.dart';
export '../src/drivers/drift/drift.dart'
show DriftElectricClient, ElectricClient, electrify;
export '../src/drivers/drift/drift_adapter.dart' show DriftAdapter;
export '../src/drivers/drift/relation.dart' show TableRelation, TableRelations;
export '../src/drivers/drift/schema.dart'
show DBSchemaDrift, ElectricTableMixin;
export '../src/drivers/drift/sync_input.dart'
show SyncIncludeBuilder, SyncInputRelation, SyncWhereBuilder;
4 changes: 2 additions & 2 deletions packages/electricsql/lib/src/client/model/index.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export 'package:electricsql/src/client/model/schema.dart'
show ElectricMigrations, ElectricTableMixin;
show ElectricMigrations;

export 'client.dart' show BaseElectricClient, ElectricClientRaw;
export 'relation.dart' show TableRelation, TableRelations;
export 'shapes.dart'
show IShapeManager, SyncManager, SyncStatus, SyncStatusType;
63 changes: 0 additions & 63 deletions packages/electricsql/lib/src/client/model/relation.dart

This file was deleted.

170 changes: 83 additions & 87 deletions packages/electricsql/lib/src/client/model/schema.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import 'package:drift/drift.dart';
import 'package:electricsql/electricsql.dart';
import 'package:electricsql/src/client/conversions/custom_types.dart';
import 'package:electricsql/src/client/conversions/types.dart';
import 'package:electricsql/src/satellite/shapes/types.dart';
import 'package:meta/meta.dart';

typedef FieldName = String;
typedef RelationName = String;

typedef Fields = Map<FieldName, PgType>;

mixin ElectricTableMixin on Table {
TableRelations? get $relations => null;
}

class ElectricMigrations {
final List<Migration> sqliteMigrations;
final List<Migration> pgMigrations;
Expand All @@ -23,8 +18,18 @@ class ElectricMigrations {
});
}

class TableSchema {
final Fields fields;
final List<Relation> relations;

TableSchema({
required this.fields,
required this.relations,
});
}

abstract class DBSchema {
final Map<String, Fields> _fieldsByTable;
final Map<String, TableSchema> _tableSchemas;
final List<Migration> _migrations;
final List<Migration> _pgMigrations;

Expand All @@ -35,113 +40,76 @@ abstract class DBSchema {
/// @param migrations Bundled SQLite migrations
/// @param pgMigrations Bundled Postgres migrations
DBSchema({
required Map<String, Fields> fieldsByTable,
required Map<String, TableSchema> tableSchemas,
required List<Migration> migrations,
required List<Migration> pgMigrations,
}) : _fieldsByTable = fieldsByTable,
}) : _tableSchemas = tableSchemas,
_migrations = migrations,
_pgMigrations = pgMigrations;

bool hasTable(String table) {
return _fieldsByTable.containsKey(table);
return _tableSchemas.containsKey(table);
}

Fields getFields(String table) {
return _fieldsByTable[table]!;
TableSchema getTableSchema(String table) {
return _tableSchemas[table]!;
}
}

class DBSchemaDrift extends DBSchema {
final DatabaseConnectionUser db;

factory DBSchemaDrift({
required DatabaseConnectionUser db,
required List<Migration> migrations,
required List<Migration> pgMigrations,
}) {
// ignore: invalid_use_of_visible_for_overriding_member
final driftDb = db.attachedDatabase;

final _fieldsByTable = {
for (final table in driftDb.allTables)
table.actualTableName: _buildFieldsForTable(table, driftDb),
};

return DBSchemaDrift._(
fieldsByTable: _fieldsByTable,
migrations: migrations,
pgMigrations: pgMigrations,
db: db,
);
Fields getFields(String table) {
return getTableSchema(table).fields;
}

DBSchemaDrift._({
required super.fieldsByTable,
required super.migrations,
required super.pgMigrations,
required this.db,
});
List<Relation> getRelations(String table) {
return getTableSchema(table).relations;
}

static Fields _buildFieldsForTable(
TableInfo<dynamic, dynamic> table,
GeneratedDatabase genDb,
) {
final Map<FieldName, PgType> fields = {};
// RelationName getRelationName(TableName table, FieldName field) {
// return getRelations(table)
// .firstWhere((r) => r.relationField == field)
// .relationName;
// }

for (final column in table.$columns) {
final pgType = _getPgTypeFromGeneratedDriftColumn(genDb, column);
if (pgType != null) {
fields[column.name] = pgType;
}
}
return fields;
Relation getRelation(String table, RelationName relationName) {
return getRelations(table)
.firstWhere((r) => r.relationName == relationName);
}

static PgType? _getPgTypeFromGeneratedDriftColumn(
GeneratedDatabase genDb,
GeneratedColumn<Object> c,
// TableName getRelatedTable(TableName table, FieldName field) {
// final relationName = getRelationName(table, field);
// final relation = getRelation(table, relationName);
// return relation.relatedTable;
// }

// FieldName getForeignKey(TableName table, FieldName field) {
// final relationName = getRelationName(table, field);
// return getForeignKeyFromRelationName(table, relationName);
// }

FieldName getForeignKeyFromRelationName(
TableName table,
RelationName relationName,
) {
//print("Column: ${c.name} ${c.type} ${c.driftSqlType}");
final type = c.type;
switch (type) {
case CustomElectricType():
return type.pgType;
case CustomSqlType<Object>():
return null;
case DriftSqlType.bool:
return PgType.bool;
case DriftSqlType.string:
return PgType.text;
case DriftSqlType.int:
return PgType.integer;
case DriftSqlType.dateTime:
return genDb.typeMapping.storeDateTimesAsText
? PgType.text
: PgType.integer;
case DriftSqlType.double:
return PgType.real;
case DriftSqlType.bigInt:
return PgType.int8;
case DriftSqlType.blob:
return PgType.bytea;
case DriftSqlType.any:
// Unsupported
return null;
default:
return null;
final relation = getRelation(table, relationName);
if (relation.isOutgoingRelation()) {
return relation.fromField;
}
// it's an incoming relation
// we need to fetch the `fromField` from the outgoing relation
final oppositeRelation = relation.getOppositeRelation(this);
return oppositeRelation.fromField;
}
}

@visibleForTesting
class DBSchemaRaw extends DBSchema {
Map<String, Fields> get fields => _fieldsByTable;
Map<String, Fields> get fields =>
_tableSchemas.map((k, v) => MapEntry(k, v.fields));

DBSchemaRaw({
required Map<String, Fields> fields,
required super.tableSchemas,
required super.migrations,
required super.pgMigrations,
}) : super(fieldsByTable: fields);
});
}

@protected
Expand Down Expand Up @@ -233,3 +201,31 @@ List<Map<String, Object?>> _extractWhereConditionsFor(

return conditions;
}

class Relation {
// final String relationField;
final String fromField;
final String toField;
final String relationName;
final String relatedTable;

const Relation({
// required this.relationField,
required this.fromField,
required this.toField,
required this.relationName,
required this.relatedTable,
});

bool isIncomingRelation() {
return fromField == '' && toField == '';
}

bool isOutgoingRelation() {
return !isIncomingRelation();
}

Relation getOppositeRelation(DBSchema dbDescription) {
return dbDescription.getRelation(relatedTable, relationName);
}
}
19 changes: 15 additions & 4 deletions packages/electricsql/lib/src/drivers/drift/drift.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'package:electricsql/drivers/drift.dart';
import 'package:electricsql/electricsql.dart';
import 'package:electricsql/migrators.dart';
import 'package:electricsql/src/client/model/client.dart';
import 'package:electricsql/src/client/model/relation.dart';
import 'package:electricsql/src/client/model/schema.dart';
import 'package:electricsql/src/client/model/transform.dart';
import 'package:electricsql/src/config/config.dart';
Expand Down Expand Up @@ -269,6 +268,7 @@ class DriftElectricClient<DB extends GeneratedDatabase>
}) {
final shape = computeShapeForDrift<T>(
db,
dbDescription,
table,
include: include,
where: where,
Expand All @@ -295,7 +295,7 @@ class DriftElectricClient<DB extends GeneratedDatabase>
// forbid transforming relation keys to avoid breaking
// referential integrity

final tableRelations = getTableRelations(table)?.$relationsList ?? [];
final tableRelations = dbDescription.getRelations(table.actualTableName);

final outgoingRelations =
tableRelations.where((r) => r.isOutgoingRelation());
Expand All @@ -309,8 +309,8 @@ class DriftElectricClient<DB extends GeneratedDatabase>
// Incoming relations don't have the `fromField` and `toField` filled in
// so we need to fetch the `toField` from the opposite relation
// which is effectively a column in this table to which the FK points
final pkCols =
incomingRelations.map((r) => r.getOppositeRelation(db).toField);
final pkCols = incomingRelations
.map((r) => r.getOppositeRelation(dbDescription).toField);

// Merge all columns that are part of a FK relation.
// Remove duplicate columns in case a column has both an outgoing FK and an incoming FK.
Expand Down Expand Up @@ -404,3 +404,14 @@ Object? _expressionToValue(Expression<Object?> expression) {
throw ArgumentError('Unsupported expression type: $expression');
}
}

TableInfo<T, dynamic>
findDriftTableInfo<DB extends GeneratedDatabase, T extends Table>(
DB db,
T table,
) {
final TableInfo<Table, dynamic> genTable = db.allTables.firstWhere((t) {
return t.asDslTable == table;
});
return genTable as TableInfo<T, dynamic>;
}
Loading

0 comments on commit 6fc260b

Please sign in to comment.