diff --git a/packages/api/amplify_api_dart/lib/src/graphql/factories/graphql_request_factory.dart b/packages/api/amplify_api_dart/lib/src/graphql/factories/graphql_request_factory.dart index faec155bfa..d484c5b799 100644 --- a/packages/api/amplify_api_dart/lib/src/graphql/factories/graphql_request_factory.dart +++ b/packages/api/amplify_api_dart/lib/src/graphql/factories/graphql_request_factory.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import 'package:amplify_api_dart/src/graphql/utils.dart'; import 'package:amplify_core/amplify_core.dart'; +import 'package:collection/collection.dart'; // ignore_for_file: public_member_api_docs @@ -322,6 +323,10 @@ class GraphQLRequestFactory { } } + final ownerFieldNames = (schema.authRules ?? []) + .map((authRule) => authRule.ownerField) + .whereNotNull() + .toSet(); // Remove some fields from input. final fieldsToRemove = schema.fields!.entries .where( @@ -330,8 +335,9 @@ class GraphQLRequestFactory { entry.value.association != null || // read-only entry.value.isReadOnly || - // null values on create operations + // null values for owner fields on create operations (operation == GraphQLRequestOperation.create && + ownerFieldNames.contains(entry.value.name) && modelJson[entry.value.name] == null), ) .map((entry) => entry.key) diff --git a/packages/api/amplify_api_dart/test/graphql_helpers_test.dart b/packages/api/amplify_api_dart/test/graphql_helpers_test.dart index 4c3d0fc244..7f85a058ef 100644 --- a/packages/api/amplify_api_dart/test/graphql_helpers_test.dart +++ b/packages/api/amplify_api_dart/test/graphql_helpers_test.dart @@ -377,6 +377,8 @@ void main() { 'id': id, 'name': name, 'createdAt': time, + 'file': null, + 'files': null } }; const expectedDoc = @@ -391,15 +393,15 @@ void main() { }); test( - 'ModelMutations.create() should not include null fields in input variable', + 'ModelMutations.create() should not include null values for owner fields', () { - const name = 'Test Blog'; - - final Blog blog = Blog(name: name); - final GraphQLRequest req = ModelMutations.create(blog); + const name = 'Test with owner field'; + final customOwnerField = CustomOwnerField(name: name); + final GraphQLRequest req = + ModelMutations.create(customOwnerField); final inputVariable = req.variables['input'] as Map; - expect(inputVariable.containsKey('file'), isFalse); + expect(inputVariable.containsKey('owners'), isFalse); }); test( @@ -422,6 +424,8 @@ void main() { 'id': postId, 'title': title, 'rating': rating, + 'created': null, + 'likeCount': null, 'blogID': blogId } }; diff --git a/packages/api/amplify_api_dart/test/test_models/CustomOwnerField.dart b/packages/api/amplify_api_dart/test/test_models/CustomOwnerField.dart new file mode 100644 index 0000000000..37c8068fc5 --- /dev/null +++ b/packages/api/amplify_api_dart/test/test_models/CustomOwnerField.dart @@ -0,0 +1,279 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'package:amplify_core/amplify_core.dart'; +import 'package:collection/collection.dart'; +import 'package:meta/meta.dart'; + +/** This is an auto generated class representing the CustomOwnerField type in your schema. */ +@immutable +class CustomOwnerField extends Model { + static const classType = const _CustomOwnerFieldModelType(); + final String id; + final String? _name; + final List? _owners; + final String? _private; + final TemporalDateTime? _createdAt; + final TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated( + '[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + CustomOwnerFieldModelIdentifier get modelIdentifier { + return CustomOwnerFieldModelIdentifier(id: id); + } + + String get name { + try { + return _name!; + } catch (e) { + throw new AmplifyCodeGenModelException( + AmplifyExceptionMessages + .codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: AmplifyExceptionMessages + .codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString()); + } + } + + List? get owners { + return _owners; + } + + String? get private { + return _private; + } + + TemporalDateTime? get createdAt { + return _createdAt; + } + + TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const CustomOwnerField._internal( + {required this.id, required name, owners, private, createdAt, updatedAt}) + : _name = name, + _owners = owners, + _private = private, + _createdAt = createdAt, + _updatedAt = updatedAt; + + factory CustomOwnerField( + {String? id, + required String name, + List? owners, + String? private}) { + return CustomOwnerField._internal( + id: id == null ? UUID.getUUID() : id, + name: name, + owners: owners != null ? List.unmodifiable(owners) : owners, + private: private); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is CustomOwnerField && + id == other.id && + _name == other._name && + DeepCollectionEquality().equals(_owners, other._owners) && + _private == other._private; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write("CustomOwnerField {"); + buffer.write("id=" + "$id" + ", "); + buffer.write("name=" + "$_name" + ", "); + buffer.write( + "owners=" + (_owners != null ? _owners!.toString() : "null") + ", "); + buffer.write("private=" + "$_private" + ", "); + buffer.write("createdAt=" + + (_createdAt != null ? _createdAt!.format() : "null") + + ", "); + buffer.write( + "updatedAt=" + (_updatedAt != null ? _updatedAt!.format() : "null")); + buffer.write("}"); + + return buffer.toString(); + } + + CustomOwnerField copyWith( + {String? name, List? owners, String? private}) { + return CustomOwnerField._internal( + id: id, + name: name ?? this.name, + owners: owners ?? this.owners, + private: private ?? this.private); + } + + CustomOwnerField.fromJson(Map json) + : id = json['id'], + _name = json['name'], + _owners = json['owners']?.cast(), + _private = json['private'], + _createdAt = json['createdAt'] != null + ? TemporalDateTime.fromString(json['createdAt']) + : null, + _updatedAt = json['updatedAt'] != null + ? TemporalDateTime.fromString(json['updatedAt']) + : null; + + Map toJson() => { + 'id': id, + 'name': _name, + 'owners': _owners, + 'private': _private, + 'createdAt': _createdAt?.format(), + 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'name': _name, + 'owners': _owners, + 'private': _private, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final QueryModelIdentifier + MODEL_IDENTIFIER = + QueryModelIdentifier(); + static final QueryField ID = QueryField(fieldName: "id"); + static final QueryField NAME = QueryField(fieldName: "name"); + static final QueryField OWNERS = QueryField(fieldName: "owners"); + static final QueryField PRIVATE = QueryField(fieldName: "private"); + static var schema = + Model.defineSchema(define: (ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = "CustomOwnerField"; + modelSchemaDefinition.pluralName = "CustomOwnerFields"; + + modelSchemaDefinition.authRules = [ + AuthRule(authStrategy: AuthStrategy.PRIVATE, operations: [ + ModelOperation.CREATE, + ModelOperation.UPDATE, + ModelOperation.DELETE, + ModelOperation.READ + ]), + AuthRule( + authStrategy: AuthStrategy.OWNER, + ownerField: "owners", + identityClaim: "cognito:username", + provider: AuthRuleProvider.USERPOOLS, + operations: [ + ModelOperation.CREATE, + ModelOperation.UPDATE, + ModelOperation.DELETE, + ModelOperation.READ + ]) + ]; + + modelSchemaDefinition.addField(ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(ModelFieldDefinition.field( + key: CustomOwnerField.NAME, + isRequired: true, + ofType: ModelFieldType(ModelFieldTypeEnum.string))); + + modelSchemaDefinition.addField(ModelFieldDefinition.field( + key: CustomOwnerField.OWNERS, + isRequired: false, + isArray: true, + ofType: ModelFieldType(ModelFieldTypeEnum.collection, + ofModelName: ModelFieldTypeEnum.string.name))); + + modelSchemaDefinition.addField(ModelFieldDefinition.field( + key: CustomOwnerField.PRIVATE, + isRequired: false, + ofType: ModelFieldType(ModelFieldTypeEnum.string))); + + modelSchemaDefinition.addField(ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: ModelFieldType(ModelFieldTypeEnum.dateTime))); + + modelSchemaDefinition.addField(ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: ModelFieldType(ModelFieldTypeEnum.dateTime))); + }); +} + +class _CustomOwnerFieldModelType extends ModelType { + const _CustomOwnerFieldModelType(); + + @override + CustomOwnerField fromJson(Map jsonData) { + return CustomOwnerField.fromJson(jsonData); + } + + @override + String modelName() { + return 'CustomOwnerField'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [CustomOwnerField] in your schema. + */ +@immutable +class CustomOwnerFieldModelIdentifier + implements ModelIdentifier { + final String id; + + /** Create an instance of CustomOwnerFieldModelIdentifier using [id] the primary key. */ + const CustomOwnerFieldModelIdentifier({required this.id}); + + @override + Map serializeAsMap() => ({'id': id}); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({entry.key: entry.value})) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'CustomOwnerFieldModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is CustomOwnerFieldModelIdentifier && id == other.id; + } + + @override + int get hashCode => id.hashCode; +} diff --git a/packages/api/amplify_api_dart/test/test_models/ModelProvider.dart b/packages/api/amplify_api_dart/test/test_models/ModelProvider.dart index ed3f822629..59dbf94491 100644 --- a/packages/api/amplify_api_dart/test/test_models/ModelProvider.dart +++ b/packages/api/amplify_api_dart/test/test_models/ModelProvider.dart @@ -11,12 +11,14 @@ import 'package:amplify_core/amplify_core.dart'; import 'Blog.dart'; import 'Comment.dart'; +import 'CustomOwnerField.dart'; import 'FileMeta.dart'; import 'Post.dart'; import 'S3Object.dart'; export 'Blog.dart'; export 'Comment.dart'; +export 'CustomOwnerField.dart'; export 'FileMeta.dart'; export 'Post.dart'; export 'S3Object.dart'; @@ -28,6 +30,7 @@ class ModelProvider implements ModelProviderInterface { List modelSchemas = [ Blog.schema, Comment.schema, + CustomOwnerField.schema, Post.schema, ]; static final ModelProvider _instance = ModelProvider(); @@ -42,6 +45,8 @@ class ModelProvider implements ModelProviderInterface { return Blog.classType; case 'Comment': return Comment.classType; + case "CustomOwnerField": + return CustomOwnerField.classType; case 'Post': return Post.classType; default: