From f79a767cc6871e23d603d241501ba75b32d9193c Mon Sep 17 00:00:00 2001 From: Justin Shih Date: Mon, 18 Sep 2023 16:15:45 +0000 Subject: [PATCH 1/2] chore(amplify-util-uibuilder): remove codegen-ui usage --- packages/amplify-util-uibuilder/package.json | 4 +- .../codegen-ui-dependency-provider.test.ts | 37 + .../__tests__/generic-from-datastore.test.ts | 343 ++ .../src/__tests__/mock-schemas.ts | 3749 +++++++++++++++++ .../__tests__/syncAmplifyUiComponents.test.ts | 2 +- .../src/__tests__/utils.ts | 2 +- .../src/commands/generateComponents.ts | 11 +- .../utils/codegen-ui-dependency-provider.ts | 39 + .../src/commands/utils/codegen-ui.ts | 344 ++ .../src/commands/utils/codegenResources.ts | 3 +- .../src/commands/utils/data-types.ts | 93 + .../commands/utils/notifyMissingPackages.ts | 3 +- .../utils/syncAmplifyUiBuilderComponents.ts | 4 +- yarn.lock | 315 +- 14 files changed, 4815 insertions(+), 134 deletions(-) create mode 100644 packages/amplify-util-uibuilder/src/__tests__/codegen-ui-dependency-provider.test.ts create mode 100644 packages/amplify-util-uibuilder/src/__tests__/generic-from-datastore.test.ts create mode 100644 packages/amplify-util-uibuilder/src/__tests__/mock-schemas.ts create mode 100644 packages/amplify-util-uibuilder/src/commands/utils/codegen-ui-dependency-provider.ts create mode 100644 packages/amplify-util-uibuilder/src/commands/utils/codegen-ui.ts create mode 100644 packages/amplify-util-uibuilder/src/commands/utils/data-types.ts diff --git a/packages/amplify-util-uibuilder/package.json b/packages/amplify-util-uibuilder/package.json index 03b56e66264..fbfc8d1e021 100644 --- a/packages/amplify-util-uibuilder/package.json +++ b/packages/amplify-util-uibuilder/package.json @@ -17,8 +17,6 @@ "@aws-amplify/amplify-category-api": "^5.6.4", "@aws-amplify/amplify-cli-core": "4.2.7", "@aws-amplify/amplify-prompts": "2.8.4", - "@aws-amplify/codegen-ui": "2.14.2", - "@aws-amplify/codegen-ui-react": "2.14.2", "amplify-codegen": "^4.6.2", "aws-sdk": "^2.1426.0", "fs-extra": "^8.1.0", @@ -28,10 +26,12 @@ }, "devDependencies": { "@aws-amplify/appsync-modelgen-plugin": "^2.6.0", + "@aws-amplify/datastore": "^4.7.5", "@types/fs-extra": "^8.0.1", "@types/jest": "^29.5.1", "@types/semver": "^7.1.0", "@types/tiny-async-pool": "^2.0.0", + "semver": "^7.5.4", "ts-jest": "^29.1.0" }, "jest": { diff --git a/packages/amplify-util-uibuilder/src/__tests__/codegen-ui-dependency-provider.test.ts b/packages/amplify-util-uibuilder/src/__tests__/codegen-ui-dependency-provider.test.ts new file mode 100644 index 00000000000..7d833c3293e --- /dev/null +++ b/packages/amplify-util-uibuilder/src/__tests__/codegen-ui-dependency-provider.test.ts @@ -0,0 +1,37 @@ +import semver from 'semver'; +import { ReactRequiredDependencyProvider } from '../commands/utils/codegen-ui-dependency-provider'; + +describe('ReactStudioDependencyProvider', () => { + const requiredDependencies = new ReactRequiredDependencyProvider().getRequiredDependencies(false); + const requiredDependenciesWithStorageManager = new ReactRequiredDependencyProvider().getRequiredDependencies(true); + + describe('getRequiredDependencies', () => { + it('has required dependencies', () => { + expect(requiredDependencies.length).toBeGreaterThan(0); + }); + + it('includes ui-react', () => { + expect(requiredDependencies.filter((dep) => dep.dependencyName === '@aws-amplify/ui-react')).toBeTruthy(); + }); + + it('includes all valid semver values', () => { + requiredDependencies.forEach((dep) => { + expect(semver.valid(dep.supportedSemVerPattern)).toBeDefined(); + }); + }); + + it('includes reasons on all dependencies', () => { + requiredDependencies.forEach((dep) => { + expect(dep.reason.length).toBeGreaterThan(0); + }); + }); + + it('does not include ui-react-storage if user does not use StorageManager', () => { + expect(requiredDependencies.filter((dep) => dep.dependencyName !== '@aws-amplify/ui-react-storage')).toBeTruthy(); + }); + + it('includes ui-react-storage if user is using StorageManager', () => { + expect(requiredDependenciesWithStorageManager.filter((dep) => dep.dependencyName === '@aws-amplify/ui-react-storage')).toBeTruthy(); + }); + }); +}); diff --git a/packages/amplify-util-uibuilder/src/__tests__/generic-from-datastore.test.ts b/packages/amplify-util-uibuilder/src/__tests__/generic-from-datastore.test.ts new file mode 100644 index 00000000000..0449f555b4e --- /dev/null +++ b/packages/amplify-util-uibuilder/src/__tests__/generic-from-datastore.test.ts @@ -0,0 +1,343 @@ +import { getGenericFromDataStore } from '../commands/utils/codegen-ui'; +import { HasManyRelationshipType } from '../commands/utils/data-types'; +import { + schemaWithEnums, + schemaWithNonModels, + schemaWithRelationships, + schemaWithRelationshipsV2, + schemaWithAssumptions, + schemaWithCPK, + schemaWithCompositeKeys, + schemaWithHasManyBelongsTo, + schemaWithoutJoinTables, + introspectionSchemaWithCompositeKeys, + schemaWithBiDirectionalHasManyWithDefinedField, +} from './mock-schemas'; + +describe('getGenericFromDataStore', () => { + it('should map fields', () => { + const genericSchema = getGenericFromDataStore(schemaWithRelationships); + expect(genericSchema.models.Child.fields).toStrictEqual({ + id: { + dataType: 'ID', + required: true, + readOnly: false, + isArray: false, + }, + name: { + dataType: 'String', + required: false, + readOnly: false, + isArray: false, + }, + createdAt: { + dataType: 'AWSDateTime', + required: false, + readOnly: true, + isArray: false, + }, + updatedAt: { + dataType: 'AWSDateTime', + required: false, + readOnly: true, + isArray: false, + }, + }); + }); + + it('should map relationships', () => { + const genericSchema = getGenericFromDataStore(schemaWithRelationships); + + expect(genericSchema.models.PrimaryCareGiver.fields.Child.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Child', + associatedFields: ['primaryCareGiverChildId'], + }); + + expect(genericSchema.models.PrimaryCareGiver.fields.primaryCareGiverChildId.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Child', + }); + + expect(genericSchema.models.Student.fields.Teachers.relationship).toStrictEqual({ + type: 'HAS_MANY', + relatedModelName: 'Teacher', + relatedModelFields: ['student'], + belongsToFieldOnRelatedModel: 'student', + canUnlinkAssociatedModel: false, + relatedJoinFieldName: 'teacher', + relatedJoinTableName: 'StudentTeacher', + }); + + expect(genericSchema.models.Teacher.fields.students.relationship).toStrictEqual({ + type: 'HAS_MANY', + relatedModelName: 'Student', + belongsToFieldOnRelatedModel: 'teacher', + relatedModelFields: ['teacher'], + canUnlinkAssociatedModel: false, + relatedJoinFieldName: 'student', + relatedJoinTableName: 'StudentTeacher', + }); + + expect(genericSchema.models.Lock.fields.Key.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Key', + associatedFields: ['lockKeyId'], + }); + + expect(genericSchema.models.Lock.fields.lockKeyId.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Key', + }); + + expect(genericSchema.models.Key.fields.Lock.relationship).toStrictEqual({ + type: 'BELONGS_TO', + relatedModelName: 'Lock', + associatedFields: ['keyLockId'], + }); + + expect(genericSchema.models.Owner.fields.Dog.relationship).toStrictEqual({ + type: 'HAS_MANY', + relatedModelName: 'Dog', + relatedModelFields: ['ownerID'], + canUnlinkAssociatedModel: true, + relatedJoinFieldName: undefined, + relatedJoinTableName: undefined, + }); + + expect(genericSchema.models.Dog.fields.ownerID.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Owner', + isHasManyIndex: true, + }); + }); + + it('should map v2 relationships', () => { + const genericSchema = getGenericFromDataStore(schemaWithRelationshipsV2); + + expect(genericSchema.models.PrimaryCareGiver.fields.Child.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Child', + associatedFields: ['primaryCareGiverChildId'], + }); + + expect(genericSchema.models.PrimaryCareGiver.fields.primaryCareGiverChildId.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Child', + }); + + expect(genericSchema.models.Student.fields.Teachers.relationship).toStrictEqual({ + type: 'HAS_MANY', + relatedModelName: 'Teacher', + relatedModelFields: ['student'], + belongsToFieldOnRelatedModel: 'student', + canUnlinkAssociatedModel: false, + relatedJoinFieldName: 'teacher', + relatedJoinTableName: 'StudentTeacher', + }); + + expect(genericSchema.models.Teacher.fields.students.relationship).toStrictEqual({ + type: 'HAS_MANY', + relatedModelName: 'Student', + belongsToFieldOnRelatedModel: 'teacher', + relatedModelFields: ['teacher'], + canUnlinkAssociatedModel: false, + relatedJoinFieldName: 'student', + relatedJoinTableName: 'StudentTeacher', + }); + + expect(genericSchema.models.Lock.fields.Key.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Key', + associatedFields: ['lockKeyId'], + }); + + expect(genericSchema.models.Lock.fields.lockKeyId.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Key', + }); + + expect(genericSchema.models.Key.fields.Lock.relationship).toStrictEqual({ + type: 'BELONGS_TO', + relatedModelName: 'Lock', + associatedFields: ['keyLockId'], + }); + + expect(genericSchema.models.Owner.fields.Dog.relationship).toStrictEqual({ + type: 'HAS_MANY', + relatedModelName: 'Dog', + relatedModelFields: ['ownerID'], + canUnlinkAssociatedModel: true, + relatedJoinFieldName: undefined, + relatedJoinTableName: undefined, + }); + + expect(genericSchema.models.Dog.fields.ownerID.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Owner', + isHasManyIndex: true, + }); + }); + + it('should map enums', () => { + const genericSchema = getGenericFromDataStore(schemaWithEnums); + + expect(genericSchema.enums).toStrictEqual(schemaWithEnums.enums); + }); + + it('should map nonModels', () => { + const genericSchema = getGenericFromDataStore(schemaWithNonModels); + expect(genericSchema.nonModels).toStrictEqual({ + Reactions: { + fields: { + ball: { dataType: 'String', required: false, readOnly: false, isArray: false }, + fireworks: { dataType: 'String', required: false, readOnly: false, isArray: false }, + }, + }, + Misc: { fields: { quotes: { dataType: 'String', required: false, readOnly: false, isArray: true } } }, + }); + }); + + it('should handle schema with assumed associated fields and models', () => { + const genericSchema = getGenericFromDataStore(schemaWithAssumptions); + const userFields = genericSchema.models.User.fields; + + expect(userFields.friends.relationship).toStrictEqual({ + type: 'HAS_MANY', + relatedModelName: 'Friend', + relatedModelFields: ['friendId'], + canUnlinkAssociatedModel: true, + relatedJoinFieldName: undefined, + relatedJoinTableName: undefined, + }); + + expect(userFields.posts.relationship).toStrictEqual({ + type: 'HAS_MANY', + relatedModelName: 'Post', + relatedModelFields: ['userPostsId'], + canUnlinkAssociatedModel: true, + relatedJoinFieldName: undefined, + relatedJoinTableName: undefined, + }); + }); + + it('should correctly identify join tables', () => { + const genericSchemaWithJoinTable = getGenericFromDataStore(schemaWithRelationships); + const joinTables1 = Object.entries(genericSchemaWithJoinTable.models) + .filter(([, model]) => model.isJoinTable) + .map(([name]) => name); + expect(joinTables1).toStrictEqual(['StudentTeacher']); + + const genericSchemaWithoutJoinTable = getGenericFromDataStore(schemaWithoutJoinTables); + const joinTables2 = Object.entries(genericSchemaWithoutJoinTable.models) + .filter(([, model]) => model.isJoinTable) + .map(([name]) => name); + expect(joinTables2).toHaveLength(0); + }); + + it('should correctly identify primary keys', () => { + const genericSchema = getGenericFromDataStore(schemaWithCPK); + const { models } = genericSchema; + expect(models.CPKStudent.primaryKeys).toStrictEqual(['specialStudentId']); + expect(models.CPKTeacher.primaryKeys).toStrictEqual(['specialTeacherId']); + }); + + it('should correctly map model with composite keys', () => { + const genericSchema = getGenericFromDataStore(schemaWithCompositeKeys); + const { CompositeDog } = genericSchema.models; + expect(CompositeDog.primaryKeys).toStrictEqual(['name', 'description']); + expect(CompositeDog.fields.CompositeBowl.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'CompositeBowl', + associatedFields: ['compositeDogCompositeBowlShape', 'compositeDogCompositeBowlSize'], + }); + expect(CompositeDog.fields.CompositeOwner.relationship).toStrictEqual({ + type: 'BELONGS_TO', + relatedModelName: 'CompositeOwner', + associatedFields: ['compositeDogCompositeOwnerLastName', 'compositeDogCompositeOwnerFirstName'], + }); + }); + + it('should correctly map schema with hasMany-belongsTo', () => { + const genericSchema = getGenericFromDataStore(schemaWithHasManyBelongsTo); + const { User, Org, Post, Comment } = genericSchema.models; + + expect(User.fields.comments.relationship).toStrictEqual({ + type: 'HAS_MANY', + canUnlinkAssociatedModel: true, + relatedModelName: 'Comment', + relatedModelFields: ['userCommentsId'], + belongsToFieldOnRelatedModel: 'User', + relatedJoinFieldName: undefined, + relatedJoinTableName: undefined, + }); + + expect(Post.fields.comments.relationship).toStrictEqual({ + type: 'HAS_MANY', + canUnlinkAssociatedModel: true, + relatedModelName: 'Comment', + relatedModelFields: ['postCommentsId'], + belongsToFieldOnRelatedModel: 'post', + relatedJoinFieldName: undefined, + relatedJoinTableName: undefined, + }); + + expect(Org.fields.comments.relationship).toStrictEqual({ + type: 'HAS_MANY', + canUnlinkAssociatedModel: false, + relatedModelName: 'Comment', + relatedModelFields: ['orgCommentsId'], + belongsToFieldOnRelatedModel: 'Org', + relatedJoinFieldName: undefined, + relatedJoinTableName: undefined, + }); + + expect(Comment.fields.postID.relationship).toStrictEqual({ + type: 'BELONGS_TO', + relatedModelName: 'Post', + }); + + expect(Comment.fields.userCommentsId.relationship).toStrictEqual({ + type: 'BELONGS_TO', + relatedModelName: 'User', + isHasManyIndex: true, + }); + + expect(Comment.fields.orgCommentsId.relationship).toStrictEqual({ + type: 'BELONGS_TO', + relatedModelName: 'Org', + isHasManyIndex: true, + }); + + expect(Comment.fields.postCommentsId.relationship).toStrictEqual({ + type: 'HAS_ONE', + relatedModelName: 'Post', + isHasManyIndex: true, + }); + }); + + it('should produce the same generic schema from MIPR and introspection schema', () => { + expect(getGenericFromDataStore(introspectionSchemaWithCompositeKeys).models).toStrictEqual( + getGenericFromDataStore(schemaWithCompositeKeys).models, + ); + }); + + it('should handle bidirectional hasMany with defined field', () => { + const { Car, Dealership } = getGenericFromDataStore(schemaWithBiDirectionalHasManyWithDefinedField).models; + expect(Car.fields.dealership.relationship).toStrictEqual({ + type: 'BELONGS_TO', + relatedModelName: 'Dealership', + associatedFields: ['dealershipId'], + }); + + expect(Dealership.fields.cars.relationship).toStrictEqual({ + type: 'HAS_MANY', + canUnlinkAssociatedModel: true, + relatedModelName: 'Car', + relatedModelFields: [], + belongsToFieldOnRelatedModel: 'dealership', + relatedJoinFieldName: undefined, + relatedJoinTableName: undefined, + }); + }); +}); diff --git a/packages/amplify-util-uibuilder/src/__tests__/mock-schemas.ts b/packages/amplify-util-uibuilder/src/__tests__/mock-schemas.ts new file mode 100644 index 00000000000..3ac63972467 --- /dev/null +++ b/packages/amplify-util-uibuilder/src/__tests__/mock-schemas.ts @@ -0,0 +1,3749 @@ +import type { Schema as DataStoreSchema } from '@aws-amplify/datastore'; +import type { ModelIntrospectionSchema } from '@aws-amplify/appsync-modelgen-plugin'; + +export const postSchema: DataStoreSchema = { + models: { + Post: { + name: 'Post', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + caption: { + name: 'caption', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + username: { + name: 'username', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + post_url: { + name: 'post_url', + isArray: false, + type: 'AWSURL', + isRequired: false, + attributes: [], + }, + profile_url: { + name: 'profile_url', + isArray: false, + type: 'AWSURL', + isRequired: false, + attributes: [], + }, + status: { + name: 'status', + isArray: false, + type: { + enum: 'PostStatus', + }, + isRequired: false, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Posts', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'private', + provider: 'iam', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + }, + enums: { + PostStatus: { + name: 'PostStatus', + values: ['PENDING', 'POSTED', 'IN_REVIEW'], + }, + }, + nonModels: {}, + version: '000000', + codegenVersion: '000000', +}; + +export const schemaWithRelationships: DataStoreSchema = { + models: { + PrimaryCareGiver: { + name: 'PrimaryCareGiver', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Child: { + name: 'Child', + isArray: false, + type: { + model: 'Child', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: 'id', + targetName: 'primaryCareGiverChildId', + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + primaryCareGiverChildId: { + name: 'primaryCareGiverChildId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'PrimaryCareGivers', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Child: { + name: 'Child', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Children', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Student: { + name: 'Student', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Teachers: { + name: 'Teachers', + isArray: true, + type: { + model: 'StudentTeacher', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: 'student', + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Students', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Teacher: { + name: 'Teacher', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + students: { + name: 'students', + isArray: true, + type: { + model: 'StudentTeacher', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: 'teacher', + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Teachers', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Lock: { + name: 'Lock', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + Key: { + name: 'Key', + isArray: false, + type: { + model: 'Key', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: 'Lock', + targetName: 'lockKeyId', + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + lockKeyId: { + name: 'lockKeyId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'Locks', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Key: { + name: 'Key', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Lock: { + name: 'Lock', + isArray: false, + type: { + model: 'Lock', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetName: 'keyLockId', + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Keys', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Owner: { + name: 'Owner', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Dog: { + name: 'Dog', + isArray: true, + type: { + model: 'Dog', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: 'ownerID', + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Owners', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Dog: { + name: 'Dog', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + ownerID: { + name: 'ownerID', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Dogs', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byOwner', + fields: ['ownerID'], + }, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + StudentTeacher: { + name: 'StudentTeacher', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + student: { + name: 'student', + isArray: false, + type: { + model: 'Student', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetName: 'studentID', + }, + }, + teacher: { + name: 'teacher', + isArray: false, + type: { + model: 'Teacher', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetName: 'teacherID', + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'StudentTeachers', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byStudent', + fields: ['studentID'], + }, + }, + { + type: 'key', + properties: { + name: 'byTeacher', + fields: ['teacherID'], + }, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + version: '3ea7de9ef8e765b48c0a53e3e45735a3', + codegenVersion: '000000', +}; + +export const schemaWithEnums: DataStoreSchema = { + models: {}, + enums: { + City: { + name: 'City', + values: ['SAN_FRANCISCO', 'NEW_YORK'], + }, + }, + nonModels: {}, + version: '3ea7de9ef8e765b48c0a53e3e45735a3', + codegenVersion: '000000', +}; + +export const schemaWithNonModels: DataStoreSchema = { + models: {}, + enums: {}, + nonModels: { + Reactions: { + name: 'Reactions', + fields: { + ball: { + name: 'ball', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + fireworks: { + name: 'fireworks', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + }, + Misc: { + name: 'Misc', + fields: { + quotes: { + name: 'quotes', + isArray: true, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + }, + }, + version: '38a1a46479c6cd75d21439d7f3122c1d', + codegenVersion: '000000', +}; + +export const schemaWithRelationshipsV2: any = { + models: { + PrimaryCareGiver: { + name: 'PrimaryCareGiver', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Child: { + name: 'Child', + isArray: false, + type: { + model: 'Child', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: ['id'], + targetNames: ['primaryCareGiverChildId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + primaryCareGiverChildId: { + name: 'primaryCareGiverChildId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'PrimaryCareGivers', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Child: { + name: 'Child', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Children', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Student: { + name: 'Student', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Teachers: { + name: 'Teachers', + isArray: true, + type: { + model: 'StudentTeacher', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['student'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Students', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Teacher: { + name: 'Teacher', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + students: { + name: 'students', + isArray: true, + type: { + model: 'StudentTeacher', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['teacher'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Teachers', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Lock: { + name: 'Lock', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + Key: { + name: 'Key', + isArray: false, + type: { + model: 'Key', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: ['Lock'], + targetNames: ['lockKeyId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + lockKeyId: { + name: 'lockKeyId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'Locks', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Key: { + name: 'Key', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Lock: { + name: 'Lock', + isArray: false, + type: { + model: 'Lock', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['keyLockId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Keys', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Owner: { + name: 'Owner', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Dog: { + name: 'Dog', + isArray: true, + type: { + model: 'Dog', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['ownerID'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Owners', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + Dog: { + name: 'Dog', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + ownerID: { + name: 'ownerID', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Dogs', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byOwner', + fields: ['ownerID'], + }, + }, + { + type: 'auth', + properties: { + rules: [ + { + allow: 'public', + operations: ['create', 'update', 'delete', 'read'], + }, + ], + }, + }, + ], + }, + StudentTeacher: { + name: 'StudentTeacher', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + student: { + name: 'student', + isArray: false, + type: { + model: 'Student', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['studentID'], + }, + }, + teacher: { + name: 'teacher', + isArray: false, + type: { + model: 'Teacher', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['teacherID'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'StudentTeachers', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byStudent', + fields: ['studentID'], + }, + }, + { + type: 'key', + properties: { + name: 'byTeacher', + fields: ['teacherID'], + }, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + version: '3ea7de9ef8e765b48c0a53e3e45735a3', + codegenVersion: '000000', +}; + +export const schemaWithAssumptions: DataStoreSchema = { + models: { + User: { + name: 'User', + fields: { + friends: { + name: 'friends', + isArray: true, + type: { + model: 'Friend', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: 'friendId', + }, + }, + posts: { + name: 'posts', + isArray: true, + type: { + model: 'Post', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: 'userPostsId', + }, + }, + badges: { + name: 'badges', + isArray: true, + type: 'String', + isRequired: false, + attributes: [], + isArrayNullable: true, + }, + }, + syncable: true, + pluralName: 'Users', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['id'], + }, + }, + ], + }, + Event: { + name: 'Post', + fields: { + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'Posts', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['id'], + }, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + version: 'version', + codegenVersion: '000000', +}; + +/** + type Student @model { + specialStudentId: ID! @primaryKey(sortKeyFields: ["grade", "age"]) + grade: Int! + age: Int! + } + + type Teacher @model { + specialTeacherId: ID! @primaryKey + Student: Student @hasOne + } + + type Dog @model { + id: ID! + name: String + } + */ + +export const schemaWithCPK: DataStoreSchema = { + models: { + CPKStudent: { + name: 'CPKStudent', + fields: { + specialStudentId: { + name: 'specialStudentId', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CPKStudents', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['specialStudentId'], + }, + }, + ], + }, + CPKTeacher: { + name: 'CPKTeacher', + fields: { + specialTeacherId: { + name: 'specialTeacherId', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + CPKStudent: { + name: 'CPKStudent', + isArray: false, + type: { + model: 'CPKStudent', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: ['specialStudentId'], + targetNames: ['cPKTeacherCPKStudentSpecialStudentId'], + }, + }, + CPKClasses: { + name: 'CPKClasses', + isArray: true, + type: { + model: 'CPKTeacherCPKClass', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['cpkTeacher'], + }, + }, + CPKProjects: { + name: 'CPKProjects', + isArray: true, + type: { + model: 'CPKProject', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['cPKTeacherID'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + cPKTeacherCPKStudentSpecialStudentId: { + name: 'cPKTeacherCPKStudentSpecialStudentId', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + }, + syncable: true, + pluralName: 'CPKTeachers', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['specialTeacherId'], + }, + }, + ], + }, + CPKClass: { + name: 'CPKClass', + fields: { + specialClassId: { + name: 'specialClassId', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + CPKTeachers: { + name: 'CPKTeachers', + isArray: true, + type: { + model: 'CPKTeacherCPKClass', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['cpkClass'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CPKClasses', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['specialClassId'], + }, + }, + ], + }, + CPKProject: { + name: 'CPKProject', + fields: { + specialProjectId: { + name: 'specialProjectId', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + cPKTeacherID: { + name: 'cPKTeacherID', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CPKProjects', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['specialProjectId'], + }, + }, + { + type: 'key', + properties: { + name: 'byCPKTeacher', + fields: ['cPKTeacherID'], + }, + }, + ], + }, + CPKTeacherCPKClass: { + name: 'CPKTeacherCPKClass', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + cPKTeacherSpecialTeacherId: { + name: 'cPKTeacherSpecialTeacherId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + cPKClassSpecialClassId: { + name: 'cPKClassSpecialClassId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + cpkTeacher: { + name: 'cpkTeacher', + isArray: false, + type: { + model: 'CPKTeacher', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['cPKTeacherSpecialTeacherId'], + }, + }, + cpkClass: { + name: 'cpkClass', + isArray: false, + type: { + model: 'CPKClass', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['cPKClassSpecialClassId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CPKTeacherCPKClasses', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byCPKTeacher', + fields: ['cPKTeacherSpecialTeacherId'], + }, + }, + { + type: 'key', + properties: { + name: 'byCPKClass', + fields: ['cPKClassSpecialClassId'], + }, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + codegenVersion: '3.3.5', + version: '19f0d1f134e00e6d1829446b37439661', +}; + +export const schemaWithCompositeKeys: DataStoreSchema = { + models: { + CompositeDog: { + name: 'CompositeDog', + fields: { + name: { + name: 'name', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + description: { + name: 'description', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + CompositeBowl: { + name: 'CompositeBowl', + isArray: false, + type: { + model: 'CompositeBowl', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: ['shape', 'size'], + targetNames: ['compositeDogCompositeBowlShape', 'compositeDogCompositeBowlSize'], + }, + }, + CompositeOwner: { + name: 'CompositeOwner', + isArray: false, + type: { + model: 'CompositeOwner', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['compositeDogCompositeOwnerLastName', 'compositeDogCompositeOwnerFirstName'], + }, + }, + CompositeToys: { + name: 'CompositeToys', + isArray: true, + type: { + model: 'CompositeToy', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['compositeDogCompositeToysName', 'compositeDogCompositeToysDescription'], + }, + }, + CompositeVets: { + name: 'CompositeVets', + isArray: true, + type: { + model: 'CompositeDogCompositeVet', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['compositeDog'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + compositeDogCompositeBowlShape: { + name: 'compositeDogCompositeBowlShape', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeDogCompositeBowlSize: { + name: 'compositeDogCompositeBowlSize', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + compositeDogCompositeOwnerLastName: { + name: 'compositeDogCompositeOwnerLastName', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeDogCompositeOwnerFirstName: { + name: 'compositeDogCompositeOwnerFirstName', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'CompositeDogs', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['name', 'description'], + }, + }, + ], + }, + CompositeBowl: { + name: 'CompositeBowl', + fields: { + shape: { + name: 'shape', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + size: { + name: 'size', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CompositeBowls', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['shape', 'size'], + }, + }, + ], + }, + CompositeOwner: { + name: 'CompositeOwner', + fields: { + lastName: { + name: 'lastName', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + firstName: { + name: 'firstName', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + CompositeDog: { + name: 'CompositeDog', + isArray: false, + type: { + model: 'CompositeDog', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: ['name', 'description'], + targetNames: ['compositeOwnerCompositeDogName', 'compositeOwnerCompositeDogDescription'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + compositeOwnerCompositeDogName: { + name: 'compositeOwnerCompositeDogName', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeOwnerCompositeDogDescription: { + name: 'compositeOwnerCompositeDogDescription', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'CompositeOwners', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['lastName', 'firstName'], + }, + }, + ], + }, + CompositeToy: { + name: 'CompositeToy', + fields: { + kind: { + name: 'kind', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + color: { + name: 'color', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + compositeDogCompositeToysName: { + name: 'compositeDogCompositeToysName', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeDogCompositeToysDescription: { + name: 'compositeDogCompositeToysDescription', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'CompositeToys', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['kind', 'color'], + }, + }, + { + type: 'key', + properties: { + name: 'gsi-CompositeDog.CompositeToys', + fields: ['compositeDogCompositeToysName', 'compositeDogCompositeToysDescription'], + }, + }, + ], + }, + CompositeVet: { + name: 'CompositeVet', + fields: { + specialty: { + name: 'specialty', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + city: { + name: 'city', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + CompositeDogs: { + name: 'CompositeDogs', + isArray: true, + type: { + model: 'CompositeDogCompositeVet', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['compositeVet'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CompositeVets', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['specialty', 'city'], + }, + }, + ], + }, + CompositeDogCompositeVet: { + name: 'CompositeDogCompositeVet', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + compositeDogName: { + name: 'compositeDogName', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeDogdescription: { + name: 'compositeDogdescription', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + compositeVetSpecialty: { + name: 'compositeVetSpecialty', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeVetcity: { + name: 'compositeVetcity', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + compositeDog: { + name: 'compositeDog', + isArray: false, + type: { + model: 'CompositeDog', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['compositeDogName', 'compositeDogdescription'], + }, + }, + compositeVet: { + name: 'compositeVet', + isArray: false, + type: { + model: 'CompositeVet', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['compositeVetSpecialty', 'compositeVetcity'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CompositeDogCompositeVets', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byCompositeDog', + fields: ['compositeDogName', 'compositeDogdescription'], + }, + }, + { + type: 'key', + properties: { + name: 'byCompositeVet', + fields: ['compositeVetSpecialty', 'compositeVetcity'], + }, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + codegenVersion: '3.3.5', + version: '8f8e59ee8fb2e3ca4efda3aa25b0211f', +}; + +export const introspectionSchemaWithCompositeKeys = { + version: 1, + models: { + CompositeDog: { + name: 'CompositeDog', + fields: { + name: { + name: 'name', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + description: { + name: 'description', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + CompositeBowl: { + name: 'CompositeBowl', + isArray: false, + type: { + model: 'CompositeBowl', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: ['shape', 'size'], + targetNames: ['compositeDogCompositeBowlShape', 'compositeDogCompositeBowlSize'], + }, + }, + CompositeOwner: { + name: 'CompositeOwner', + isArray: false, + type: { + model: 'CompositeOwner', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['compositeDogCompositeOwnerLastName', 'compositeDogCompositeOwnerFirstName'], + }, + }, + CompositeToys: { + name: 'CompositeToys', + isArray: true, + type: { + model: 'CompositeToy', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['compositeDogCompositeToysName', 'compositeDogCompositeToysDescription'], + }, + }, + CompositeVets: { + name: 'CompositeVets', + isArray: true, + type: { + model: 'CompositeDogCompositeVet', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['compositeDog'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + compositeDogCompositeBowlShape: { + name: 'compositeDogCompositeBowlShape', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeDogCompositeBowlSize: { + name: 'compositeDogCompositeBowlSize', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + compositeDogCompositeOwnerLastName: { + name: 'compositeDogCompositeOwnerLastName', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeDogCompositeOwnerFirstName: { + name: 'compositeDogCompositeOwnerFirstName', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'CompositeDogs', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['name', 'description'], + }, + }, + ], + primaryKeyInfo: { + isCustomPrimaryKey: true, + primaryKeyFieldName: 'name', + sortKeyFieldNames: ['description'], + }, + }, + CompositeBowl: { + name: 'CompositeBowl', + fields: { + shape: { + name: 'shape', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + size: { + name: 'size', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CompositeBowls', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['shape', 'size'], + }, + }, + ], + primaryKeyInfo: { + isCustomPrimaryKey: true, + primaryKeyFieldName: 'shape', + sortKeyFieldNames: ['size'], + }, + }, + CompositeOwner: { + name: 'CompositeOwner', + fields: { + lastName: { + name: 'lastName', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + firstName: { + name: 'firstName', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + CompositeDog: { + name: 'CompositeDog', + isArray: false, + type: { + model: 'CompositeDog', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: ['name', 'description'], + targetNames: ['compositeOwnerCompositeDogName', 'compositeOwnerCompositeDogDescription'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + compositeOwnerCompositeDogName: { + name: 'compositeOwnerCompositeDogName', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeOwnerCompositeDogDescription: { + name: 'compositeOwnerCompositeDogDescription', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'CompositeOwners', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['lastName', 'firstName'], + }, + }, + ], + primaryKeyInfo: { + isCustomPrimaryKey: true, + primaryKeyFieldName: 'lastName', + sortKeyFieldNames: ['firstName'], + }, + }, + CompositeToy: { + name: 'CompositeToy', + fields: { + kind: { + name: 'kind', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + color: { + name: 'color', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + compositeDogCompositeToysName: { + name: 'compositeDogCompositeToysName', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeDogCompositeToysDescription: { + name: 'compositeDogCompositeToysDescription', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'CompositeToys', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['kind', 'color'], + }, + }, + { + type: 'key', + properties: { + name: 'gsi-CompositeDog.CompositeToys', + fields: ['compositeDogCompositeToysName', 'compositeDogCompositeToysDescription'], + }, + }, + ], + primaryKeyInfo: { + isCustomPrimaryKey: true, + primaryKeyFieldName: 'kind', + sortKeyFieldNames: ['color'], + }, + }, + CompositeVet: { + name: 'CompositeVet', + fields: { + specialty: { + name: 'specialty', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + city: { + name: 'city', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + CompositeDogs: { + name: 'CompositeDogs', + isArray: true, + type: { + model: 'CompositeDogCompositeVet', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['compositeVet'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CompositeVets', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['specialty', 'city'], + }, + }, + ], + primaryKeyInfo: { + isCustomPrimaryKey: true, + primaryKeyFieldName: 'specialty', + sortKeyFieldNames: ['city'], + }, + }, + CompositeDogCompositeVet: { + name: 'CompositeDogCompositeVet', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + compositeDogName: { + name: 'compositeDogName', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeDogdescription: { + name: 'compositeDogdescription', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + compositeVetSpecialty: { + name: 'compositeVetSpecialty', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + compositeVetcity: { + name: 'compositeVetcity', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + compositeDog: { + name: 'compositeDog', + isArray: false, + type: { + model: 'CompositeDog', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['compositeDogName', 'compositeDogdescription'], + }, + }, + compositeVet: { + name: 'compositeVet', + isArray: false, + type: { + model: 'CompositeVet', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['compositeVetSpecialty', 'compositeVetcity'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'CompositeDogCompositeVets', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byCompositeDog', + fields: ['compositeDogName', 'compositeDogdescription'], + }, + }, + { + type: 'key', + properties: { + name: 'byCompositeVet', + fields: ['compositeVetSpecialty', 'compositeVetcity'], + }, + }, + ], + primaryKeyInfo: { + isCustomPrimaryKey: false, + primaryKeyFieldName: 'id', + sortKeyFieldNames: [], + }, + }, + }, + enums: {}, + nonModels: {}, +} as ModelIntrospectionSchema; // typecasting because connection types are enums + +/** + type User @model { + name: String + comments: [Comment] @hasMany + } + + type Org @model { + id: ID! + name: String + comments: [Comment] @hasMany + } + + type Post @model { + id: ID! + name: String + comments: [Comment] @hasMany + } + + type Comment @model { + id: ID! + name: String! + postID: ID + post: Post @belongsTo(fields: ["postID"]) + User: User @belongsTo + Org: Org! @belongsTo + } + */ +export const schemaWithHasManyBelongsTo: DataStoreSchema = { + models: { + User: { + name: 'User', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + comments: { + name: 'comments', + isArray: true, + type: { + model: 'Comment', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['userCommentsId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Users', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + Comment: { + name: 'Comment', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + postID: { + name: 'postID', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + post: { + name: 'post', + isArray: false, + type: { + model: 'Post', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['postID'], + }, + }, + User: { + name: 'User', + isArray: false, + type: { + model: 'User', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['userCommentsId'], + }, + }, + Org: { + name: 'Org', + isArray: false, + type: { + model: 'Org', + }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['orgCommentsId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + userCommentsId: { + name: 'userCommentsId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + orgCommentsId: { + name: 'orgCommentsId', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + postCommentsId: { + name: 'postCommentsId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'Comments', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + Post: { + name: 'Post', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + comments: { + name: 'comments', + isArray: true, + type: { + model: 'Comment', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['postCommentsId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Posts', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + Org: { + name: 'Org', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + comments: { + name: 'comments', + isArray: true, + type: { + model: 'Comment', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['orgCommentsId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Orgs', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + codegenVersion: '3.3.5', + version: 'f2f8e885f81740e5be20b201c850fa05', +}; + +/** + type Box @model { + id: ID! + name: String + crateID: ID! @index(name: "byCrate") + Crate: Crate @belongsTo(fields: ["crateID"]) + } + + type Crate @model { + id: ID! + destination: String + Boxes: [Box] @hasMany(indexName: "byCrate", fields: ["id"]) + } + + type User @model { + id: ID! + Entries: [Entry] @hasMany(indexName: "byUser", fields: ["id"]) + Images: [Image] @hasMany(indexName: "byUser", fields: ["id"]) + } + + type Entry @model { + id: ID! + userID: ID! @index(name: "byUser") + User: User @belongsTo(fields: ["userID"]) + Images: [Image] @hasMany(indexName: "byEntry", fields: ["id"]) + } + + type Image @model { + id: ID! + userID: ID! @index(name: "byUser") + entryID: ID! @index(name: "byEntry") + User: User @belongsTo(fields: ["userID"]) + Entry: Entry @belongsTo(fields: ["entryID"]) + } + */ +export const schemaWithoutJoinTables: DataStoreSchema = { + models: { + User: { + name: 'User', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + Entries: { + name: 'Entries', + isArray: true, + type: { + model: 'Entry', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['User'], + }, + }, + Images: { + name: 'Images', + isArray: true, + type: { + model: 'Image', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['User'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Users', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + Entry: { + name: 'Entry', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + userID: { + name: 'userID', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + User: { + name: 'User', + isArray: false, + type: { + model: 'User', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['userID'], + }, + }, + Images: { + name: 'Images', + isArray: true, + type: { + model: 'Image', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['Entry'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Entries', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byUser', + fields: ['userID'], + }, + }, + ], + }, + Image: { + name: 'Image', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + userID: { + name: 'userID', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + entryID: { + name: 'entryID', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + User: { + name: 'User', + isArray: false, + type: { + model: 'User', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['userID'], + }, + }, + Entry: { + name: 'Entry', + isArray: false, + type: { + model: 'Entry', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['entryID'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Images', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byUser', + fields: ['userID'], + }, + }, + { + type: 'key', + properties: { + name: 'byEntry', + fields: ['entryID'], + }, + }, + ], + }, + Box: { + name: 'Box', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + crateID: { + name: 'crateID', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + Crate: { + name: 'Crate', + isArray: false, + type: { + model: 'Crate', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['crateID'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Boxes', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byCrate', + fields: ['crateID'], + }, + }, + ], + }, + Crate: { + name: 'Crate', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + destination: { + name: 'destination', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + Boxes: { + name: 'Boxes', + isArray: true, + type: { + model: 'Box', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['Crate'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Crates', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + codegenVersion: '3.3.5', + version: '925d97d5ee6e402764bce3a9c0e546c1', +}; + +/** + type Dealership @model { + id: ID! + name: String! + cars: [Car] @hasMany(fields: ["id"]) + } + + + type Car @model { + id: ID! + name: String! + dealershipId: ID + dealership: Dealership @belongsTo(fields: ["dealershipId"]) + } + */ + +export const schemaWithBiDirectionalHasManyWithDefinedField: DataStoreSchema = { + models: { + Dealership: { + name: 'Dealership', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + cars: { + name: 'cars', + isArray: true, + type: { + model: 'Car', + }, + isRequired: false, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: ['dealership'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Dealerships', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + Car: { + name: 'Car', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + dealershipId: { + name: 'dealershipId', + isArray: false, + type: 'ID', + isRequired: false, + attributes: [], + }, + dealership: { + name: 'dealership', + isArray: false, + type: { + model: 'Dealership', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetNames: ['dealershipId'], + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Cars', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + codegenVersion: '3.3.5', + version: '832519d29b9b70a1444d1c99127dbd59', +}; diff --git a/packages/amplify-util-uibuilder/src/__tests__/syncAmplifyUiComponents.test.ts b/packages/amplify-util-uibuilder/src/__tests__/syncAmplifyUiComponents.test.ts index 0b65aa5fd9e..df5762cb95c 100644 --- a/packages/amplify-util-uibuilder/src/__tests__/syncAmplifyUiComponents.test.ts +++ b/packages/amplify-util-uibuilder/src/__tests__/syncAmplifyUiComponents.test.ts @@ -11,7 +11,7 @@ import { } from '../commands/utils'; import { AmplifyStudioClient } from '../clients'; import { isDataStoreEnabled } from '@aws-amplify/amplify-category-api'; -import type { GenericDataSchema } from '@aws-amplify/codegen-ui'; +import type { GenericDataSchema } from '../commands/utils/data-types'; import fetch, { Response } from 'node-fetch'; import { existsSync, writeFileSync } from 'fs'; diff --git a/packages/amplify-util-uibuilder/src/__tests__/utils.ts b/packages/amplify-util-uibuilder/src/__tests__/utils.ts index c9bf04dc3e7..82b9c8de33f 100644 --- a/packages/amplify-util-uibuilder/src/__tests__/utils.ts +++ b/packages/amplify-util-uibuilder/src/__tests__/utils.ts @@ -1,4 +1,4 @@ -import type { GenericDataSchema } from '@aws-amplify/codegen-ui'; +import type { GenericDataSchema } from '../commands/utils/data-types'; export const exampleSchema: GenericDataSchema = { dataSourceType: 'DataStore', diff --git a/packages/amplify-util-uibuilder/src/commands/generateComponents.ts b/packages/amplify-util-uibuilder/src/commands/generateComponents.ts index 64bbcca6e50..54092777601 100644 --- a/packages/amplify-util-uibuilder/src/commands/generateComponents.ts +++ b/packages/amplify-util-uibuilder/src/commands/generateComponents.ts @@ -34,8 +34,9 @@ export const run = async (context: $TSContext, eventType: 'PostPush' | 'PostPull studioClient.listForms(), studioClient.isGraphQLSupported ? getAmplifyDataSchema(context) : Promise.resolve(undefined), ]); - - const canGenerateDataComponents = dataSchema && studioClient.isGraphQLSupported; + const genericDataSchema = dataSchema ? mapGenericDataSchemaToCodegen(dataSchema) : undefined; + + const canGenerateDataComponents = genericDataSchema && studioClient.isGraphQLSupported; const apiConfiguration: AmplifyUIBuilder.ApiConfiguration = canGenerateDataComponents ? getApiConfiguration(studioClient, context) @@ -49,8 +50,6 @@ export const run = async (context: $TSContext, eventType: 'PostPush' | 'PostPull } spinner.start('Generating UI components...'); - const genericDataSchema = dataSchema ? mapGenericDataSchemaToCodegen(dataSchema) : undefined; - const job: AmplifyUIBuilder.StartCodegenJobData = { renderConfig: { react: { @@ -79,10 +78,10 @@ export const run = async (context: $TSContext, eventType: 'PostPush' | 'PostPull const detachedForms: { id: string; name: string }[] = []; const failedResponseNames: string[] = []; - const modelNames = dataSchema?.models ? new Set(Object.keys(dataSchema.models)) : new Set(); + const modelNames = genericDataSchema?.models ? new Set(Object.keys(genericDataSchema.models)) : new Set(); const hasStorageManagerField = formSchemas.entities.some((formSchema) => hasStorageField(formSchema)); - if (dataSchema && eventType === 'PostPush') { + if (genericDataSchema && eventType === 'PostPush') { formSchemas.entities.forEach((formSchema) => { isFormDetachedFromModel(formSchema, modelNames) && detachedForms.push({ id: formSchema.id, name: formSchema.name }); }); diff --git a/packages/amplify-util-uibuilder/src/commands/utils/codegen-ui-dependency-provider.ts b/packages/amplify-util-uibuilder/src/commands/utils/codegen-ui-dependency-provider.ts new file mode 100644 index 00000000000..57cf5d28e20 --- /dev/null +++ b/packages/amplify-util-uibuilder/src/commands/utils/codegen-ui-dependency-provider.ts @@ -0,0 +1,39 @@ +export type RequiredDependency = { + dependencyName: string; + reason: string; +}; + +export abstract class RequiredDependencyProvider { + abstract getRequiredDependencies(hasStorageManager?: boolean): DependencyType[]; +} + +type SemVerRequiredDependency = RequiredDependency & { + supportedSemVerPattern: string; +}; + +export class ReactRequiredDependencyProvider extends RequiredDependencyProvider { + getRequiredDependencies(hasStorageManager?: boolean): SemVerRequiredDependency[] { + const dependencies = [ + { + dependencyName: '@aws-amplify/ui-react', + supportedSemVerPattern: '^4.6.0', + reason: 'Required to leverage Amplify UI primitives, and Amplify Studio component helper functions.', + }, + { + dependencyName: 'aws-amplify', + supportedSemVerPattern: '^5.0.2', + reason: 'Required to leverage DataStore.', + }, + ]; + + if (hasStorageManager) { + dependencies.push({ + dependencyName: '@aws-amplify/ui-react-storage', + supportedSemVerPattern: '^1.1.0', + reason: 'Required to leverage StorageManager.', + }); + } + + return dependencies; + } +} diff --git a/packages/amplify-util-uibuilder/src/commands/utils/codegen-ui.ts b/packages/amplify-util-uibuilder/src/commands/utils/codegen-ui.ts new file mode 100644 index 00000000000..b12c6409367 --- /dev/null +++ b/packages/amplify-util-uibuilder/src/commands/utils/codegen-ui.ts @@ -0,0 +1,344 @@ +import type { + ModelIntrospectionSchema, + SchemaModel as IntrospectionModel, + Field as IntrospectionModelField, + SchemaNonModel as IntrospectionNonModel, +} from '@aws-amplify/appsync-modelgen-plugin'; +import type { + Schema as DataStoreSchema, + SchemaModel as DataStoreModel, + ModelField as DataStoreModelField, + SchemaNonModel as DataStoreNonModel, +} from '@aws-amplify/datastore'; + +import { GenericDataField, GenericDataRelationshipType, GenericDataSchema } from './data-types'; + +class InvalidInputError extends Error { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, InvalidInputError.prototype); + } +} + +const isFieldModelType = ( + field: IntrospectionModelField | DataStoreModelField, +): field is (IntrospectionModelField | DataStoreModelField) & { type: { model: string } } => + typeof field.type === 'object' && 'model' in field.type; + +const getAssociatedFieldNames = (field: IntrospectionModelField | DataStoreModelField): string[] => { + if (!field.association || !('associatedWith' in field.association)) { + return []; + } + + return Array.isArray(field.association.associatedWith) ? field.association.associatedWith : [field.association.associatedWith]; +}; + +const getTargetNames = (field: IntrospectionModelField | DataStoreModelField): string[] => { + const { association } = field; + if (association) { + const targetName = 'targetName' in association && association.targetName; + const targetNames = 'targetNames' in association && association.targetNames; + if (typeof targetName === 'string') { + return [targetName]; + } + if (Array.isArray(targetNames)) { + return targetNames; + } + } + return []; +}; + +/** + Disclaimer: there's no 100% sure way of telling if something's a join table. + This is best effort. + Feature request w/ amplify-codegen: https://github.com/aws-amplify/amplify-codegen/issues/543 + After fulfilled, this can be fallback + */ +function checkIsModelAJoinTable(modelName: string, schema: ModelIntrospectionSchema | DataStoreSchema) { + const model = schema.models[modelName]; + if (!model) { + return false; + } + + let numberOfKeyTypeAttributes = 0; + + const allowedNonModelFields: string[] = ['id', 'createdAt', 'updatedAt']; + + model.attributes?.forEach((attribute) => { + if (attribute.type === 'key') { + numberOfKeyTypeAttributes += 1; + if (attribute.properties && 'fields' in attribute.properties && Array.isArray(attribute.properties.fields)) { + allowedNonModelFields.push(...attribute.properties.fields); + } + } + }); + + // should have 2 keys + if (numberOfKeyTypeAttributes !== 2) { + return false; + } + + const modelFieldTuples: [string, IntrospectionModelField | DataStoreModelField][] = []; + let allFieldsAllowed = true; + + Object.entries(model.fields).forEach((field: [string, IntrospectionModelField | DataStoreModelField]) => { + const [name, value] = field; + if (isFieldModelType(value)) { + modelFieldTuples.push(field); + } else if (!allowedNonModelFields.includes(name)) { + allFieldsAllowed = false; + } + }); + + // non-model fields should be limited + if (!allFieldsAllowed) { + return false; + } + + // should have 2 model fields + if (modelFieldTuples.length !== 2) { + return false; + } + + return modelFieldTuples.every(([fieldName, fieldValue]) => { + // should be required + if (!fieldValue.isRequired) { + return false; + } + + // should be BELONGS_TO + if (fieldValue.association?.connectionType !== 'BELONGS_TO') { + return false; + } + const relatedModel = isFieldModelType(fieldValue) && schema.models[fieldValue.type.model]; + + if (!relatedModel) { + return false; + } + + // should be bidirectional with HAS_MANY + // that has a different model type + return Object.values(relatedModel.fields).some((field: IntrospectionModelField | DataStoreModelField) => { + if (!isFieldModelType(field) || field.association?.connectionType !== 'HAS_MANY') { + return false; + } + + const associatedFieldNames = getAssociatedFieldNames(field); + return associatedFieldNames.length === 1 && associatedFieldNames.includes(fieldName); + }); + }); +} +function getGenericDataField(field: IntrospectionModelField | DataStoreModelField): GenericDataField { + return { + dataType: field.type, + required: !!field.isRequired, + readOnly: !!field.isReadOnly, + isArray: field.isArray, + }; +} +/* eslint-disable no-param-reassign */ +function addRelationship( + fields: { + [modelName: string]: { [fieldName: string]: GenericDataField['relationship'] }; + }, + modelName: string, + fieldName: string, + relationship: GenericDataField['relationship'], +) { + // handle prototype-pollution vulnerability + if (modelName === '__proto__') { + throw new InvalidInputError('Invalid model name "__proto__"'); + } + if (!fields[modelName]) { + fields[modelName] = {}; + } + + const existingRelationship = fields[modelName][fieldName]; + + const isHasManyIndex = existingRelationship && 'isHasManyIndex' in existingRelationship && existingRelationship.isHasManyIndex; + if (relationship?.type === 'HAS_ONE' || relationship?.type === 'BELONGS_TO') { + // give priority to designations as isHasManyIndex and BELONGS_TO + if (isHasManyIndex) { + relationship.isHasManyIndex = true; + } + if (existingRelationship?.type === 'BELONGS_TO') { + relationship.type = 'BELONGS_TO'; + } + } + fields[modelName][fieldName] = relationship; +} +/* eslint-enable no-param-reassign */ + +// get custom primary keys || id +// TODO: when moved over to use introspection schema, this can be vastly simplified +function getPrimaryKeys({ model }: { model: IntrospectionModel | DataStoreModel }) { + const customPrimaryKeys = model.attributes?.find( + (attr) => + attr.type === 'key' && + (attr.properties === undefined || + // presence of name indicates that it is a secondary index and not a primary key + !Object.keys(attr.properties).includes('name')), + )?.properties?.fields; + + return customPrimaryKeys && Array.isArray(customPrimaryKeys) && customPrimaryKeys.length ? customPrimaryKeys : ['id']; +} + +export function getGenericFromDataStore(dataStoreSchema: ModelIntrospectionSchema | DataStoreSchema): GenericDataSchema { + const genericSchema: GenericDataSchema = { + dataSourceType: 'DataStore', + models: {}, + enums: {}, + nonModels: {}, + }; + + const fieldsWithImplicitRelationships: { + [modelName: string]: { [fieldName: string]: GenericDataField['relationship'] }; + } = {}; + + const joinTableNames: string[] = []; + + Object.values(dataStoreSchema.models).forEach((model: DataStoreModel | IntrospectionModel) => { + const genericFields: { [fieldName: string]: GenericDataField } = {}; + + Object.values(model.fields).forEach((field: DataStoreModelField | IntrospectionModelField) => { + const genericField = getGenericDataField(field); + + // handle relationships + if (isFieldModelType(field)) { + if (field.association) { + const relationshipType = field.association.connectionType; + + let relatedModelName = field.type.model; + let relatedJoinFieldName; + let relatedJoinTableName; + let modelRelationship: GenericDataRelationshipType | undefined; + + if (relationshipType === 'HAS_MANY' && 'associatedWith' in field.association) { + // for 1:m relationships, we will not attach these + // (i.e. model-type fields) as relatedModelFields + const modelTypeFieldsOnHasManyChild: Set = new Set(); + + const associatedModel = dataStoreSchema.models[relatedModelName]; + const associatedFieldNames = getAssociatedFieldNames(field); + let canUnlinkAssociatedModel = true; + + associatedFieldNames.forEach((associatedFieldName) => { + const associatedField = associatedModel?.fields[associatedFieldName]; + // if any of the associatedField is required, you cannot unlink from parent model + if (associatedField?.isRequired) { + canUnlinkAssociatedModel = false; + } + + // if the associated model is a join table, update relatedModelName to the actual related model + if (associatedModel && checkIsModelAJoinTable(associatedModel.name, dataStoreSchema)) { + joinTableNames.push(associatedModel.name); + + const relatedJoinField = Object.values(associatedModel.fields).find( + (joinField: IntrospectionModelField | DataStoreModelField) => + joinField.name !== associatedFieldName && isFieldModelType(joinField), + ); + if (relatedJoinField && isFieldModelType(relatedJoinField)) { + relatedJoinTableName = relatedModelName; + relatedModelName = relatedJoinField.type.model; + relatedJoinFieldName = relatedJoinField.name; + } + // if the associated model is not a join table, note implicit relationship for associated field + } else if (associatedField) { + if (isFieldModelType(associatedField)) { + modelTypeFieldsOnHasManyChild.add(associatedFieldName); + } else { + addRelationship(fieldsWithImplicitRelationships, relatedModelName, associatedFieldName, { + type: 'HAS_ONE', + relatedModelName: model.name, + // identify index on 1:m child as such + isHasManyIndex: true, + }); + } + } + }); + + const belongsToFieldOnRelatedModelTuple = Object.entries(associatedModel?.fields ?? {}).find( + ([, f]: [string, IntrospectionModelField | DataStoreModelField]) => + isFieldModelType(f) && f.type.model === model.name && f.association?.connectionType === 'BELONGS_TO', + ); + + if (belongsToFieldOnRelatedModelTuple && belongsToFieldOnRelatedModelTuple[1].isRequired) { + canUnlinkAssociatedModel = false; + } + + modelRelationship = { + type: relationshipType, + canUnlinkAssociatedModel, + relatedModelName, + relatedModelFields: associatedFieldNames.filter((n) => !modelTypeFieldsOnHasManyChild.has(n)), + relatedJoinFieldName, + relatedJoinTableName, + }; + + if (belongsToFieldOnRelatedModelTuple) { + const [belongsToField] = belongsToFieldOnRelatedModelTuple; + modelRelationship.belongsToFieldOnRelatedModel = belongsToField; + } + } + + if (relationshipType === 'HAS_ONE' || relationshipType === 'BELONGS_TO') { + const targetNames = getTargetNames(field); + const associatedFields: string[] = []; + // note implicit relationship for associated field within same model + if (targetNames) { + targetNames.forEach((targetName) => { + addRelationship(fieldsWithImplicitRelationships, model.name, targetName, { + type: relationshipType, + relatedModelName, + }); + associatedFields.push(targetName); + }); + } + modelRelationship = { + type: relationshipType, + relatedModelName, + associatedFields: associatedFields.length ? associatedFields : undefined, + }; + } + + genericField.relationship = modelRelationship; + } + } + + genericFields[field.name] = genericField; + }); + + genericSchema.models[model.name] = { fields: genericFields, primaryKeys: getPrimaryKeys({ model }) }; + }); + + Object.entries(fieldsWithImplicitRelationships).forEach(([modelName, fields]) => { + Object.entries(fields).forEach(([fieldName, relationship]) => { + const field = genericSchema.models[modelName]?.fields[fieldName]; + if (field) { + field.relationship = relationship; + } + }); + }); + + joinTableNames.forEach((joinTableName) => { + const model = genericSchema.models[joinTableName]; + if (model) { + model.isJoinTable = true; + } + }); + + genericSchema.enums = dataStoreSchema.enums; + + if (dataStoreSchema.nonModels) { + Object.values(dataStoreSchema.nonModels).forEach((nonModel: IntrospectionNonModel | DataStoreNonModel) => { + const genericFields: { [fieldName: string]: GenericDataField } = {}; + Object.values(nonModel.fields).forEach((field: IntrospectionModelField | DataStoreModelField) => { + const genericField = getGenericDataField(field); + genericFields[field.name] = genericField; + }); + genericSchema.nonModels[nonModel.name] = { fields: genericFields }; + }); + } + + return genericSchema; +} diff --git a/packages/amplify-util-uibuilder/src/commands/utils/codegenResources.ts b/packages/amplify-util-uibuilder/src/commands/utils/codegenResources.ts index 5479ba179b7..959da5d0f3d 100644 --- a/packages/amplify-util-uibuilder/src/commands/utils/codegenResources.ts +++ b/packages/amplify-util-uibuilder/src/commands/utils/codegenResources.ts @@ -1,4 +1,5 @@ -import { GenericDataSchema, getGenericFromDataStore } from '@aws-amplify/codegen-ui'; +import { getGenericFromDataStore } from './codegen-ui'; +import type { GenericDataSchema } from './data-types'; import { printer } from '@aws-amplify/amplify-prompts'; import { $TSContext } from '@aws-amplify/amplify-cli-core'; import { ModelIntrospectionSchema } from '@aws-amplify/appsync-modelgen-plugin'; diff --git a/packages/amplify-util-uibuilder/src/commands/utils/data-types.ts b/packages/amplify-util-uibuilder/src/commands/utils/data-types.ts new file mode 100644 index 00000000000..97dfd4daee4 --- /dev/null +++ b/packages/amplify-util-uibuilder/src/commands/utils/data-types.ts @@ -0,0 +1,93 @@ +export type SchemaEnums = Record; +export type SchemaEnum = { + name: string; + values: string[]; +}; + +type FieldType = string | { model: string } | { nonModel: string } | { enum: string }; + +export type DataStoreModelField = { + name: string; + type: FieldType; + isReadOnly: boolean; + isRequired: boolean; + isArray: boolean; +}; + +export type CommonRelationshipType = { + relatedModelName: string; +}; + +export type HasManyRelationshipType = { + type: 'HAS_MANY'; + relatedModelFields: string[]; + canUnlinkAssociatedModel: boolean; + relatedJoinFieldName?: string; + relatedJoinTableName?: string; + belongsToFieldOnRelatedModel?: string; +} & CommonRelationshipType; + +export type HasOneRelationshipType = { + type: 'HAS_ONE'; + associatedFields?: string[]; + isHasManyIndex?: boolean; +} & CommonRelationshipType; + +export type BelongsToRelationshipType = { + type: 'BELONGS_TO'; + associatedFields?: string[]; + isHasManyIndex?: boolean; +} & CommonRelationshipType; + +export type GenericDataRelationshipType = HasManyRelationshipType | HasOneRelationshipType | BelongsToRelationshipType; + +export type DataFieldDataType = + | 'ID' + | 'String' + | 'Int' + | 'Float' + | 'AWSDate' + | 'AWSTime' + | 'AWSDateTime' + | 'AWSTimestamp' + | 'AWSEmail' + | 'AWSURL' + | 'AWSIPAddress' + | 'Boolean' + | 'AWSJSON' + | 'AWSPhone' + | { enum: string } + | { model: string } + | { nonModel: string }; + +export type GenericDataField = { + dataType: DataFieldDataType; + + required: boolean; + + readOnly: boolean; + + isArray: boolean; + + relationship?: GenericDataRelationshipType; +}; + +export type GenericDataModel = { + fields: { [fieldName: string]: GenericDataField }; + isJoinTable?: boolean; + primaryKeys: string[]; +}; + +export type GenericDataNonModel = { + fields: { [fieldName: string]: GenericDataField }; +}; + +export type GenericDataSchema = { + dataSourceType: 'DataStore'; + + models: { [modelName: string]: GenericDataModel }; + + enums: { [enumName: string]: { values: string[] } }; + + nonModels: { [nonModelName: string]: GenericDataNonModel }; +}; diff --git a/packages/amplify-util-uibuilder/src/commands/utils/notifyMissingPackages.ts b/packages/amplify-util-uibuilder/src/commands/utils/notifyMissingPackages.ts index 829e98eac8e..d9e056079e7 100644 --- a/packages/amplify-util-uibuilder/src/commands/utils/notifyMissingPackages.ts +++ b/packages/amplify-util-uibuilder/src/commands/utils/notifyMissingPackages.ts @@ -3,8 +3,7 @@ import { printer } from '@aws-amplify/amplify-prompts'; import fs from 'fs-extra'; import path from 'path'; import rangeSubset from 'semver/ranges/subset'; -import { RequiredDependency } from '@aws-amplify/codegen-ui'; -import { ReactRequiredDependencyProvider } from '@aws-amplify/codegen-ui-react'; +import { RequiredDependency, ReactRequiredDependencyProvider } from '../../commands/utils/codegen-ui-dependency-provider'; import { extractArgs } from './extractArgs'; const getRequiredDependencies = (hasStorageManagerField?: boolean): RequiredDependency[] => diff --git a/packages/amplify-util-uibuilder/src/commands/utils/syncAmplifyUiBuilderComponents.ts b/packages/amplify-util-uibuilder/src/commands/utils/syncAmplifyUiBuilderComponents.ts index 87a9b4f01d9..d34bf13d907 100644 --- a/packages/amplify-util-uibuilder/src/commands/utils/syncAmplifyUiBuilderComponents.ts +++ b/packages/amplify-util-uibuilder/src/commands/utils/syncAmplifyUiBuilderComponents.ts @@ -1,5 +1,5 @@ import { printer } from '@aws-amplify/amplify-prompts'; -import type { GenericDataSchema, GenericDataField, GenericDataRelationshipType } from '@aws-amplify/codegen-ui'; +import type { GenericDataSchema, GenericDataField, GenericDataRelationshipType } from './data-types'; import { CodegenGenericDataEnum, CodegenGenericDataFieldDataType, @@ -87,7 +87,7 @@ const mapDataFieldsToCodegen = (fields: { [fieldName: string]: GenericDataField return codegenFields; }; -export const mapGenericDataSchemaToCodegen = (genericDataSchema: GenericDataSchema): CodegenJobGenericDataSchema => { +export const mapGenericDataSchemaToCodegen = async (genericDataSchema: GenericDataSchema): CodegenJobGenericDataSchema | undefined => { const { models, nonModels, enums, dataSourceType } = genericDataSchema; const codegenModels: { [key: string]: CodegenGenericDataModel } = {}; const codegenNonModels: { [key: string]: CodegenGenericDataNonModel } = {}; diff --git a/yarn.lock b/yarn.lock index e1726834521..5d33ab42965 100644 --- a/yarn.lock +++ b/yarn.lock @@ -945,8 +945,7 @@ __metadata: "@aws-amplify/amplify-cli-core": 4.2.7 "@aws-amplify/amplify-prompts": 2.8.4 "@aws-amplify/appsync-modelgen-plugin": ^2.6.0 - "@aws-amplify/codegen-ui": 2.14.2 - "@aws-amplify/codegen-ui-react": 2.14.2 + "@aws-amplify/datastore": ^4.7.5 "@types/fs-extra": ^8.0.1 "@types/jest": ^29.5.1 "@types/semver": ^7.1.0 @@ -956,6 +955,7 @@ __metadata: fs-extra: ^8.1.0 node-fetch: ^2.6.7 ora: ^4.0.3 + semver: ^7.5.4 tiny-async-pool: ^2.1.0 ts-jest: ^29.1.0 languageName: unknown @@ -994,6 +994,23 @@ __metadata: languageName: node linkType: hard +"@aws-amplify/api-graphql@npm:3.4.11": + version: 3.4.11 + resolution: "@aws-amplify/api-graphql@npm:3.4.11" + dependencies: + "@aws-amplify/api-rest": 3.5.5 + "@aws-amplify/auth": 5.6.5 + "@aws-amplify/cache": 5.1.11 + "@aws-amplify/core": 5.8.5 + "@aws-amplify/pubsub": 5.5.5 + graphql: 15.8.0 + tslib: ^1.8.0 + uuid: ^3.2.1 + zen-observable-ts: 0.8.19 + checksum: ae4bc4b03174824ed67163864c661c9486de6b3480ebac29a93381beb8570ae39ec5f4913801bf2dedc41a98a7e87bb597d972d0aeb4225e4b7ca4d583462370 + languageName: node + linkType: hard + "@aws-amplify/api-rest@npm:2.0.29": version: 2.0.29 resolution: "@aws-amplify/api-rest@npm:2.0.29" @@ -1004,6 +1021,18 @@ __metadata: languageName: node linkType: hard +"@aws-amplify/api-rest@npm:3.5.5": + version: 3.5.5 + resolution: "@aws-amplify/api-rest@npm:3.5.5" + dependencies: + "@aws-amplify/core": 5.8.5 + axios: 0.26.0 + tslib: ^1.8.0 + url: 0.11.0 + checksum: 2822d75b0abefd091d0c52ba8822b2a6b34589708dce980a47c1ebb1d492a06ba56b47fbe1b101e4c427acd598be3912a00a30b56aae685063e6630f809930c0 + languageName: node + linkType: hard + "@aws-amplify/api@npm:4.0.29": version: 4.0.29 resolution: "@aws-amplify/api@npm:4.0.29" @@ -1045,6 +1074,19 @@ __metadata: languageName: node linkType: hard +"@aws-amplify/auth@npm:5.6.5": + version: 5.6.5 + resolution: "@aws-amplify/auth@npm:5.6.5" + dependencies: + "@aws-amplify/core": 5.8.5 + amazon-cognito-identity-js: 6.3.6 + buffer: 4.9.2 + tslib: ^1.8.0 + url: 0.11.0 + checksum: 8113f435c11fb3a5619f08cffe488fd71fc2ef29d7f5c82c5fa3db9328823b60f5ac4b5eae10ce92624e57287fad7cefe3de794a0e32d3f157765f68c3658956 + languageName: node + linkType: hard + "@aws-amplify/cache@npm:4.0.31": version: 4.0.31 resolution: "@aws-amplify/cache@npm:4.0.31" @@ -1054,6 +1096,16 @@ __metadata: languageName: node linkType: hard +"@aws-amplify/cache@npm:5.1.11": + version: 5.1.11 + resolution: "@aws-amplify/cache@npm:5.1.11" + dependencies: + "@aws-amplify/core": 5.8.5 + tslib: ^1.8.0 + checksum: 0ea58972d1b9bdcd46218d9c858be7ec3523aca3734239476a9dbd7951b40643c6cad7b2eec2f21806696c3a380a9e2e6b867cf5dc1b33b8f29877405c7ca2cd + languageName: node + linkType: hard + "@aws-amplify/cli-extensibility-helper@3.0.17, @aws-amplify/cli-extensibility-helper@workspace:packages/amplify-cli-extensibility-helper": version: 0.0.0-use.local resolution: "@aws-amplify/cli-extensibility-helper@workspace:packages/amplify-cli-extensibility-helper" @@ -1174,34 +1226,6 @@ __metadata: languageName: unknown linkType: soft -"@aws-amplify/codegen-ui-react@npm:2.14.2": - version: 2.14.2 - resolution: "@aws-amplify/codegen-ui-react@npm:2.14.2" - dependencies: - "@aws-amplify/codegen-ui": 2.14.2 - "@typescript/vfs": ~1.3.5 - prettier: 2.3.2 - typescript: <=4.5.0 - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - dependenciesMeta: - prettier: - optional: true - checksum: 91052ff146601bedc2e08f6b878ddc89e8633529e203f1a4a4c68ff441cc27d141c0dc748893e572b2f91501d81405f819d76aacde6345b212ef271d1b223b4d - languageName: node - linkType: hard - -"@aws-amplify/codegen-ui@npm:2.14.2": - version: 2.14.2 - resolution: "@aws-amplify/codegen-ui@npm:2.14.2" - dependencies: - change-case: ^4.1.2 - yup: ^0.32.11 - checksum: 1ef00989aa89584e10e9d5216c78265ba3ce06f6770b414237db1e09fa49fa07a5d7faa24cd121df67af1bffcf9d8c4c518fb0a30df2e9b95cc3b637a523c704 - languageName: node - linkType: hard - "@aws-amplify/core@npm:4.3.11": version: 4.3.11 resolution: "@aws-amplify/core@npm:4.3.11" @@ -1218,6 +1242,24 @@ __metadata: languageName: node linkType: hard +"@aws-amplify/core@npm:5.8.5": + version: 5.8.5 + resolution: "@aws-amplify/core@npm:5.8.5" + dependencies: + "@aws-crypto/sha256-js": 1.2.2 + "@aws-sdk/client-cloudwatch-logs": 3.6.1 + "@aws-sdk/types": 3.6.1 + "@aws-sdk/util-hex-encoding": 3.6.1 + "@types/node-fetch": 2.6.4 + isomorphic-unfetch: ^3.0.0 + react-native-url-polyfill: ^1.3.0 + tslib: ^1.8.0 + universal-cookie: ^4.0.4 + zen-observable-ts: 0.8.19 + checksum: b018787a8cafba68d83b316dab8216ee42dd0673e839bf44efac259b1ac2b4aa51324d259b9cbfbd24e3a469a8b05bd5ad5920d6b7c9ddb948955a1dc59ed4e3 + languageName: node + linkType: hard + "@aws-amplify/datastore@npm:3.7.3": version: 3.7.3 resolution: "@aws-amplify/datastore@npm:3.7.3" @@ -1237,6 +1279,26 @@ __metadata: languageName: node linkType: hard +"@aws-amplify/datastore@npm:^4.7.5": + version: 4.7.5 + resolution: "@aws-amplify/datastore@npm:4.7.5" + dependencies: + "@aws-amplify/api": 5.4.5 + "@aws-amplify/auth": 5.6.5 + "@aws-amplify/core": 5.8.5 + "@aws-amplify/pubsub": 5.5.5 + amazon-cognito-identity-js: 6.3.6 + buffer: 4.9.2 + idb: 5.0.6 + immer: 9.0.6 + ulid: 2.3.0 + uuid: 3.4.0 + zen-observable-ts: 0.8.19 + zen-push: 0.2.1 + checksum: 7d3df8684831f48875cca89316c0d71e1c3c7150b23ff9f687501c0457ff9d1538027cd82715541932ca910f2e5ab55c50a02c86be80db7f01274f8b165f3d28 + languageName: node + linkType: hard + "@aws-amplify/geo@npm:1.1.11": version: 1.1.11 resolution: "@aws-amplify/geo@npm:1.1.11" @@ -1601,6 +1663,23 @@ __metadata: languageName: node linkType: hard +"@aws-amplify/pubsub@npm:5.5.5": + version: 5.5.5 + resolution: "@aws-amplify/pubsub@npm:5.5.5" + dependencies: + "@aws-amplify/auth": 5.6.5 + "@aws-amplify/cache": 5.1.11 + "@aws-amplify/core": 5.8.5 + buffer: 4.9.2 + graphql: 15.8.0 + tslib: ^1.8.0 + url: 0.11.0 + uuid: ^3.2.1 + zen-observable-ts: 0.8.19 + checksum: c5540f4cc33c18d9d6ecdc9e31dcb1fff976f5a5589ecd2f74b6244f9590a30cdf58a57d6c6796b366d50d16249c59aab06ad3f10005e4a269b998fca7acf6de + languageName: node + linkType: hard + "@aws-amplify/storage@npm:4.4.12": version: 4.4.12 resolution: "@aws-amplify/storage@npm:4.4.12" @@ -1821,6 +1900,17 @@ __metadata: languageName: node linkType: hard +"@aws-crypto/sha256-js@npm:1.2.2, @aws-crypto/sha256-js@npm:^1.0.0, @aws-crypto/sha256-js@npm:^1.2.0, @aws-crypto/sha256-js@npm:^1.2.2": + version: 1.2.2 + resolution: "@aws-crypto/sha256-js@npm:1.2.2" + dependencies: + "@aws-crypto/util": ^1.2.2 + "@aws-sdk/types": ^3.1.0 + tslib: ^1.11.1 + checksum: f4e8593cfbc48591413f00c744569b21e5ed5fab0e27fa4b59c517f2024ca4f46fab7b3874f2a207ceeef8feefc22d143a82d6c6bfe5303ea717f579d8d7ad0a + languageName: node + linkType: hard + "@aws-crypto/sha256-js@npm:2.0.0": version: 2.0.0 resolution: "@aws-crypto/sha256-js@npm:2.0.0" @@ -1843,17 +1933,6 @@ __metadata: languageName: node linkType: hard -"@aws-crypto/sha256-js@npm:^1.0.0, @aws-crypto/sha256-js@npm:^1.2.0, @aws-crypto/sha256-js@npm:^1.2.2": - version: 1.2.2 - resolution: "@aws-crypto/sha256-js@npm:1.2.2" - dependencies: - "@aws-crypto/util": ^1.2.2 - "@aws-sdk/types": ^3.1.0 - tslib: ^1.11.1 - checksum: f4e8593cfbc48591413f00c744569b21e5ed5fab0e27fa4b59c517f2024ca4f46fab7b3874f2a207ceeef8feefc22d143a82d6c6bfe5303ea717f579d8d7ad0a - languageName: node - linkType: hard - "@aws-crypto/sha256-js@npm:^2.0.0": version: 2.0.1 resolution: "@aws-crypto/sha256-js@npm:2.0.1" @@ -8259,7 +8338,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.10.5, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2, @babel/runtime@npm:^7.9.6": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.10.5, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2, @babel/runtime@npm:^7.9.6": version: 7.17.9 resolution: "@babel/runtime@npm:7.17.9" dependencies: @@ -12701,7 +12780,7 @@ __metadata: languageName: node linkType: hard -"@types/lodash@npm:*, @types/lodash@npm:^4.14.149, @types/lodash@npm:^4.14.175": +"@types/lodash@npm:*, @types/lodash@npm:^4.14.149": version: 4.14.178 resolution: "@types/lodash@npm:4.14.178" checksum: 820e33578a084aba2ca66fc83728c14d82813b91f3f14f281621b36904533c3d1681992b5e2719579b8beb52e1a77cfa914283a145f66dfa71b5e02a7cec5a37 @@ -12745,6 +12824,16 @@ __metadata: languageName: node linkType: hard +"@types/node-fetch@npm:2.6.4": + version: 2.6.4 + resolution: "@types/node-fetch@npm:2.6.4" + dependencies: + "@types/node": "*" + form-data: ^3.0.0 + checksum: e43e4670ed8b7693dbf660ac1450b14fcfcdd8efca1eb0f501b6ad95af2d1fa06f8541db03e9511e82a5fee510a238fe0913330c9a58f8ac6892b985f6dd993e + languageName: node + linkType: hard + "@types/node-fetch@npm:^2.6.1": version: 2.6.1 resolution: "@types/node-fetch@npm:2.6.1" @@ -13342,15 +13431,6 @@ __metadata: languageName: node linkType: hard -"@typescript/vfs@npm:~1.3.5": - version: 1.3.5 - resolution: "@typescript/vfs@npm:1.3.5" - dependencies: - debug: ^4.1.1 - checksum: b3512eb50b6dc6affbd0402eb6cf6ee31b2877c262588520753f5a4de8ecf73f396843ac776b3b1ab681d34448154672b6fd6f826184cb9318c9835e5511b3da - languageName: node - linkType: hard - "@ungap/promise-all-settled@npm:1.1.2": version: 1.1.2 resolution: "@ungap/promise-all-settled@npm:1.1.2" @@ -13854,6 +13934,19 @@ __metadata: languageName: node linkType: hard +"amazon-cognito-identity-js@npm:6.3.6": + version: 6.3.6 + resolution: "amazon-cognito-identity-js@npm:6.3.6" + dependencies: + "@aws-crypto/sha256-js": 1.2.2 + buffer: 4.9.2 + fast-base64-decode: ^1.0.0 + isomorphic-unfetch: ^3.0.0 + js-cookie: ^2.2.1 + checksum: 96512224b26fc9f7aa052c8d76b968aae33910745e8647854754ff72d8e184bdc246e330c4e8ab46af0e926372c0be7f25767d4ce8394c83a7480b6b60d543fe + languageName: node + linkType: hard + "amdefine@npm:>=0.0.4": version: 1.0.1 resolution: "amdefine@npm:1.0.1" @@ -14969,7 +15062,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.26.0": +"axios@npm:0.26.0, axios@npm:^0.26.0": version: 0.26.0 resolution: "axios@npm:0.26.0" dependencies: @@ -15785,7 +15878,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.5.0, buffer@npm:^5.7.0": +"buffer@npm:^5.4.3, buffer@npm:^5.5.0, buffer@npm:^5.7.0": version: 5.7.1 resolution: "buffer@npm:5.7.1" dependencies: @@ -25422,13 +25515,6 @@ __metadata: languageName: node linkType: hard -"nanoclone@npm:^0.2.1": - version: 0.2.1 - resolution: "nanoclone@npm:0.2.1" - checksum: 760b569ea841c9678fdf8d763c6d7bb093f0889150087f82d86c536a318b302939c82ce35cdaec999d0f687789d0d79d0f3f75a272d7a98dfac7a067c0b47053 - languageName: node - linkType: hard - "nanoid@npm:3.1.25": version: 3.1.25 resolution: "nanoid@npm:3.1.25" @@ -27999,15 +28085,6 @@ node-pty@beta: languageName: node linkType: hard -"prettier@npm:2.3.2": - version: 2.3.2 - resolution: "prettier@npm:2.3.2" - bin: - prettier: bin-prettier.js - checksum: 40f159f05808966ff4c57e147651cf038adb7f5af3fbca8d999b87ccbaeff7d73cf9038a45f667a8c18cbb049c1a980a752fa8987dfd3dcdd66e932e366f40be - languageName: node - linkType: hard - "prettier@npm:^1.19.1": version: 1.19.1 resolution: "prettier@npm:1.19.1" @@ -28244,13 +28321,6 @@ node-pty@beta: languageName: node linkType: hard -"property-expr@npm:^2.0.4": - version: 2.0.4 - resolution: "property-expr@npm:2.0.4" - checksum: 6d289a02bbb812990bcc63f1e3607bf97adcb912e3a75d72cfc33f01bfd80170d4234668de965fa44bfac73e3e18f5bf4cff7bae5713bd2caa1e9b583bd8a51a - languageName: node - linkType: hard - "proto-list@npm:~1.2.1": version: 1.2.4 resolution: "proto-list@npm:1.2.4" @@ -28630,6 +28700,17 @@ node-pty@beta: languageName: node linkType: hard +"react-native-url-polyfill@npm:^1.3.0": + version: 1.3.0 + resolution: "react-native-url-polyfill@npm:1.3.0" + dependencies: + whatwg-url-without-unicode: 8.0.0-3 + peerDependencies: + react-native: "*" + checksum: d8167ad2cc17261906ffde19970279406db63d61b9ca85d85b02f5592e53a83db70aace3c1d89081ce46ddcfacbdac6a7faaa329b5235c6b980e1f533de5b318 + languageName: node + linkType: hard + "react-popper@npm:^2.3.0": version: 2.3.0 resolution: "react-popper@npm:2.3.0" @@ -31363,13 +31444,6 @@ node-pty@beta: languageName: node linkType: hard -"toposort@npm:^2.0.2": - version: 2.0.2 - resolution: "toposort@npm:2.0.2" - checksum: ab9ca91fce4b972ccae9e2f539d755bf799a0c7eb60da07fd985fce0f14c159ed1e92305ff55697693b5bc13e300f5417db90e2593b127d421c9f6c440950222 - languageName: node - linkType: hard - "tough-cookie@npm:^4.1.3": version: 4.1.3 resolution: "tough-cookie@npm:4.1.3" @@ -31812,16 +31886,6 @@ node-pty@beta: languageName: node linkType: hard -"typescript@npm:<=4.5.0, typescript@npm:~4.4.4": - version: 4.4.4 - resolution: "typescript@npm:4.4.4" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 7cd160bbfdf99404238c296db0d56352c7e1d57e367f02640ca36f254f3fa47f74bfc76615e0010c2688a443d9e7403e2d26c79d98ab450d924b17c950732486 - languageName: node - linkType: hard - "typescript@npm:^3 || ^4, typescript@npm:^4.9.5": version: 4.9.5 resolution: "typescript@npm:4.9.5" @@ -31842,23 +31906,23 @@ node-pty@beta: languageName: node linkType: hard -"typescript@npm:~4.8.3, typescript@npm:~4.8.4": - version: 4.8.4 - resolution: "typescript@npm:4.8.4" +"typescript@npm:~4.4.4": + version: 4.4.4 + resolution: "typescript@npm:4.4.4" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 663bf455b21ac024e719bb8c6a07bcaaa027a9943abfb58a694b59789e7d08578badb5556170267ad480e31786b8b4c8ab3c9c0e597d3b8df39af800e43c6ed5 + checksum: 7cd160bbfdf99404238c296db0d56352c7e1d57e367f02640ca36f254f3fa47f74bfc76615e0010c2688a443d9e7403e2d26c79d98ab450d924b17c950732486 languageName: node linkType: hard -"typescript@patch:typescript@<=4.5.0#~builtin, typescript@patch:typescript@~4.4.4#~builtin": - version: 4.4.4 - resolution: "typescript@patch:typescript@npm%3A4.4.4#~builtin::version=4.4.4&hash=bbeadb" +"typescript@npm:~4.8.3, typescript@npm:~4.8.4": + version: 4.8.4 + resolution: "typescript@npm:4.8.4" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 5eb1f150ac8d9a1bf79b971dcabe4158e10666d19733a1e9d36ea6b2c9f60e129889fe02c945b7b863d94749f582e633115a9dcb3c607e435246fdecb957dc27 + checksum: 663bf455b21ac024e719bb8c6a07bcaaa027a9943abfb58a694b59789e7d08578badb5556170267ad480e31786b8b4c8ab3c9c0e597d3b8df39af800e43c6ed5 languageName: node linkType: hard @@ -31882,6 +31946,16 @@ node-pty@beta: languageName: node linkType: hard +"typescript@patch:typescript@~4.4.4#~builtin": + version: 4.4.4 + resolution: "typescript@patch:typescript@npm%3A4.4.4#~builtin::version=4.4.4&hash=bbeadb" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 5eb1f150ac8d9a1bf79b971dcabe4158e10666d19733a1e9d36ea6b2c9f60e129889fe02c945b7b863d94749f582e633115a9dcb3c607e435246fdecb957dc27 + languageName: node + linkType: hard + "typescript@patch:typescript@~4.8.3#~builtin, typescript@patch:typescript@~4.8.4#~builtin": version: 4.8.4 resolution: "typescript@patch:typescript@npm%3A4.8.4#~builtin::version=4.8.4&hash=1a91c8" @@ -32231,7 +32305,7 @@ node-pty@beta: languageName: node linkType: hard -"url@npm:^0.11.0": +"url@npm:0.11.0, url@npm:^0.11.0": version: 0.11.0 resolution: "url@npm:0.11.0" dependencies: @@ -32313,7 +32387,7 @@ node-pty@beta: languageName: node linkType: hard -"uuid@npm:3.x, uuid@npm:^3.0.0, uuid@npm:^3.2.1, uuid@npm:^3.3.2": +"uuid@npm:3.4.0, uuid@npm:3.x, uuid@npm:^3.0.0, uuid@npm:^3.2.1, uuid@npm:^3.3.2": version: 3.4.0 resolution: "uuid@npm:3.4.0" bin: @@ -32565,6 +32639,13 @@ node-pty@beta: languageName: node linkType: hard +"webidl-conversions@npm:^5.0.0": + version: 5.0.0 + resolution: "webidl-conversions@npm:5.0.0" + checksum: bf31df332ed11e1114bfcae7712d9ab2c37e7faa60ba32d8fdbee785937c0b012eee235c19d2b5d84f5072db84a160e8d08dd382da7f850feec26a4f46add8ff + languageName: node + linkType: hard + "webpack-dev-middleware@npm:^5.3.1": version: 5.3.1 resolution: "webpack-dev-middleware@npm:5.3.1" @@ -32732,6 +32813,17 @@ node-pty@beta: languageName: node linkType: hard +"whatwg-url-without-unicode@npm:8.0.0-3": + version: 8.0.0-3 + resolution: "whatwg-url-without-unicode@npm:8.0.0-3" + dependencies: + buffer: ^5.4.3 + punycode: ^2.1.1 + webidl-conversions: ^5.0.0 + checksum: c27a637ab7d01981b2e2f576fde2113b9c42247500e093d2f5ba94b515d5c86dbcf70e5cad4b21b8813185f21fa1b4846f53c79fa87995293457e28c889cc0fd + languageName: node + linkType: hard + "whatwg-url@npm:^5.0.0": version: 5.0.0 resolution: "whatwg-url@npm:5.0.0" @@ -33535,21 +33627,6 @@ node-pty@beta: languageName: node linkType: hard -"yup@npm:^0.32.11": - version: 0.32.11 - resolution: "yup@npm:0.32.11" - dependencies: - "@babel/runtime": ^7.15.4 - "@types/lodash": ^4.14.175 - lodash: ^4.17.21 - lodash-es: ^4.17.21 - nanoclone: ^0.2.1 - property-expr: ^2.0.4 - toposort: ^2.0.2 - checksum: f0802798dc64b49f313886b983a9bea5f283e2094ee2aa1197587b84f50ac5b5d03af99857c313139e63dc02558fac3aaa343503bdbffa96f70006b39d1f59c9 - languageName: node - linkType: hard - "z-schema@npm:~5.0.2": version: 5.0.4 resolution: "z-schema@npm:5.0.4" From 4d76058fe3ecd34a33ecc7f675272a17f56eb6d9 Mon Sep 17 00:00:00 2001 From: Justin Shih Date: Thu, 21 Sep 2023 17:08:33 -0700 Subject: [PATCH 2/2] fix: remove async map generic dataschema --- .../src/__tests__/generateComponents.test.ts | 1 + .../src/commands/generateComponents.ts | 2 +- .../utils/syncAmplifyUiBuilderComponents.ts | 2 +- yarn.lock | 23 ++++++++++--------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/amplify-util-uibuilder/src/__tests__/generateComponents.test.ts b/packages/amplify-util-uibuilder/src/__tests__/generateComponents.test.ts index 493c7a6d1af..73f61ef3b00 100644 --- a/packages/amplify-util-uibuilder/src/__tests__/generateComponents.test.ts +++ b/packages/amplify-util-uibuilder/src/__tests__/generateComponents.test.ts @@ -35,6 +35,7 @@ const getUiBuilderComponentsPathMocked = getUiBuilderComponentsPath as any; utilsMock.shouldRenderComponents = jest.fn().mockReturnValue(true); utilsMock.notifyMissingPackages = jest.fn().mockReturnValue(true); utilsMock.getAmplifyDataSchema = jest.fn().mockReturnValue({}); +utilsMock.mapGenericDataSchemaToCodegen = jest.fn().mockReturnValue({}); utilsMock.isFormDetachedFromModel = jest.fn().mockReturnValue(false); utilsMock.extractUIComponents = jest.fn().mockReturnValue(undefined); utilsMock.waitForSucceededJob = jest diff --git a/packages/amplify-util-uibuilder/src/commands/generateComponents.ts b/packages/amplify-util-uibuilder/src/commands/generateComponents.ts index 54092777601..387959db636 100644 --- a/packages/amplify-util-uibuilder/src/commands/generateComponents.ts +++ b/packages/amplify-util-uibuilder/src/commands/generateComponents.ts @@ -35,7 +35,7 @@ export const run = async (context: $TSContext, eventType: 'PostPush' | 'PostPull studioClient.isGraphQLSupported ? getAmplifyDataSchema(context) : Promise.resolve(undefined), ]); const genericDataSchema = dataSchema ? mapGenericDataSchemaToCodegen(dataSchema) : undefined; - + const canGenerateDataComponents = genericDataSchema && studioClient.isGraphQLSupported; const apiConfiguration: AmplifyUIBuilder.ApiConfiguration = canGenerateDataComponents diff --git a/packages/amplify-util-uibuilder/src/commands/utils/syncAmplifyUiBuilderComponents.ts b/packages/amplify-util-uibuilder/src/commands/utils/syncAmplifyUiBuilderComponents.ts index d34bf13d907..eeaeb408ed3 100644 --- a/packages/amplify-util-uibuilder/src/commands/utils/syncAmplifyUiBuilderComponents.ts +++ b/packages/amplify-util-uibuilder/src/commands/utils/syncAmplifyUiBuilderComponents.ts @@ -87,7 +87,7 @@ const mapDataFieldsToCodegen = (fields: { [fieldName: string]: GenericDataField return codegenFields; }; -export const mapGenericDataSchemaToCodegen = async (genericDataSchema: GenericDataSchema): CodegenJobGenericDataSchema | undefined => { +export const mapGenericDataSchemaToCodegen = (genericDataSchema: GenericDataSchema): CodegenJobGenericDataSchema => { const { models, nonModels, enums, dataSourceType } = genericDataSchema; const codegenModels: { [key: string]: CodegenGenericDataModel } = {}; const codegenNonModels: { [key: string]: CodegenGenericDataNonModel } = {}; diff --git a/yarn.lock b/yarn.lock index 5d33ab42965..f40315ff4ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1043,6 +1043,17 @@ __metadata: languageName: node linkType: hard +"@aws-amplify/api@npm:5.4.5": + version: 5.4.5 + resolution: "@aws-amplify/api@npm:5.4.5" + dependencies: + "@aws-amplify/api-graphql": 3.4.11 + "@aws-amplify/api-rest": 3.5.5 + tslib: ^1.8.0 + checksum: 13f3551e5d2d29a201f5011a265fcaa24fdec4796afe835f2c0d9b8fcc76f243663d691de2273c680b2efbe4fea2fb1ecd7678ed393a605997ee97021f03d138 + languageName: node + linkType: hard + "@aws-amplify/appsync-modelgen-plugin@npm:2.7.2, @aws-amplify/appsync-modelgen-plugin@npm:^2.6.0": version: 2.7.2 resolution: "@aws-amplify/appsync-modelgen-plugin@npm:2.7.2" @@ -12824,7 +12835,7 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:2.6.4": +"@types/node-fetch@npm:2.6.4, @types/node-fetch@npm:^2.6.1": version: 2.6.4 resolution: "@types/node-fetch@npm:2.6.4" dependencies: @@ -12834,16 +12845,6 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:^2.6.1": - version: 2.6.1 - resolution: "@types/node-fetch@npm:2.6.1" - dependencies: - "@types/node": "*" - form-data: ^3.0.0 - checksum: 033945215fa6b36d5597b21bbdd7d946a751dcd066f8fa71e5f5ab5698390bc2e76e38932ec6ac709def39b6371dfd61844e6804409c7ba812e24d1c820fbff8 - languageName: node - linkType: hard - "@types/node@npm:*, @types/node@npm:^18.16.1": version: 18.16.1 resolution: "@types/node@npm:18.16.1"