diff --git a/packages/supabase_typegen/lib/src/generator_metadata_parser.dart b/packages/supabase_typegen/lib/src/generator_metadata_parser.dart index d104714ad..100ac9163 100644 --- a/packages/supabase_typegen/lib/src/generator_metadata_parser.dart +++ b/packages/supabase_typegen/lib/src/generator_metadata_parser.dart @@ -125,13 +125,18 @@ DatabaseDescription _parseGeneratorMetadata( final relations = [ for (final table in _relationsOf(document, 'tables', schemas)) - (relation: table, isInsertable: true, isUpdatable: true), + (relation: table, isInsertable: true, isUpdatable: true, isView: false), for (final foreignTable in _relationsOf( document, 'foreignTables', schemas, )) - (relation: foreignTable, isInsertable: true, isUpdatable: true), + ( + relation: foreignTable, + isInsertable: true, + isUpdatable: true, + isView: false, + ), for (final view in _relationsOf(document, 'views', schemas)) ( relation: view, @@ -139,13 +144,19 @@ DatabaseDescription _parseGeneratorMetadata( (view['is_insert_enabled'] ?? view['is_updatable']) as bool, isUpdatable: (view['is_update_enabled'] ?? view['is_updatable']) as bool, + isView: true, ), for (final materializedView in _relationsOf( document, 'materializedViews', schemas, )) - (relation: materializedView, isInsertable: false, isUpdatable: false), + ( + relation: materializedView, + isInsertable: false, + isUpdatable: false, + isView: true, + ), ]; // Document order is kept: `sortGeneratorMetadata` orders columns by name @@ -180,7 +191,8 @@ DatabaseDescription _parseGeneratorMetadata( ), }; final generatedRelations = { - for (final (:relation, isInsertable: _, isUpdatable: _) in relations) + for (final (:relation, isInsertable: _, isUpdatable: _, isView: _) + in relations) (relation['schema'] as String, relation['name'] as String), }; final functionsByRelationId = _functionsByRelationId(document, typesById); @@ -188,7 +200,7 @@ DatabaseDescription _parseGeneratorMetadata( final tables = []; final enumsByType = <(String, String), EnumDescription>{}; - for (final (:relation, :isInsertable, :isUpdatable) in relations) { + for (final (:relation, :isInsertable, :isUpdatable, :isView) in relations) { final relationSchema = relation['schema'] as String; final relationName = relation['name'] as String; @@ -242,7 +254,9 @@ DatabaseDescription _parseGeneratorMetadata( _rangeBoundKinds[isArray ? format.substring(1) : format], enumValues: isEnum ? enumValues : null, enumType: enumDescription, - isRequired: !isNullable && !hasDefault, + // A view column does not carry the default of the column it reads, + // so an insert through the view may still omit it. + isRequired: !isView && !isNullable && !hasDefault, hasDefault: hasDefault, isNullable: isNullable, isReadOnly: diff --git a/packages/supabase_typegen/test/fixtures/generator_metadata.json b/packages/supabase_typegen/test/fixtures/generator_metadata.json index 2ff66067c..0e83136a5 100644 --- a/packages/supabase_typegen/test/fixtures/generator_metadata.json +++ b/packages/supabase_typegen/test/fixtures/generator_metadata.json @@ -270,7 +270,7 @@ "is_identity": false, "identity_generation": null, "is_generated": false, - "is_nullable": true, + "is_nullable": false, "is_updatable": false, "is_unique": false, "check": null, @@ -375,7 +375,7 @@ "is_identity": false, "identity_generation": null, "is_generated": false, - "is_nullable": true, + "is_nullable": false, "is_updatable": true, "is_unique": false, "check": null, @@ -417,7 +417,7 @@ "is_identity": false, "identity_generation": null, "is_generated": false, - "is_nullable": true, + "is_nullable": false, "is_updatable": true, "is_unique": false, "check": null, @@ -438,7 +438,7 @@ "is_identity": false, "identity_generation": null, "is_generated": false, - "is_nullable": true, + "is_nullable": false, "is_updatable": true, "is_unique": false, "check": null, @@ -459,7 +459,7 @@ "is_identity": false, "identity_generation": null, "is_generated": false, - "is_nullable": true, + "is_nullable": false, "is_updatable": true, "is_unique": false, "check": null, @@ -480,7 +480,7 @@ "is_identity": false, "identity_generation": null, "is_generated": false, - "is_nullable": true, + "is_nullable": false, "is_updatable": false, "is_unique": false, "check": null, @@ -501,7 +501,7 @@ "is_identity": false, "identity_generation": null, "is_generated": false, - "is_nullable": true, + "is_nullable": false, "is_updatable": false, "is_unique": false, "check": null, @@ -522,7 +522,7 @@ "is_identity": false, "identity_generation": null, "is_generated": false, - "is_nullable": true, + "is_nullable": false, "is_updatable": false, "is_unique": false, "check": null, @@ -8168,7 +8168,7 @@ "is_setof_return": true }, "computed_field_of": 16392, - "error": null + "error": "the function public.latest_book with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache" } ] }, @@ -8327,7 +8327,7 @@ "is_setof_return": true }, "computed_field_of": 16392, - "error": null + "error": "the function public.recent_books with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache" } ] }, diff --git a/packages/supabase_typegen/test/generator_metadata_parser_test.dart b/packages/supabase_typegen/test/generator_metadata_parser_test.dart index 31189f998..3981fbc51 100644 --- a/packages/supabase_typegen/test/generator_metadata_parser_test.dart +++ b/packages/supabase_typegen/test/generator_metadata_parser_test.dart @@ -862,7 +862,17 @@ void main() { 'author_id', 'book_count', ]); - expect(authorStats.columns.first.isNullable, isTrue); + expect(authorStats.columns.first.isNullable, isFalse); + expect(authorStats.columns.last.isNullable, isTrue); + }); + + test('non-null view columns are not required on insert', () { + final bookPrices = schema.tables.singleWhere( + (table) => table.name == 'book_prices', + ); + final id = bookPrices.columns.singleWhere((column) => column.name == 'id'); + expect(id.isNullable, isFalse); + expect(id.isRequired, isFalse); }); test('foreign tables are insertable and updatable', () { diff --git a/packages/supabase_typegen/test/goldens/hostile_schema.dart b/packages/supabase_typegen/test/goldens/hostile_schema.dart index fe2915084..cd7768c75 100644 --- a/packages/supabase_typegen/test/goldens/hostile_schema.dart +++ b/packages/supabase_typegen/test/goldens/hostile_schema.dart @@ -1,4 +1,4 @@ -// Generated by supabase_typegen 0.5.0 from GeneratorMetadata version 1. +// Generated by supabase_typegen 0.5.2 from GeneratorMetadata version 1. // Do not edit by hand. // // Source schemas: evil multiline "schema" name, private, public diff --git a/packages/supabase_typegen/test/goldens/supabase_schema.dart b/packages/supabase_typegen/test/goldens/supabase_schema.dart index 4c26425c5..3f2f8370c 100644 --- a/packages/supabase_typegen/test/goldens/supabase_schema.dart +++ b/packages/supabase_typegen/test/goldens/supabase_schema.dart @@ -1,4 +1,4 @@ -// Generated by supabase_typegen 0.5.0 from GeneratorMetadata version 1. +// Generated by supabase_typegen 0.5.2 from GeneratorMetadata version 1. // Do not edit by hand. // // Source schemas: inventory, public @@ -215,7 +215,7 @@ class InventoryStock { /// Aggregated statistics per author extension type const AuthorStatsRow(Map _json) implements Object { - int? get authorId => _json['author_id'] as int?; + int get authorId => _json['author_id'] as int; int? get bookCount => _json['book_count'] as int?; /// The row as decoded from the response. @@ -235,9 +235,7 @@ class AuthorStats { relations: [authors], ); - static const authorId = PostgrestNullableColumn( - 'author_id', - ); + static const authorId = PostgrestColumn('author_id'); static const bookCount = PostgrestNullableColumn( 'book_count', ); @@ -331,9 +329,9 @@ class Authors { extension type const BookPricesRow(Map _json) implements Object { num? get discountedPrice => _json['discounted_price'] as num?; - int? get id => _json['id'] as int?; + int get id => _json['id'] as int; num? get price => _json['price'] as num?; - String? get title => _json['title'] as String?; + String get title => _json['title'] as String; /// The row as decoded from the response. Map toJson() => _json; @@ -349,18 +347,10 @@ extension type const BookPricesInsert._(Map _json) BookPricesInsert({int? id, num? price, String? title}) : this._({'id': ?id, 'price': ?price, 'title': ?title}); - /// Returns a copy with `id` set to SQL NULL, overriding any database default. - BookPricesInsert setIdToNull() => BookPricesInsert._({..._json, 'id': null}); - /// Returns a copy with `price` set to SQL NULL, overriding any database /// default. BookPricesInsert setPriceToNull() => BookPricesInsert._({..._json, 'price': null}); - - /// Returns a copy with `title` set to SQL NULL, overriding any database - /// default. - BookPricesInsert setTitleToNull() => - BookPricesInsert._({..._json, 'title': null}); } /// Values for updating rows of `book_prices`. All columns are optional; passing @@ -371,18 +361,10 @@ extension type const BookPricesUpdate._(Map _json) BookPricesUpdate({int? id, num? price, String? title}) : this._({'id': ?id, 'price': ?price, 'title': ?title}); - /// Returns a copy with `id` set to SQL NULL, overriding any database default. - BookPricesUpdate setIdToNull() => BookPricesUpdate._({..._json, 'id': null}); - /// Returns a copy with `price` set to SQL NULL, overriding any database /// default. BookPricesUpdate setPriceToNull() => BookPricesUpdate._({..._json, 'price': null}); - - /// Returns a copy with `title` set to SQL NULL, overriding any database - /// default. - BookPricesUpdate setTitleToNull() => - BookPricesUpdate._({..._json, 'title': null}); } /// Typed access to the `book_prices` table. @@ -402,9 +384,9 @@ class BookPrices { static const discountedPrice = PostgrestNullableColumn( 'discounted_price', ); - static const id = PostgrestNullableColumn('id'); + static const id = PostgrestColumn('id'); static const price = PostgrestNullableColumn('price'); - static const title = PostgrestNullableColumn('title'); + static const title = PostgrestColumn('title'); /// The `discount` computed field, selected by name; `select()` leaves it out. static const discount = PostgrestComputedField( @@ -416,8 +398,8 @@ class BookPrices { /// column. extension type const BookSubmissionsRow(Map _json) implements Object { - String? get authorName => _json['author_name'] as String?; - String? get title => _json['title'] as String?; + String get authorName => _json['author_name'] as String; + String get title => _json['title'] as String; /// The row as decoded from the response. Map toJson() => _json; @@ -432,16 +414,6 @@ extension type const BookSubmissionsInsert._(Map _json) implements Object { BookSubmissionsInsert({String? authorName, String? title}) : this._({'author_name': ?authorName, 'title': ?title}); - - /// Returns a copy with `author_name` set to SQL NULL, overriding any database - /// default. - BookSubmissionsInsert setAuthorNameToNull() => - BookSubmissionsInsert._({..._json, 'author_name': null}); - - /// Returns a copy with `title` set to SQL NULL, overriding any database - /// default. - BookSubmissionsInsert setTitleToNull() => - BookSubmissionsInsert._({..._json, 'title': null}); } /// Typed access to the `book_submissions` table. @@ -457,12 +429,10 @@ class BookSubmissions { primaryKey: [], ); - static const authorName = PostgrestNullableColumn( + static const authorName = PostgrestColumn( 'author_name', ); - static const title = PostgrestNullableColumn( - 'title', - ); + static const title = PostgrestColumn('title'); } /// A row of the `book_summaries` table, as `select()` reads it with every @@ -470,9 +440,9 @@ class BookSubmissions { /// Denormalized book and author names extension type const BookSummariesRow(Map _json) implements Object { - String? get authorName => _json['author_name'] as String?; - int? get id => _json['id'] as int?; - String? get title => _json['title'] as String?; + String get authorName => _json['author_name'] as String; + int get id => _json['id'] as int; + String get title => _json['title'] as String; /// The row as decoded from the response. Map toJson() => _json; @@ -490,13 +460,11 @@ class BookSummaries { primaryKey: [], ); - static const authorName = PostgrestNullableColumn( + static const authorName = PostgrestColumn( 'author_name', ); - static const id = PostgrestNullableColumn('id'); - static const title = PostgrestNullableColumn( - 'title', - ); + static const id = PostgrestColumn('id'); + static const title = PostgrestColumn('title'); } /// A row of the `books` table, as `select()` reads it with every column.