Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(api): GraphQL Model Helpers support lowercase model names #4143

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,18 @@ type OwnerOnly @model @auth(rules: [{allow: owner}]) {
id: ID!
name: String!
}

type lowerCase
@model
@auth(
rules: [
{ allow: public, operations: [read], provider: apiKey },
{ allow: public, operations: [read], provider: iam },
{ allow: private, operations: [read], provider: iam },
{ allow: private, operations: [read], provider: userPools },
{ allow: owner, operations: [create, read, update, delete] }
]
) {
id: ID!
name: String!
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@ void main({bool useExistingTestUser = false}) {
expect(data.rating, equals(rating));
});

testWidgets('should CREATE a lower case model name with Model helper',
(WidgetTester tester) async {
final name = 'Integration Test lowercase - ${uuid()}';
final model = lowerCase(name: name);

final req = ModelMutations.create(
model,
authorizationMode: APIAuthorizationType.userPools,
);
final res = await Amplify.API.mutate(request: req).response;
expect(res, hasNoGraphQLErrors);
final data = res.data;
if (data != null) lowerCaseCache.add(data);

expect(data?.name, equals(model.name));
expect(data?.id, equals(model.id));
});

testWidgets('should UPDATE a blog with Model helper',
(WidgetTester tester) async {
const oldName = 'Integration Test Blog to update';
Expand Down
14 changes: 14 additions & 0 deletions packages/api/amplify_api/example/integration_test/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ TestUser? testUser;
final blogCache = <Blog>[];
final postCache = <Post>[];
final ownerOnlyCache = <OwnerOnly>[];
final lowerCaseCache = <lowerCase>[];
final cpkParentCache = <CpkOneToOneBidirectionalParentCD>[];
final cpkExplicitChildCache = <CpkOneToOneBidirectionalChildExplicitCD>[];
final cpkImplicitChildCache = <CpkOneToOneBidirectionalChildImplicitCD>[];
Expand Down Expand Up @@ -297,12 +298,25 @@ Future<OwnerOnly?> deleteOwnerOnly(OwnerOnly model) async {
return res.data;
}

Future<lowerCase?> deleteLowerCase(lowerCase model) async {
final request = ModelMutations.deleteById(
lowerCase.classType,
model.modelIdentifier,
authorizationMode: APIAuthorizationType.userPools,
);
final res = await Amplify.API.mutate(request: request).response;
expect(res, hasNoGraphQLErrors);
lowerCaseCache.removeWhere((modelFromCache) => modelFromCache.id == model.id);
return res.data;
}

Future<void> deleteTestModels() async {
await Future.wait(blogCache.map(deleteBlog));
await Future.wait(postCache.map(deletePost));
await Future.wait(cpkExplicitChildCache.map(deleteCpkExplicitChild));
await Future.wait(cpkImplicitChildCache.map(deleteCpkImplicitChild));
await Future.wait(ownerOnlyCache.map(deleteOwnerOnly));
await Future.wait(lowerCaseCache.map(deleteLowerCase));
}

/// Wait for subscription established for given request.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

157 changes: 86 additions & 71 deletions packages/api/amplify_api/example/lib/models/Blog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,17 @@
// 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 'ModelProvider.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_core/amplify_core.dart' as amplify_core;
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';

/// This is an auto generated class representing the Blog type in your schema.
@immutable
class Blog extends Model {
static const classType = _BlogModelType();
/** This is an auto generated class representing the Blog type in your schema. */
class Blog extends amplify_core.Model {
static const classType = const _BlogModelType();
final String id;
final String? _name;
final List<Post>? _posts;
final TemporalDateTime? _createdAt;
final TemporalDateTime? _updatedAt;
final amplify_core.TemporalDateTime? _createdAt;
final amplify_core.TemporalDateTime? _updatedAt;

@override
getInstanceType() => classType;
Expand All @@ -50,10 +48,10 @@ class Blog extends Model {
try {
return _name!;
} catch (e) {
throw AmplifyCodeGenModelException(
AmplifyExceptionMessages
throw amplify_core.AmplifyCodeGenModelException(
amplify_core.AmplifyExceptionMessages
.codeGenRequiredFieldForceCastExceptionMessage,
recoverySuggestion: AmplifyExceptionMessages
recoverySuggestion: amplify_core.AmplifyExceptionMessages
.codeGenRequiredFieldForceCastRecoverySuggestion,
underlyingException: e.toString());
}
Expand All @@ -63,11 +61,11 @@ class Blog extends Model {
return _posts;
}

TemporalDateTime? get createdAt {
amplify_core.TemporalDateTime? get createdAt {
return _createdAt;
}

TemporalDateTime? get updatedAt {
amplify_core.TemporalDateTime? get updatedAt {
return _updatedAt;
}

Expand All @@ -80,7 +78,7 @@ class Blog extends Model {

factory Blog({String? id, required String name, List<Post>? posts}) {
return Blog._internal(
id: id == null ? UUID.getUUID() : id,
id: id == null ? amplify_core.UUID.getUUID() : id,
name: name,
posts: posts != null ? List<Post>.unmodifiable(posts) : posts);
}
Expand All @@ -103,7 +101,7 @@ class Blog extends Model {

@override
String toString() {
var buffer = StringBuffer();
var buffer = new StringBuffer();

buffer.write("Blog {");
buffer.write("id=" + "$id" + ", ");
Expand All @@ -123,21 +121,29 @@ class Blog extends Model {
id: id, name: name ?? this.name, posts: posts ?? this.posts);
}

Blog copyWithModelFieldValues(
{ModelFieldValue<String>? name, ModelFieldValue<List<Post>?>? posts}) {
return Blog._internal(
id: id,
name: name == null ? this.name : name.value,
posts: posts == null ? this.posts : posts.value);
}

Blog.fromJson(Map<String, dynamic> json)
: id = json['id'],
_name = json['name'],
_posts = json['posts'] is List
? (json['posts'] as List)
.where((e) => e?['serializedData'] != null)
.map((e) => Post.fromJson(
Map<String, dynamic>.from(e['serializedData'])))
new Map<String, dynamic>.from(e['serializedData'])))
.toList()
: null,
_createdAt = json['createdAt'] != null
? TemporalDateTime.fromString(json['createdAt'])
? amplify_core.TemporalDateTime.fromString(json['createdAt'])
: null,
_updatedAt = json['updatedAt'] != null
? TemporalDateTime.fromString(json['updatedAt'])
? amplify_core.TemporalDateTime.fromString(json['updatedAt'])
: null;

Map<String, dynamic> toJson() => {
Expand All @@ -156,76 +162,84 @@ class Blog extends Model {
'updatedAt': _updatedAt
};

static final QueryModelIdentifier<BlogModelIdentifier> MODEL_IDENTIFIER =
QueryModelIdentifier<BlogModelIdentifier>();
static final QueryField ID = QueryField(fieldName: "id");
static final QueryField NAME = QueryField(fieldName: "name");
static final QueryField POSTS = QueryField(
static final amplify_core.QueryModelIdentifier<BlogModelIdentifier>
MODEL_IDENTIFIER =
amplify_core.QueryModelIdentifier<BlogModelIdentifier>();
static final ID = amplify_core.QueryField(fieldName: "id");
static final NAME = amplify_core.QueryField(fieldName: "name");
static final POSTS = amplify_core.QueryField(
fieldName: "posts",
fieldType: ModelFieldType(ModelFieldTypeEnum.model, ofModelName: 'Post'));
static var schema =
Model.defineSchema(define: (ModelSchemaDefinition modelSchemaDefinition) {
fieldType: amplify_core.ModelFieldType(
amplify_core.ModelFieldTypeEnum.model,
ofModelName: 'Post'));
static var schema = amplify_core.Model.defineSchema(
define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) {
modelSchemaDefinition.name = "Blog";
modelSchemaDefinition.pluralName = "Blogs";

modelSchemaDefinition.authRules = [
AuthRule(
authStrategy: AuthStrategy.PUBLIC,
provider: AuthRuleProvider.APIKEY,
operations: [ModelOperation.READ]),
AuthRule(
authStrategy: AuthStrategy.PUBLIC,
provider: AuthRuleProvider.IAM,
operations: [ModelOperation.READ]),
AuthRule(
authStrategy: AuthStrategy.PRIVATE,
provider: AuthRuleProvider.IAM,
operations: [ModelOperation.READ]),
AuthRule(
authStrategy: AuthStrategy.PRIVATE,
provider: AuthRuleProvider.USERPOOLS,
operations: [ModelOperation.READ]),
AuthRule(
authStrategy: AuthStrategy.OWNER,
amplify_core.AuthRule(
authStrategy: amplify_core.AuthStrategy.PUBLIC,
provider: amplify_core.AuthRuleProvider.APIKEY,
operations: const [amplify_core.ModelOperation.READ]),
amplify_core.AuthRule(
authStrategy: amplify_core.AuthStrategy.PUBLIC,
provider: amplify_core.AuthRuleProvider.IAM,
operations: const [amplify_core.ModelOperation.READ]),
amplify_core.AuthRule(
authStrategy: amplify_core.AuthStrategy.PRIVATE,
provider: amplify_core.AuthRuleProvider.IAM,
operations: const [amplify_core.ModelOperation.READ]),
amplify_core.AuthRule(
authStrategy: amplify_core.AuthStrategy.PRIVATE,
provider: amplify_core.AuthRuleProvider.USERPOOLS,
operations: const [amplify_core.ModelOperation.READ]),
amplify_core.AuthRule(
authStrategy: amplify_core.AuthStrategy.OWNER,
ownerField: "owner",
identityClaim: "cognito:username",
provider: AuthRuleProvider.USERPOOLS,
operations: [
ModelOperation.CREATE,
ModelOperation.READ,
ModelOperation.UPDATE,
ModelOperation.DELETE
provider: amplify_core.AuthRuleProvider.USERPOOLS,
operations: const [
amplify_core.ModelOperation.CREATE,
amplify_core.ModelOperation.READ,
amplify_core.ModelOperation.UPDATE,
amplify_core.ModelOperation.DELETE
])
];

modelSchemaDefinition.addField(ModelFieldDefinition.id());
modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id());

modelSchemaDefinition.addField(ModelFieldDefinition.field(
modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field(
key: Blog.NAME,
isRequired: true,
ofType: ModelFieldType(ModelFieldTypeEnum.string)));
ofType: amplify_core.ModelFieldType(
amplify_core.ModelFieldTypeEnum.string)));

modelSchemaDefinition.addField(ModelFieldDefinition.hasMany(
modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasMany(
key: Blog.POSTS,
isRequired: false,
ofModelName: 'Post',
associatedKey: Post.BLOG));

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)));
modelSchemaDefinition.addField(
amplify_core.ModelFieldDefinition.nonQueryField(
fieldName: 'createdAt',
isRequired: false,
isReadOnly: true,
ofType: amplify_core.ModelFieldType(
amplify_core.ModelFieldTypeEnum.dateTime)));

modelSchemaDefinition.addField(
amplify_core.ModelFieldDefinition.nonQueryField(
fieldName: 'updatedAt',
isRequired: false,
isReadOnly: true,
ofType: amplify_core.ModelFieldType(
amplify_core.ModelFieldTypeEnum.dateTime)));
});
}

class _BlogModelType extends ModelType<Blog> {
class _BlogModelType extends amplify_core.ModelType<Blog> {
const _BlogModelType();

@override
Expand All @@ -239,13 +253,14 @@ class _BlogModelType extends ModelType<Blog> {
}
}

/// This is an auto generated class representing the model identifier
/// of [Blog] in your schema.
@immutable
class BlogModelIdentifier implements ModelIdentifier<Blog> {
/**
* This is an auto generated class representing the model identifier
* of [Blog] in your schema.
*/
class BlogModelIdentifier implements amplify_core.ModelIdentifier<Blog> {
final String id;

/// Create an instance of BlogModelIdentifier using [id] the primary key.
/** Create an instance of BlogModelIdentifier using [id] the primary key. */
const BlogModelIdentifier({required this.id});

@override
Expand Down
Loading
Loading