diff --git a/packages/brick_offline_first_with_supabase_build/analysis_options.yaml b/packages/brick_offline_first_with_supabase_build/analysis_options.yaml index 29aff7e8..f04c6cf0 100644 --- a/packages/brick_offline_first_with_supabase_build/analysis_options.yaml +++ b/packages/brick_offline_first_with_supabase_build/analysis_options.yaml @@ -1,5 +1 @@ include: ../../analysis_options.yaml - -linter: - rules: - library_prefixes: false diff --git a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_default_to_null.dart b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_default_to_null.dart new file mode 100644 index 00000000..4a95b678 --- /dev/null +++ b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_default_to_null.dart @@ -0,0 +1,112 @@ +import 'package:brick_offline_first/brick_offline_first.dart'; +import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart'; +import 'package:brick_supabase/brick_supabase.dart'; + +final output = r''' +// GENERATED CODE DO NOT EDIT +part of '../brick.g.dart'; + +Future _$SupabaseDefinedFromSupabase(Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefined(someLongField: data['some_long_field'] as int); +} + +Future> _$SupabaseDefinedToSupabase( + SupabaseDefined instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseDefinedFromSqlite(Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefined(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseDefinedToSqlite(SupabaseDefined instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +/// Construct a [SupabaseDefined] +class SupabaseDefinedAdapter extends OfflineFirstAdapter { + SupabaseDefinedAdapter(); + + @override + final tableName = 'supabase_defineds'; + @override + final defaultToNull = false; + @override + final Map fieldsToSqliteColumns = { + 'someLongField': const RuntimeSupabaseColumnDefinition( + association: false, + associationForeignKey: 'null', + associationType: int, + columnName: 'some_long_field', + ) + }; + @override + final ignoreDuplicates = false; + @override + final uniqueFields = {}; + @override + final Map fieldsToSqliteColumns = { + 'primaryKey': const RuntimeSqliteColumnDefinition( + association: false, + columnName: '_brick_id', + iterable: false, + type: int, + ), + 'someLongField': const RuntimeSqliteColumnDefinition( + association: false, + columnName: 'some_long_field', + iterable: false, + type: int, + ) + }; + @override + Future primaryKeyByUniqueColumns( + SupabaseDefined instance, DatabaseExecutor executor) async => + instance.primaryKey; + @override + final String tableName = 'SupabaseDefined'; + + @override + Future fromSupabase(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedFromSupabase(input, + provider: provider, repository: repository); + @override + Future> toSupabase(SupabaseDefined input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedToSupabase(input, + provider: provider, repository: repository); + @override + Future fromSqlite(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedFromSqlite(input, + provider: provider, repository: repository); + @override + Future> toSqlite(SupabaseDefined input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedToSqlite(input, + provider: provider, repository: repository); +} +'''; + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(defaultToNull: false), +) +class SupabaseDefined extends OfflineFirstModel { + final int someLongField; + + SupabaseDefined(this.someLongField); +} diff --git a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_specify_field_name.dart b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_field_name.dart similarity index 88% rename from packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_specify_field_name.dart rename to packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_field_name.dart index def2f5a9..61d91e53 100644 --- a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_specify_field_name.dart +++ b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_field_name.dart @@ -7,14 +7,14 @@ Future _$SpecifyFieldNameFromSupabase( Map data, {required SupabaseProvider provider, OfflineFirstRepository? repository}) async { - return SpecifyFieldName(email: data['email_address'] as String?); + return SpecifyFieldName(email: data['supa_email_address'] as String?); } Future> _$SpecifyFieldNameToSupabase( SpecifyFieldName instance, {required SupabaseProvider provider, OfflineFirstRepository? repository}) async { - return {'email_address': instance.email}; + return {'supa_email_address': instance.email}; } Future _$SpecifyFieldNameFromSqlite(Map data, @@ -38,7 +38,7 @@ Future> _$SpecifyFieldNameToSqlite( @ConnectOfflineFirstWithSupabase() class SpecifyFieldName { @Sqlite(name: 'email_address') - @Supabase(name: 'email_address') + @Supabase(name: 'supa_email_address') final String? email; SpecifyFieldName({this.email}); diff --git a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_field_rename.dart b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_field_rename.dart new file mode 100644 index 00000000..a8b23e3a --- /dev/null +++ b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_field_rename.dart @@ -0,0 +1,231 @@ +import 'package:brick_offline_first/brick_offline_first.dart'; +import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart'; +import 'package:brick_supabase/brick_supabase.dart'; + +final output = r''' +Future _$SupabaseDefaultFromSupabase(Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefault(someLongField: data['some_long_field'] as int); +} + +Future> _$SupabaseDefaultToSupabase( + SupabaseDefault instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseDefaultFromSqlite(Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefault(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseDefaultToSqlite(SupabaseDefault instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseNoRenameFromSupabase( + Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseNoRename(someLongField: data['someLongField'] as int); +} + +Future> _$SupabaseNoRenameToSupabase( + SupabaseNoRename instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'someLongField': instance.someLongField}; +} + +Future _$SupabaseNoRenameFromSqlite(Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseNoRename(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseNoRenameToSqlite( + SupabaseNoRename instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseSnakeRenameFromSupabase( + Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseSnakeRename(someLongField: data['some_long_field'] as int); +} + +Future> _$SupabaseSnakeRenameToSupabase( + SupabaseSnakeRename instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseSnakeRenameFromSqlite( + Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseSnakeRename(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseSnakeRenameToSqlite( + SupabaseSnakeRename instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseKebabRenameFromSupabase( + Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseKebabRename(someLongField: data['some-long-field'] as int); +} + +Future> _$SupabaseKebabRenameToSupabase( + SupabaseKebabRename instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some-long-field': instance.someLongField}; +} + +Future _$SupabaseKebabRenameFromSqlite( + Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseKebabRename(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseKebabRenameToSqlite( + SupabaseKebabRename instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabasePascalRenameFromSupabase( + Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabasePascalRename(someLongField: data['SomeLongField'] as int); +} + +Future> _$SupabasePascalRenameToSupabase( + SupabasePascalRename instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'SomeLongField': instance.someLongField}; +} + +Future _$SupabasePascalRenameFromSqlite( + Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabasePascalRename(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabasePascalRenameToSqlite( + SupabasePascalRename instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseRenameWithOverrideFromSupabase( + Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseRenameWithOverride(someLongField: data['some_field'] as int); +} + +Future> _$SupabaseRenameWithOverrideToSupabase( + SupabaseRenameWithOverride instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_field': instance.someLongField}; +} + +Future _$SupabaseRenameWithOverrideFromSqlite( + Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseRenameWithOverride( + someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseRenameWithOverrideToSqlite( + SupabaseRenameWithOverride instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} +'''; + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(), +) +class SupabaseDefault extends OfflineFirstModel { + final int someLongField; + + SupabaseDefault(this.someLongField); +} + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(fieldRename: FieldRename.none), +) +class SupabaseNoRename extends OfflineFirstModel { + final int someLongField; + + SupabaseNoRename(this.someLongField); +} + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(fieldRename: FieldRename.snake), +) +class SupabaseSnakeRename extends OfflineFirstModel { + final int someLongField; + + SupabaseSnakeRename(this.someLongField); +} + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(fieldRename: FieldRename.kebab), +) +class SupabaseKebabRename extends OfflineFirstModel { + final int someLongField; + + SupabaseKebabRename(this.someLongField); +} + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(fieldRename: FieldRename.pascal), +) +class SupabasePascalRename extends OfflineFirstModel { + final int someLongField; + + SupabasePascalRename(this.someLongField); +} + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(fieldRename: FieldRename.pascal), +) +class SupabaseRenameWithOverride extends OfflineFirstModel { + @Supabase(name: 'some_field') + final int someLongField; + + SupabaseRenameWithOverride(this.someLongField); +} diff --git a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_ignore_duplicates.dart b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_ignore_duplicates.dart new file mode 100644 index 00000000..544a9614 --- /dev/null +++ b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_ignore_duplicates.dart @@ -0,0 +1,112 @@ +import 'package:brick_offline_first/brick_offline_first.dart'; +import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart'; +import 'package:brick_supabase/brick_supabase.dart'; + +final output = r''' +// GENERATED CODE DO NOT EDIT +part of '../brick.g.dart'; + +Future _$SupabaseDefinedFromSupabase(Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefined(someLongField: data['some_long_field'] as int); +} + +Future> _$SupabaseDefinedToSupabase( + SupabaseDefined instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseDefinedFromSqlite(Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefined(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseDefinedToSqlite(SupabaseDefined instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +/// Construct a [SupabaseDefined] +class SupabaseDefinedAdapter extends OfflineFirstAdapter { + SupabaseDefinedAdapter(); + + @override + final tableName = 'supabase_defineds'; + @override + final defaultToNull = true; + @override + final Map fieldsToSqliteColumns = { + 'someLongField': const RuntimeSupabaseColumnDefinition( + association: false, + associationForeignKey: 'null', + associationType: int, + columnName: 'some_long_field', + ) + }; + @override + final ignoreDuplicates = true; + @override + final uniqueFields = {}; + @override + final Map fieldsToSqliteColumns = { + 'primaryKey': const RuntimeSqliteColumnDefinition( + association: false, + columnName: '_brick_id', + iterable: false, + type: int, + ), + 'someLongField': const RuntimeSqliteColumnDefinition( + association: false, + columnName: 'some_long_field', + iterable: false, + type: int, + ) + }; + @override + Future primaryKeyByUniqueColumns( + SupabaseDefined instance, DatabaseExecutor executor) async => + instance.primaryKey; + @override + final String tableName = 'SupabaseDefined'; + + @override + Future fromSupabase(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedFromSupabase(input, + provider: provider, repository: repository); + @override + Future> toSupabase(SupabaseDefined input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedToSupabase(input, + provider: provider, repository: repository); + @override + Future fromSqlite(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedFromSqlite(input, + provider: provider, repository: repository); + @override + Future> toSqlite(SupabaseDefined input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedToSqlite(input, + provider: provider, repository: repository); +} +'''; + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(ignoreDuplicates: true), +) +class SupabaseDefined extends OfflineFirstModel { + final int someLongField; + + SupabaseDefined(this.someLongField); +} diff --git a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_on_conflict.dart b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_on_conflict.dart new file mode 100644 index 00000000..7b1260cd --- /dev/null +++ b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_on_conflict.dart @@ -0,0 +1,114 @@ +import 'package:brick_offline_first/brick_offline_first.dart'; +import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart'; +import 'package:brick_supabase/brick_supabase.dart'; + +final output = r''' +// GENERATED CODE DO NOT EDIT +part of '../brick.g.dart'; + +Future _$SupabaseDefinedFromSupabase(Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefined(someLongField: data['some_long_field'] as int); +} + +Future> _$SupabaseDefinedToSupabase( + SupabaseDefined instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseDefinedFromSqlite(Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefined(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseDefinedToSqlite(SupabaseDefined instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +/// Construct a [SupabaseDefined] +class SupabaseDefinedAdapter extends OfflineFirstAdapter { + SupabaseDefinedAdapter(); + + @override + final tableName = 'supabase_defineds'; + @override + final defaultToNull = true; + @override + final Map fieldsToSqliteColumns = { + 'someLongField': const RuntimeSupabaseColumnDefinition( + association: false, + associationForeignKey: 'null', + associationType: int, + columnName: 'some_long_field', + ) + }; + @override + final ignoreDuplicates = false; + @override + final onConflict = user_id, other_id; + @override + final uniqueFields = {}; + @override + final Map fieldsToSqliteColumns = { + 'primaryKey': const RuntimeSqliteColumnDefinition( + association: false, + columnName: '_brick_id', + iterable: false, + type: int, + ), + 'someLongField': const RuntimeSqliteColumnDefinition( + association: false, + columnName: 'some_long_field', + iterable: false, + type: int, + ) + }; + @override + Future primaryKeyByUniqueColumns( + SupabaseDefined instance, DatabaseExecutor executor) async => + instance.primaryKey; + @override + final String tableName = 'SupabaseDefined'; + + @override + Future fromSupabase(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedFromSupabase(input, + provider: provider, repository: repository); + @override + Future> toSupabase(SupabaseDefined input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedToSupabase(input, + provider: provider, repository: repository); + @override + Future fromSqlite(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedFromSqlite(input, + provider: provider, repository: repository); + @override + Future> toSqlite(SupabaseDefined input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedToSqlite(input, + provider: provider, repository: repository); +} +'''; + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(onConflict: 'user_id,other_id'), +) +class SupabaseDefined extends OfflineFirstModel { + final int someLongField; + + SupabaseDefined(this.someLongField); +} diff --git a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_table_name_defined.dart b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_table_name_defined.dart new file mode 100644 index 00000000..64e1a9cb --- /dev/null +++ b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_table_name_defined.dart @@ -0,0 +1,112 @@ +import 'package:brick_offline_first/brick_offline_first.dart'; +import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart'; +import 'package:brick_supabase/brick_supabase.dart'; + +final output = r''' +// GENERATED CODE DO NOT EDIT +part of '../brick.g.dart'; + +Future _$SupabaseDefinedFromSupabase(Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefined(someLongField: data['some_long_field'] as int); +} + +Future> _$SupabaseDefinedToSupabase( + SupabaseDefined instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$SupabaseDefinedFromSqlite(Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return SupabaseDefined(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$SupabaseDefinedToSqlite(SupabaseDefined instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +/// Construct a [SupabaseDefined] +class SupabaseDefinedAdapter extends OfflineFirstAdapter { + SupabaseDefinedAdapter(); + + @override + final tableName = 'strictly_defined_items'; + @override + final defaultToNull = true; + @override + final Map fieldsToSqliteColumns = { + 'someLongField': const RuntimeSupabaseColumnDefinition( + association: false, + associationForeignKey: 'null', + associationType: int, + columnName: 'some_long_field', + ) + }; + @override + final ignoreDuplicates = false; + @override + final uniqueFields = {}; + @override + final Map fieldsToSqliteColumns = { + 'primaryKey': const RuntimeSqliteColumnDefinition( + association: false, + columnName: '_brick_id', + iterable: false, + type: int, + ), + 'someLongField': const RuntimeSqliteColumnDefinition( + association: false, + columnName: 'some_long_field', + iterable: false, + type: int, + ) + }; + @override + Future primaryKeyByUniqueColumns( + SupabaseDefined instance, DatabaseExecutor executor) async => + instance.primaryKey; + @override + final String tableName = 'SupabaseDefined'; + + @override + Future fromSupabase(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedFromSupabase(input, + provider: provider, repository: repository); + @override + Future> toSupabase(SupabaseDefined input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedToSupabase(input, + provider: provider, repository: repository); + @override + Future fromSqlite(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedFromSqlite(input, + provider: provider, repository: repository); + @override + Future> toSqlite(SupabaseDefined input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$SupabaseDefinedToSqlite(input, + provider: provider, repository: repository); +} +'''; + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(tableName: 'strictly_defined_items'), +) +class SupabaseDefined extends OfflineFirstModel { + final int someLongField; + + SupabaseDefined(this.someLongField); +} diff --git a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_table_name_undefined.dart b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_table_name_undefined.dart new file mode 100644 index 00000000..f45bf94e --- /dev/null +++ b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator/test_table_name_undefined.dart @@ -0,0 +1,116 @@ +import 'package:brick_offline_first/brick_offline_first.dart'; +import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart'; +import 'package:brick_supabase/brick_supabase.dart'; + +final output = r''' +// GENERATED CODE DO NOT EDIT +part of '../brick.g.dart'; + +Future _$UndefinedCamelizedNameFromSupabase( + Map data, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return UndefinedCamelizedName(someLongField: data['some_long_field'] as int); +} + +Future> _$UndefinedCamelizedNameToSupabase( + UndefinedCamelizedName instance, + {required SupabaseProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +Future _$UndefinedCamelizedNameFromSqlite( + Map data, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return UndefinedCamelizedName(someLongField: data['some_long_field'] as int) + ..primaryKey = data['_brick_id'] as int; +} + +Future> _$UndefinedCamelizedNameToSqlite( + UndefinedCamelizedName instance, + {required SqliteProvider provider, + OfflineFirstRepository? repository}) async { + return {'some_long_field': instance.someLongField}; +} + +/// Construct a [UndefinedCamelizedName] +class UndefinedCamelizedNameAdapter + extends OfflineFirstAdapter { + UndefinedCamelizedNameAdapter(); + + @override + final tableName = 'undefined_camelized_names'; + @override + final defaultToNull = true; + @override + final Map fieldsToSqliteColumns = { + 'someLongField': const RuntimeSupabaseColumnDefinition( + association: false, + associationForeignKey: 'null', + associationType: int, + columnName: 'some_long_field', + ) + }; + @override + final ignoreDuplicates = false; + @override + final uniqueFields = {}; + @override + final Map fieldsToSqliteColumns = { + 'primaryKey': const RuntimeSqliteColumnDefinition( + association: false, + columnName: '_brick_id', + iterable: false, + type: int, + ), + 'someLongField': const RuntimeSqliteColumnDefinition( + association: false, + columnName: 'some_long_field', + iterable: false, + type: int, + ) + }; + @override + Future primaryKeyByUniqueColumns( + UndefinedCamelizedName instance, DatabaseExecutor executor) async => + instance.primaryKey; + @override + final String tableName = 'UndefinedCamelizedName'; + + @override + Future fromSupabase(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$UndefinedCamelizedNameFromSupabase(input, + provider: provider, repository: repository); + @override + Future> toSupabase(UndefinedCamelizedName input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$UndefinedCamelizedNameToSupabase(input, + provider: provider, repository: repository); + @override + Future fromSqlite(Map input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$UndefinedCamelizedNameFromSqlite(input, + provider: provider, repository: repository); + @override + Future> toSqlite(UndefinedCamelizedName input, + {required provider, + covariant OfflineFirstRepository? repository}) async => + await _$UndefinedCamelizedNameToSqlite(input, + provider: provider, repository: repository); +} +'''; + +@ConnectOfflineFirstWithSupabase( + supabaseConfig: SupabaseSerializable(), +) +class UndefinedCamelizedName extends OfflineFirstModel { + final int someLongField; + + UndefinedCamelizedName(this.someLongField); +} diff --git a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator_test.dart b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator_test.dart index abce7222..80a5df73 100644 --- a/packages/brick_offline_first_with_supabase_build/test/offline_first_generator_test.dart +++ b/packages/brick_offline_first_with_supabase_build/test/offline_first_generator_test.dart @@ -3,7 +3,13 @@ import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supab import 'package:brick_offline_first_with_supabase_build/src/offline_first_with_supabase_generator.dart'; import 'package:test/test.dart'; -import 'offline_first_generator/test_specify_field_name.dart' as specifyFieldName; +import 'offline_first_generator/test_default_to_null.dart' as default_to_null; +import 'offline_first_generator/test_field_name.dart' as specify_field_name; +import 'offline_first_generator/test_field_rename.dart' as field_rename; +import 'offline_first_generator/test_ignore_duplicates.dart' as ignore_duplicates; +import 'offline_first_generator/test_on_conflict.dart' as on_conflict; +import 'offline_first_generator/test_table_name_defined.dart' as table_name_defined; +import 'offline_first_generator/test_table_name_undefined.dart' as table_name_undefined; final _generator = OfflineFirstWithSupabaseGenerator(); final folder = 'offline_first_generator'; @@ -13,7 +19,35 @@ void main() { group('OfflineFirstWithSupabaseGenerator', () { group('FieldSerializable', () { test('name', () async { - await generateExpectation('specify_field_name', specifyFieldName.output); + await generateExpectation('field_name', specify_field_name.output); + }); + }); + + group('@SupabaseSerializable', () { + test('defaultToNull', () async { + await generateAdapterExpectation('default_to_null', default_to_null.output); + }); + + test('fieldRename', () async { + await generateExpectation('field_rename', field_rename.output); + }); + + test('ignoreDuplicates', () async { + await generateAdapterExpectation('ignore_duplicates', ignore_duplicates.output); + }); + + test('onConflict', () async { + await generateAdapterExpectation('on_conflict', on_conflict.output); + }); + + group('tableName', () { + test('defined', () async { + await generateAdapterExpectation('table_name_defined', table_name_defined.output); + }); + + test('undefined', () async { + await generateAdapterExpectation('table_name_undefined', table_name_undefined.output); + }); }); }); }); diff --git a/packages/brick_supabase/README.md b/packages/brick_supabase/README.md index 97a693e0..3040796a 100644 --- a/packages/brick_supabase/README.md +++ b/packages/brick_supabase/README.md @@ -36,6 +36,18 @@ class User `fieldRename` is only the default transformation. Naming can be overriden on a field-by-field basis with `@Supabase(name:)`. +### `@SupabaseSerializable(defaultToNull:)` + +Forwards to [Supabase's defaultToNull](https://supabase.com/docs/reference/dart/upsert) during `upsert` operations. + +### `@SupabaseSerializable(ignoreDuplicates:)` + +Forwards to [Supabase's ignoreDuplicates](https://supabase.com/docs/reference/dart/upsert) during `upsert` operations. + +### `@SupabaseSerializable(onConflict:)` + +Forwards to [Supabase's onConflict](https://supabase.com/docs/reference/dart/upsert) during `upsert` operations. + ## Fields ### `@Supabase(unique:)` diff --git a/packages/brick_supabase/lib/src/supabase_adapter.dart b/packages/brick_supabase/lib/src/supabase_adapter.dart index 5b67bc9b..b693e8e2 100644 --- a/packages/brick_supabase/lib/src/supabase_adapter.dart +++ b/packages/brick_supabase/lib/src/supabase_adapter.dart @@ -24,7 +24,7 @@ abstract mixin class SupabaseAdapter implements Ad /// used to target upsert and delete operations. Set get uniqueFields; - TModel fromSupabase( + Future fromSupabase( Map input, { required SupabaseProvider provider, ModelRepository? repository, diff --git a/packages/brick_supabase/test/__mocks__.dart b/packages/brick_supabase/test/__mocks__.dart index 4ade27d1..99cead47 100644 --- a/packages/brick_supabase/test/__mocks__.dart +++ b/packages/brick_supabase/test/__mocks__.dart @@ -28,7 +28,8 @@ Future> _$DemoModelToSupabase(DemoModel instance) async { class DemoModelAdapter extends SupabaseAdapter { @override - DemoModel fromSupabase(data, {required provider, repository}) => _$DemoModelFromSupabase(data); + Future fromSupabase(data, {required provider, repository}) async => + _$DemoModelFromSupabase(data); @override Future> toSupabase(instance, {required provider, repository}) async => @@ -97,7 +98,7 @@ Future> _$DemoNestedAssociationModelToSupabase( class DemoNestedAssociationModelAdapter extends SupabaseAdapter { @override - DemoNestedAssociationModel fromSupabase(data, {required provider, repository}) => + Future fromSupabase(data, {required provider, repository}) async => _$DemoNestedAssociationModelFromSupabase(data); @override @@ -171,7 +172,7 @@ Future> _$DemoAssociationModelToSupabase(DemoAssociationMod class DemoAssociationModelAdapter extends SupabaseAdapter { @override - DemoAssociationModel fromSupabase(data, {required provider, repository}) => + Future fromSupabase(data, {required provider, repository}) async => _$DemoAssociationModelFromSupabase(data); @override diff --git a/packages/brick_supabase_generators/lib/src/supabase_deserialize.dart b/packages/brick_supabase_generators/lib/src/supabase_deserialize.dart index bb6d753a..48e4fafc 100644 --- a/packages/brick_supabase_generators/lib/src/supabase_deserialize.dart +++ b/packages/brick_supabase_generators/lib/src/supabase_deserialize.dart @@ -18,7 +18,7 @@ class SupabaseDeserialize extends SupabaseSerdesGenerator final config = (fields as SupabaseFields).config; return [ - if (config?.tableName != null) '@override\nfinal tableName = ${config!.tableName};', + if (config?.tableName != null) "@override\nfinal tableName = '${config!.tableName}';", ]; } } diff --git a/packages/brick_supabase_generators/lib/src/supabase_serialize.dart b/packages/brick_supabase_generators/lib/src/supabase_serialize.dart index 31f3c318..65f65e23 100644 --- a/packages/brick_supabase_generators/lib/src/supabase_serialize.dart +++ b/packages/brick_supabase_generators/lib/src/supabase_serialize.dart @@ -49,6 +49,20 @@ class SupabaseSerialize extends SupabaseSerdesGenerator ]; } + @override + String? coderForField(field, checker, {required wrappedInFuture, required fieldAnnotation}) { + // Supabase's API only accepts the active model + // Recursive assocations are iteratively upserted + if (checker.isSibling || (checker.isIterable && checker.isArgTypeASibling)) return null; + + return super.coderForField( + field, + checker, + wrappedInFuture: wrappedInFuture, + fieldAnnotation: fieldAnnotation, + ); + } + String _finalTypeForField(DartType type) { final checker = checkerForType(type); final typeRemover = RegExp(r'\<[,\s\w]+\>'); diff --git a/packages/brick_supabase_generators/test/supabase_model_serdes_generator/test_constructor_member_field_mismatch.dart b/packages/brick_supabase_generators/test/supabase_model_serdes_generator/test_constructor_member_field_mismatch.dart index 5b35bea1..cb2918c2 100644 --- a/packages/brick_supabase_generators/test/supabase_model_serdes_generator/test_constructor_member_field_mismatch.dart +++ b/packages/brick_supabase_generators/test/supabase_model_serdes_generator/test_constructor_member_field_mismatch.dart @@ -23,11 +23,7 @@ Future> _$SupabaseConstructorMemberFieldMismatchToSupabase( SupabaseFirstRepository? repository}) async { return { 'nullable_constructor': instance.nullableConstructor, - 'non_nullable_constructor': instance.nonNullableConstructor, - 'some_field': await Future.wait>(instance.someField - .map((s) => AssocAdapter() - .toSupabase(s, provider: provider, repository: repository)) - .toList()) + 'non_nullable_constructor': instance.nonNullableConstructor }; } '''; diff --git a/packages/brick_supabase_generators/test/supabase_model_serdes_generator/test_runtime_supabase_column_definition.dart b/packages/brick_supabase_generators/test/supabase_model_serdes_generator/test_runtime_supabase_column_definition.dart new file mode 100644 index 00000000..da5648e4 --- /dev/null +++ b/packages/brick_supabase_generators/test/supabase_model_serdes_generator/test_runtime_supabase_column_definition.dart @@ -0,0 +1,109 @@ +import 'package:brick_supabase/brick_supabase.dart'; + +final output = r""" +// GENERATED CODE DO NOT EDIT +part of '../brick.g.dart'; + +Future _$SupabaseRuntimeFromSupabase(Map data, + {required SupabaseProvider provider, + SupabaseFirstRepository? repository}) async { + return SupabaseRuntime( + someField: data['some_field'] as int, + unannotatedAssoc: await AssocAdapter().fromSupabase( + data['unannotated_assoc'], + provider: provider, + repository: repository), + annotatedAssoc: await AssocAdapter().fromSupabase(data['annotated_assoc'], + provider: provider, repository: repository), + differentNameAssoc: await AssocAdapter().fromSupabase( + data['differing_name'], + provider: provider, + repository: repository)); +} + +Future> _$SupabaseRuntimeToSupabase( + SupabaseRuntime instance, + {required SupabaseProvider provider, + SupabaseFirstRepository? repository}) async { + return {'some_field': instance.someField}; +} + +/// Construct a [SupabaseRuntime] +class SupabaseRuntimeAdapter extends SupabaseFirstAdapter { + SupabaseRuntimeAdapter(); + + @override + final defaultToNull = true; + @override + final Map fieldsToSqliteColumns = { + 'someField': const RuntimeSupabaseColumnDefinition( + association: false, + associationForeignKey: 'null', + associationType: int, + columnName: 'some_field', + ), + 'unannotatedAssoc': const RuntimeSupabaseColumnDefinition( + association: true, + associationForeignKey: 'null', + associationType: Assoc, + columnName: 'unannotated_assoc', + ), + 'annotatedAssoc': const RuntimeSupabaseColumnDefinition( + association: true, + associationForeignKey: 'assoc_id', + associationType: Assoc, + columnName: 'annotated_assoc', + ), + 'differentNameAssoc': const RuntimeSupabaseColumnDefinition( + association: true, + associationForeignKey: 'assoc_id', + associationType: Assoc, + columnName: 'differing_name', + ) + }; + @override + final ignoreDuplicates = false; + @override + final uniqueFields = {}; + + @override + Future fromSupabase(Map input, + {required provider, + covariant SupabaseFirstRepository? repository}) async => + await _$SupabaseRuntimeFromSupabase(input, + provider: provider, repository: repository); + @override + Future> toSupabase(SupabaseRuntime input, + {required provider, + covariant SupabaseFirstRepository? repository}) async => + await _$SupabaseRuntimeToSupabase(input, + provider: provider, repository: repository); +} +"""; + +@SupabaseSerializable() +class SupabaseRuntime extends SupabaseModel { + final int someField; + + final Assoc unannotatedAssoc; + + @Supabase(foreignKey: 'assoc_id') + final Assoc annotatedAssoc; + + @Supabase(foreignKey: 'assoc_id', name: 'differing_name') + final Assoc differentNameAssoc; + + SupabaseRuntime({ + required this.unannotatedAssoc, + required this.annotatedAssoc, + required this.someField, + required this.differentNameAssoc, + }); +} + +class Assoc extends SupabaseModel { + @Supabase(unique: true) + final int someField; + + Assoc(this.someField); +} diff --git a/packages/brick_supabase_generators/test/supabase_model_serdes_generator_test.dart b/packages/brick_supabase_generators/test/supabase_model_serdes_generator_test.dart index 623422f5..ac1c0c18 100644 --- a/packages/brick_supabase_generators/test/supabase_model_serdes_generator_test.dart +++ b/packages/brick_supabase_generators/test/supabase_model_serdes_generator_test.dart @@ -10,6 +10,8 @@ import 'supabase_model_serdes_generator/test_constructor_member_field_mismatch.d as constructor_member_field_mismatch; import 'supabase_model_serdes_generator/test_enum_as_string.dart' as enum_as_string; import 'supabase_model_serdes_generator/test_ignore_from_to.dart' as ignore_from_to; +import 'supabase_model_serdes_generator/test_runtime_supabase_column_definition.dart' + as runtime_supabase_column_definition; import 'supabase_model_serdes_generator/test_unique.dart' as unique; import 'supabase_model_serdes_generator/test_unserializable_field_with_generator.dart' as unserializable_field_with_generator; @@ -47,6 +49,13 @@ void main() { ); }); }); + + test('runtime associations', () async { + await generateAdapterExpectation( + 'runtime_supabase_column_definition', + runtime_supabase_column_definition.output, + ); + }); }); }