From f51b5d3bbac23f7f63e0adc0bd2aad67b0621977 Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Wed, 27 Mar 2024 09:12:48 -0700 Subject: [PATCH 1/8] feat: enable codegen to run in browser (#789) --- .codebuild/e2e_workflow.yml | 18 ++++--- .../__tests__/graphql-generator-app.test.ts | 17 ++++++ .../graphql-generator-app/.gitignore | 23 ++++++++ .../test-apps/graphql-generator-app/README.md | 46 ++++++++++++++++ .../graphql-generator-app/config-overrides.js | 45 ++++++++++++++++ .../graphql-generator-app/cypress.config.ts | 13 +++++ .../cypress/support/commands.ts | 2 + .../cypress/support/component-index.html | 12 +++++ .../cypress/support/component.ts | 39 ++++++++++++++ .../graphql-generator-app/package.json | 54 +++++++++++++++++++ .../graphql-generator-app/public/index.html | 40 ++++++++++++++ .../graphql-generator-app/src/App.cy.js | 23 ++++++++ .../graphql-generator-app/src/App.tsx | 46 ++++++++++++++++ .../graphql-generator-app/src/index.tsx | 14 +++++ .../src/polyfills/fs-extra.js | 18 +++++++ .../src/polyfills/process-shim.js | 28 ++++++++++ .../graphql-generator-app/src/schemas.ts | 20 +++++++ .../graphql-generator-app/src/testCases.ts | 40 ++++++++++++++ .../graphql-generator-app/tsconfig.json | 26 +++++++++ .../codegen-config/AmplifyCodeGenConfig.js | 3 +- packages/amplify-codegen/src/commands/add.js | 3 +- .../src/utils/getRelativeTypesPath.js | 3 +- .../src/utils/input-params-manager.js | 4 +- .../1/ModelIntrospectionSchema.json | 0 .../appsync-model-introspection-visitor.ts | 6 +-- .../appsync-modelgen-plugin/tsconfig.json | 5 +- packages/graphql-generator/src/models.ts | 3 +- .../src/utils/GraphQLStatementsFormatter.ts | 3 +- .../src/utilities/getOutputFileName.ts | 3 +- 29 files changed, 537 insertions(+), 20 deletions(-) create mode 100644 packages/amplify-codegen-e2e-tests/src/__tests__/graphql-generator-app.test.ts create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/.gitignore create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/README.md create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/config-overrides.js create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress.config.ts create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/commands.ts create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/component-index.html create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/component.ts create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/package.json create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/public/index.html create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/App.cy.js create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/App.tsx create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/index.tsx create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/polyfills/fs-extra.js create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/polyfills/process-shim.js create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/schemas.ts create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/testCases.ts create mode 100644 packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/tsconfig.json rename packages/appsync-modelgen-plugin/{ => src}/schemas/introspection/1/ModelIntrospectionSchema.json (100%) diff --git a/.codebuild/e2e_workflow.yml b/.codebuild/e2e_workflow.yml index b250e8310..f0e8c945b 100644 --- a/.codebuild/e2e_workflow.yml +++ b/.codebuild/e2e_workflow.yml @@ -145,24 +145,25 @@ batch: depend-on: - publish_to_local_registry - identifier: >- - l_build_app_ts_uninitialized_project_codegen_js_uninitialized_project_modelgen_android_uninitialized_project_modelgen_flutter + l_build_app_ts_graphql_generator_app_uninitialized_project_codegen_js_uninitialized_project_modelgen_android buildspec: .codebuild/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_LARGE variables: TEST_SUITE: >- - src/__tests__/build-app-ts.test.ts|src/__tests__/uninitialized-project-codegen-js.test.ts|src/__tests__/uninitialized-project-modelgen-android.test.ts|src/__tests__/uninitialized-project-modelgen-flutter.test.ts + src/__tests__/build-app-ts.test.ts|src/__tests__/graphql-generator-app.test.ts|src/__tests__/uninitialized-project-codegen-js.test.ts|src/__tests__/uninitialized-project-modelgen-android.test.ts CLI_REGION: ap-southeast-1 DISABLE_ESLINT_PLUGIN: true depend-on: - publish_to_local_registry - - identifier: l_uninitialized_project_modelgen_ios_uninitialized_project_modelgen_js + - identifier: >- + l_uninitialized_project_modelgen_flutter_uninitialized_project_modelgen_ios_uninitialized_project_modelgen_js buildspec: .codebuild/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_LARGE variables: TEST_SUITE: >- - src/__tests__/uninitialized-project-modelgen-ios.test.ts|src/__tests__/uninitialized-project-modelgen-js.test.ts + src/__tests__/uninitialized-project-modelgen-flutter.test.ts|src/__tests__/uninitialized-project-modelgen-ios.test.ts|src/__tests__/uninitialized-project-modelgen-js.test.ts CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry @@ -251,7 +252,7 @@ batch: - publish_to_local_registry - build_windows - identifier: >- - w_build_app_ts_uninitialized_project_codegen_js_uninitialized_project_modelgen_android_uninitialized_project_modelgen_flutter + w_build_app_ts_graphql_generator_app_uninitialized_project_codegen_js_uninitialized_project_modelgen_android buildspec: .codebuild/run_e2e_tests_windows.yml env: compute-type: BUILD_GENERAL1_LARGE @@ -259,13 +260,14 @@ batch: type: WINDOWS_SERVER_2019_CONTAINER variables: TEST_SUITE: >- - src/__tests__/build-app-ts.test.ts|src/__tests__/uninitialized-project-codegen-js.test.ts|src/__tests__/uninitialized-project-modelgen-android.test.ts|src/__tests__/uninitialized-project-modelgen-flutter.test.ts + src/__tests__/build-app-ts.test.ts|src/__tests__/graphql-generator-app.test.ts|src/__tests__/uninitialized-project-codegen-js.test.ts|src/__tests__/uninitialized-project-modelgen-android.test.ts CLI_REGION: us-east-1 DISABLE_ESLINT_PLUGIN: true depend-on: - publish_to_local_registry - build_windows - - identifier: w_uninitialized_project_modelgen_ios_uninitialized_project_modelgen_js + - identifier: >- + w_uninitialized_project_modelgen_flutter_uninitialized_project_modelgen_ios_uninitialized_project_modelgen_js buildspec: .codebuild/run_e2e_tests_windows.yml env: compute-type: BUILD_GENERAL1_LARGE @@ -273,7 +275,7 @@ batch: type: WINDOWS_SERVER_2019_CONTAINER variables: TEST_SUITE: >- - src/__tests__/uninitialized-project-modelgen-ios.test.ts|src/__tests__/uninitialized-project-modelgen-js.test.ts + src/__tests__/uninitialized-project-modelgen-flutter.test.ts|src/__tests__/uninitialized-project-modelgen-ios.test.ts|src/__tests__/uninitialized-project-modelgen-js.test.ts CLI_REGION: us-east-1 depend-on: - publish_to_local_registry diff --git a/packages/amplify-codegen-e2e-tests/src/__tests__/graphql-generator-app.test.ts b/packages/amplify-codegen-e2e-tests/src/__tests__/graphql-generator-app.test.ts new file mode 100644 index 000000000..0bf9a0b88 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/src/__tests__/graphql-generator-app.test.ts @@ -0,0 +1,17 @@ +import { DEFAULT_JS_CONFIG, craInstall, craBuild, cypressRun, isWindows } from '@aws-amplify/amplify-codegen-e2e-core'; +import path from 'path'; + +describe('GraphQL documents generator e2e tests', () => { + let apiName: string; + const projectRoot = path.resolve('test-apps', 'graphql-generator-app'); + const config = DEFAULT_JS_CONFIG; + + beforeAll(async () => { + await craInstall(projectRoot, { ...config }); + }); + + // skip cypress test on windows + (isWindows() ? it.skip : it)('graphql generator does not crash in browser', async () => { + await cypressRun(projectRoot, { componentsTesting: true }); + }); +}); diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/.gitignore b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/.gitignore new file mode 100644 index 000000000..4d29575de --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/README.md b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/README.md new file mode 100644 index 000000000..b87cb0044 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/README.md @@ -0,0 +1,46 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/config-overrides.js b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/config-overrides.js new file mode 100644 index 000000000..b6c6cd617 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/config-overrides.js @@ -0,0 +1,45 @@ +const path = require('path'); +const webpack = require('webpack'); + +module.exports = function override(config) { + const alias = config.resolve.alias || {}; + Object.assign(alias, { + 'fs-extra': path.resolve(__dirname, 'src/polyfills/fs-extra.js'), + }); + config.resolve.alias = alias; + const fallback = config.resolve.fallback || {}; + Object.assign(fallback, { + path: require.resolve('path-browserify'), + os: require.resolve('os-browserify/browser'), + stream: require.resolve('stream-browserify'), + crypto: require.resolve('crypto-browserify'), + assert: require.resolve('assert'), + 'fs-extra': false, + vm: false, + fs: false, + module: false, + constants: false, + }); + config.resolve.fallback = fallback; + config.plugins = (config.plugins || []).concat([ + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + }), + new webpack.ProvidePlugin({ + process: 'process/browser', + }), + new webpack.ProvidePlugin({ + 'process.hrtime': [path.resolve(__dirname, 'src/polyfills/process-shim.js'), 'default'], + }), + ]); + config.ignoreWarnings = [/Failed to parse source map/]; + config.module.rules.push({ + test: /\.(js|mjs|jsx)$/, + enforce: 'pre', + loader: require.resolve('source-map-loader'), + resolve: { + fullySpecified: false, + }, + }); + return config; +}; diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress.config.ts b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress.config.ts new file mode 100644 index 000000000..7d1177565 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'cypress'; + +process.env.NODE_ENV = 'test'; +process.env.BABEL_ENV = 'test'; +require('react-app-rewired/config/webpack.config')('development'); +export default defineConfig({ + component: { + devServer: { + framework: 'create-react-app', + bundler: 'webpack', + }, + }, +}); diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/commands.ts b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/commands.ts new file mode 100644 index 000000000..5fcc9d052 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/commands.ts @@ -0,0 +1,2 @@ +/// +// This file needs to exist for cypress tests to function diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/component-index.html b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/component-index.html new file mode 100644 index 000000000..ac6e79fd8 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/component.ts b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/component.ts new file mode 100644 index 000000000..37f59edbe --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/cypress/support/component.ts @@ -0,0 +1,39 @@ +// *********************************************************** +// This example support/component.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') + +import { mount } from 'cypress/react18' + +// Augment the Cypress namespace to include type definitions for +// your custom command. +// Alternatively, can be defined in cypress/support/component.d.ts +// with a at the top of your spec. +declare global { + namespace Cypress { + interface Chainable { + mount: typeof mount + } + } +} + +Cypress.Commands.add('mount', mount) + +// Example use: +// cy.mount() \ No newline at end of file diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/package.json b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/package.json new file mode 100644 index 000000000..76b5c1993 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/package.json @@ -0,0 +1,54 @@ +{ + "name": "graphql-generator-app", + "version": "0.1.0", + "private": true, + "dependencies": { + "@aws-amplify/appsync-modelgen-plugin": "file:../../../appsync-modelgen-plugin", + "@aws-amplify/graphql-generator": "file:../../../graphql-generator", + "@testing-library/jest-dom": "^5.17.0", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "@types/jest": "^27.5.2", + "@types/node": "^16.18.91", + "@types/react": "^18.2.67", + "@types/react-dom": "^18.2.22", + "assert": "^2.1.0", + "crypto-browserify": "^3.12.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "typescript": "^4.9.5", + "web-vitals": "^2.1.4" + }, + "scripts": { + "start": "react-app-rewired start", + "build": "react-app-rewired build", + "test": "react-app-rewired test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "cypress": "^13.7.1", + "react-app-rewired": "^2.2.1" + } +} diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/public/index.html b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/public/index.html new file mode 100644 index 000000000..61b3c249d --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/public/index.html @@ -0,0 +1,40 @@ + + + + + + + + + + React App + + + +
+ + + diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/App.cy.js b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/App.cy.js new file mode 100644 index 000000000..a3b308e97 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/App.cy.js @@ -0,0 +1,23 @@ +import React from 'react'; +import App from './App'; + +describe('graphql-generator does not crash in browser', () => { + beforeEach(() => { + cy.mount(); + }); + + const testCases = [ + 'generate-models-java', + 'generate-models-javascript', + 'generate-models-typescript', + 'generate-models-dart', + 'generate-models-introspection', + ]; + + testCases.forEach(testCase => { + it(testCase, {}, () => { + cy.get(`#${testCase}_button`).click(); + cy.get(`#${testCase}_result`).contains('✅', { timeout: 5000 }); + }); + }); +}); diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/App.tsx b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/App.tsx new file mode 100644 index 000000000..1a47018da --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/App.tsx @@ -0,0 +1,46 @@ +import React, { useState } from 'react'; +import { GeneratedOutput } from '@aws-amplify/graphql-generator'; +import testCases from './testCases'; + +function TestCase({ + test, + id, +}: { + test: () => Promise; + id: string; +}) { + const [result, setResult] = useState(false); + const [started, setStarted] = useState(false); + const [output, setOutput] = useState({}); + return ( +
+ + {!started ? '⌛' : result ? '✅' : '❌'} + {JSON.stringify(output)} +
+ ); +} + +function App() { + return ( +
+ {testCases.map((testCase) => )} +
+ ); +} + +export default App; diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/index.tsx b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/index.tsx new file mode 100644 index 000000000..3bdfecac5 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/index.tsx @@ -0,0 +1,14 @@ +/* eslint-disable import/first */ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); +root.render( + + + +); diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/polyfills/fs-extra.js b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/polyfills/fs-extra.js new file mode 100644 index 000000000..3c70ae70e --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/polyfills/fs-extra.js @@ -0,0 +1,18 @@ +/* eslint-disable */ +// @ts-nocheck + +module.exports = new Proxy( + {}, + { + get: (target, prop) => { + if (prop in target) { + return target[prop]; + } + + console.warn(`Attempted to call fs-extra.${String(prop)}, which is not supported in the browser.`); + return () => { + throw new Error(`fs-extra.${String(prop)} is not supported in the browser.`); + }; + }, + }, +); diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/polyfills/process-shim.js b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/polyfills/process-shim.js new file mode 100644 index 000000000..c20f2c1f8 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/polyfills/process-shim.js @@ -0,0 +1,28 @@ +// polyfil for window.performance.now + +const performanceNow = function() { + return new Date().getTime(); +}; + +// generate timestamp or delta +// see http://nodejs.org/api/process.html#process_process_hrtime +/** + * @param {number[]} previousTimestamp + */ +export default function hrtime(previousTimestamp) { + const clocktime = performanceNow.call(performance) * 1e-3; + let seconds = Math.floor(clocktime); + let nanoseconds = Math.floor((clocktime % 1) * 1e9); + + if (previousTimestamp) { + seconds = seconds - previousTimestamp[0]; + nanoseconds = nanoseconds - previousTimestamp[1]; + + if (nanoseconds < 0) { + seconds--; + nanoseconds += 1e9; + } + } + + return [seconds, nanoseconds]; +} diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/schemas.ts b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/schemas.ts new file mode 100644 index 000000000..bae16a584 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/schemas.ts @@ -0,0 +1,20 @@ +export const modelSchema = ` + type Blog @model { + id: ID! + name: String! + posts: [Post] @hasMany + } + + type Post @model { + id: ID! + title: String! + blog: Blog @belongsTo + comments: [Comment] @hasMany + } + + type Comment @model { + id: ID! + post: Post @belongsTo + content: String! + } +`; diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/testCases.ts b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/testCases.ts new file mode 100644 index 000000000..8877af444 --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/src/testCases.ts @@ -0,0 +1,40 @@ +import { modelSchema } from './schemas'; +import { generateModels, GeneratedOutput, ModelsTarget } from '@aws-amplify/graphql-generator'; + +const generateModelForTarget = async (target: ModelsTarget) => { + const options = { + schema: modelSchema, + target, + directives: '', + }; + return await generateModels(options); +}; + +const testCases: { id: string; test: () => Promise }[] = [ + { + id: 'generate-models-java', + test: () => generateModelForTarget('java'), + }, + { + id: 'generate-models-swift', + test: () => generateModelForTarget('swift'), + }, + { + id: 'generate-models-javascript', + test: () => generateModelForTarget('javascript'), + }, + { + id: 'generate-models-typescript', + test: () => generateModelForTarget('typescript'), + }, + { + id: 'generate-models-dart', + test: () => generateModelForTarget('dart'), + }, + { + id: 'generate-models-introspection', + test: () => generateModelForTarget('introspection'), + }, +]; + +export default testCases; diff --git a/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/tsconfig.json b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/tsconfig.json new file mode 100644 index 000000000..a273b0cfc --- /dev/null +++ b/packages/amplify-codegen-e2e-tests/test-apps/graphql-generator-app/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} diff --git a/packages/amplify-codegen/src/codegen-config/AmplifyCodeGenConfig.js b/packages/amplify-codegen/src/codegen-config/AmplifyCodeGenConfig.js index 7b8886570..81f7cf8ad 100644 --- a/packages/amplify-codegen/src/codegen-config/AmplifyCodeGenConfig.js +++ b/packages/amplify-codegen/src/codegen-config/AmplifyCodeGenConfig.js @@ -47,8 +47,9 @@ class AmplifyCodeGenConfig { } // Set schemaPath to use posix separators. Node can handle windows and posix separators regradless of platform // Ensures all paths in .graphlqconfig.yml use posix style + // Fallback to \ because path.win32 is not implemented by path-browserify const schemaPath = (isAbsolute(project.schema) ? relative(this.gqlConfig.configDir, project.schema) : project.schema) - .split(path.win32.sep) + .split(path.win32?.sep || '\\') .join(path.posix.sep); const newProject = { schemaPath, diff --git a/packages/amplify-codegen/src/commands/add.js b/packages/amplify-codegen/src/commands/add.js index 26ddb3f88..fc396fc7a 100644 --- a/packages/amplify-codegen/src/commands/add.js +++ b/packages/amplify-codegen/src/commands/add.js @@ -136,7 +136,8 @@ async function add(context, apiId = null, region = 'us-east-1') { excludes: [...answer.excludePattern, answer.generatedFileName]?.filter(item => item), // Set schema path to use posix separators. Node can handle windows and posix separators regradless of platform // Ensures all paths in .graphlqconfig.yml use posix style - schema: schema.split(path.win32.sep).join(path.posix.sep), + // Fallback to \ because path.win32 is not implemented by path-browserify + schema: schema.split(path.win32?.sep || '\\').join(path.posix.sep), amplifyExtension: { codeGenTarget: answer.target || '', generatedFileName: answer.generatedFileName || '', diff --git a/packages/amplify-codegen/src/utils/getRelativeTypesPath.js b/packages/amplify-codegen/src/utils/getRelativeTypesPath.js index 7d8a406bc..8b32a8db5 100644 --- a/packages/amplify-codegen/src/utils/getRelativeTypesPath.js +++ b/packages/amplify-codegen/src/utils/getRelativeTypesPath.js @@ -5,7 +5,8 @@ function getRelativeTypesPath(opsGenDirectory, generatedFileName) { const relativePath = path .relative(opsGenDirectory, generatedFileName) // ensure posix path separators are used - .split(path.win32.sep) + // Fallback to \ because path.win32 is not implemented by path-browserify + .split(path.win32?.sep || '\\') .join(path.posix.sep); // generatedFileName is in same directory as opsGenDirectory diff --git a/packages/amplify-codegen/src/utils/input-params-manager.js b/packages/amplify-codegen/src/utils/input-params-manager.js index b16cedb92..27335a7e1 100644 --- a/packages/amplify-codegen/src/utils/input-params-manager.js +++ b/packages/amplify-codegen/src/utils/input-params-manager.js @@ -68,7 +68,9 @@ function normalizeValue(key, value) { } function normalizePathForGlobPattern(pattern) { - const splits = pattern.split(path.win32.sep); + // ensure posix path separators are used + // Fallback to \ because path.win32 is not implemented by path-browserify + const splits = pattern.split(path.win32?.sep || '\\'); return splits.join(path.posix.sep); } diff --git a/packages/appsync-modelgen-plugin/schemas/introspection/1/ModelIntrospectionSchema.json b/packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json similarity index 100% rename from packages/appsync-modelgen-plugin/schemas/introspection/1/ModelIntrospectionSchema.json rename to packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json diff --git a/packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts b/packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts index 9b1e645de..e58672743 100644 --- a/packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts +++ b/packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts @@ -4,9 +4,9 @@ import { Argument, AssociationType, Field, Fields, FieldType, ModelAttribute, Mo import { METADATA_SCALAR_MAP } from "../scalars"; import { CodeGenConnectionType } from "../utils/process-connections"; import { RawAppSyncModelConfig, ParsedAppSyncModelConfig, AppSyncModelVisitor, CodeGenEnum, CodeGenField, CodeGenModel, CodeGenPrimaryKeyType, CodeGenQuery, CodeGenSubscription, CodeGenMutation } from "./appsync-visitor"; -import fs from 'fs'; import path from 'path'; import Ajv from 'ajv'; +import modelIntrospectionSchema from '../schemas/introspection/1/ModelIntrospectionSchema.json'; export interface RawAppSyncModelIntrospectionConfig extends RawAppSyncModelConfig {}; export interface ParsedAppSyncModelIntrospectionConfig extends ParsedAppSyncModelConfig {}; @@ -23,8 +23,6 @@ export class AppSyncModelIntrospectionVisitor< defaultScalars: NormalizedScalarsMap = DEFAULT_SCALARS, ) { super(schema, rawConfig, additionalConfig, defaultScalars); - const modelIntrospectionSchemaText = fs.readFileSync(path.join(__dirname, '..', '..', 'schemas', 'introspection', this.introspectionVersion.toString(), 'ModelIntrospectionSchema.json'), 'utf8'); - const modelIntrospectionSchema = JSON.parse(modelIntrospectionSchemaText); this.schemaValidator = new Ajv().compile(modelIntrospectionSchema); } @@ -213,4 +211,4 @@ export class AppSyncModelIntrospectionVisitor< } throw new Error(`No primary key found for model ${model.name}`); } -} \ No newline at end of file +} diff --git a/packages/appsync-modelgen-plugin/tsconfig.json b/packages/appsync-modelgen-plugin/tsconfig.json index 965e8efcc..c43fd6202 100644 --- a/packages/appsync-modelgen-plugin/tsconfig.json +++ b/packages/appsync-modelgen-plugin/tsconfig.json @@ -4,9 +4,12 @@ "rootDir": "src", "outDir": "lib" }, + "include": [ + "src/**/*", + "src/schemas/**/*.json" + ], "exclude": [ "scripts", - "schemas", "lib", "src/__tests__" ] diff --git a/packages/graphql-generator/src/models.ts b/packages/graphql-generator/src/models.ts index 17106fba9..8723bb54c 100644 --- a/packages/graphql-generator/src/models.ts +++ b/packages/graphql-generator/src/models.ts @@ -66,7 +66,8 @@ export async function generateModels(options: GenerateModelsOptions): Promise outputs.reduce((curr, next) => ({ ...curr, ...next }), {})); } diff --git a/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts b/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts index 9293f226c..995c61a8e 100644 --- a/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts +++ b/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts @@ -38,7 +38,8 @@ export class GraphQLStatementsFormatter { if (typesPath) { const { dir, name } = path.parse(typesPath); // ensure posix path separators are used - const typesPathWithoutExtension = path.join(dir, name).split(path.win32.sep).join(path.posix.sep); + // Fallback to \ because path.win32 is not implemented by path-browserify + const typesPathWithoutExtension = path.join(dir, name).split(path.win32?.sep || '\\').join(path.posix.sep); if (!typesPathWithoutExtension.startsWith('.')) { // path.join will strip prefixed ./ this.typesPath = `./${typesPathWithoutExtension}`; diff --git a/packages/graphql-types-generator/src/utilities/getOutputFileName.ts b/packages/graphql-types-generator/src/utilities/getOutputFileName.ts index 517cfae00..408ac2f9d 100644 --- a/packages/graphql-types-generator/src/utilities/getOutputFileName.ts +++ b/packages/graphql-types-generator/src/utilities/getOutputFileName.ts @@ -10,7 +10,8 @@ export function getOutputFileName(inputFileName: string, target: Target): string const baseName = inputFileName.substr(0, inputFileName.length - ext.length); const filename = inputFileName.includes(fileExtension) ? inputFileName : `${baseName}.${fileExtension}`; // ensure the filepath for the types file uses posix separators - return ['API', 'api'].includes(inputFileName) ? path.join(folderMap[target], filename).split(path.win32.sep).join(path.posix.sep) : filename; + // Fallback to \ because path.win32 is not implemented by path-browserify + return ['API', 'api'].includes(inputFileName) ? path.join(folderMap[target], filename).split(path.win32?.sep || '\\').join(path.posix.sep) : filename; } return inputFileName; } From a6efa72cd3345d52b43bd4754af0826351930bfb Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Thu, 11 Apr 2024 10:23:44 -0600 Subject: [PATCH 2/8] feat: set correct association with references (#793) --- .../utils/process-connections-v2.test.ts | 7 + ...c-model-introspection-visitor.test.ts.snap | 870 +++++++++++++++++- ...ppsync-model-introspection-visitor.test.ts | 255 +++++ .../visitors/appsync-visitor.test.ts | 33 + .../1/ModelIntrospectionSchema.json | 3 +- .../src/utils/process-belongs-to.ts | 16 +- .../src/utils/process-connections-v2.ts | 36 +- .../src/utils/process-connections.ts | 6 +- .../src/utils/process-has-many.ts | 21 +- .../src/utils/process-has-one.ts | 24 +- .../src/visitors/appsync-java-visitor.ts | 2 +- .../src/visitors/appsync-swift-visitor.ts | 4 +- .../src/visitors/appsync-visitor.ts | 18 +- 13 files changed, 1247 insertions(+), 48 deletions(-) diff --git a/packages/appsync-modelgen-plugin/src/__tests__/utils/process-connections-v2.test.ts b/packages/appsync-modelgen-plugin/src/__tests__/utils/process-connections-v2.test.ts index 4f8fb7d72..77c649ba6 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/utils/process-connections-v2.test.ts +++ b/packages/appsync-modelgen-plugin/src/__tests__/utils/process-connections-v2.test.ts @@ -710,6 +710,7 @@ describe('Connection process with custom Primary Key support tests', () => { targetNames: ['teamProjectProjectId', 'teamProjectName'], connectedModel: project, isConnectingFieldAutoCreated: false, + isUsingReferences: false, }); }); }); @@ -787,6 +788,7 @@ describe('Connection process with custom Primary Key support tests', () => { targetNames: ["postCommentsPostId", "postCommentsTitle"], connectedModel: post, isConnectingFieldAutoCreated: false, + isUsingReferences: false, }); }); it('should return correct connection info in hasMany/belongsTo bi direction when in JS platforms', () => { @@ -837,6 +839,7 @@ describe('Connection process with custom Primary Key support tests', () => { targetNames: ["postCommentsPostId", "postCommentsTitle"], connectedModel: post, isConnectingFieldAutoCreated: false, + isUsingReferences: false, }); }); it('should return correct connection info in hasMany/belongsTo bi direction when index is defined', () => { @@ -874,6 +877,7 @@ describe('Connection process with custom Primary Key support tests', () => { targetNames: ["postId", "postTitle"], connectedModel: post, isConnectingFieldAutoCreated: false, + isUsingReferences: false, }); }); it('should return correct connection info in hasMany uni direction when index is defined', () => { @@ -954,6 +958,7 @@ describe('Connection process with custom Primary Key support tests', () => { targetNames: ['teamProjectProjectId', 'teamProjectName'], connectedModel: project, isConnectingFieldAutoCreated: false, + isUsingReferences: false, }); }); @@ -993,6 +998,7 @@ describe('Connection process with custom Primary Key support tests', () => { targetNames: ['compositeDogCompositeOwnerLastName', 'compositeDogCompositeOwnerFirstName'], connectedModel: compositeOwner, isConnectingFieldAutoCreated: false, + isUsingReferences: false, }); }); @@ -1032,6 +1038,7 @@ describe('Connection process with custom Primary Key support tests', () => { targetNames: ['boringDogBoringOwnerId'], connectedModel: boringOwner, isConnectingFieldAutoCreated: false, + isUsingReferences: false, }); }); }) diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap index e7fd2efee..2efe4ed99 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap @@ -3402,7 +3402,7 @@ exports[`custom fields sets the association for fields for hasMany 1`] = ` }" `; -exports[`custom fields sets the association for fields for hasMany and belongsTo 1`] = ` +exports[`custom fields sets the association for fields for hasOne 1`] = ` "{ \\"version\\": 1, \\"models\\": { @@ -3425,17 +3425,19 @@ exports[`custom fields sets the association for fields for hasMany and belongsTo }, \\"related\\": { \\"name\\": \\"related\\", - \\"isArray\\": true, + \\"isArray\\": false, \\"type\\": { \\"model\\": \\"RelatedLegacy\\" }, \\"isRequired\\": false, \\"attributes\\": [], - \\"isArrayNullable\\": true, \\"association\\": { - \\"connectionType\\": \\"HAS_MANY\\", + \\"connectionType\\": \\"HAS_ONE\\", \\"associatedWith\\": [ \\"primary\\" + ], + \\"targetNames\\": [ + \\"relatedId\\" ] } }, @@ -3491,7 +3493,7 @@ exports[`custom fields sets the association for fields for hasMany and belongsTo \\"association\\": { \\"connectionType\\": \\"BELONGS_TO\\", \\"targetNames\\": [ - \\"primaryId\\" + \\"relatedLegacyPrimaryId\\" ] } }, @@ -3532,7 +3534,7 @@ exports[`custom fields sets the association for fields for hasMany and belongsTo }" `; -exports[`custom fields sets the association for fields for hasOne 1`] = ` +exports[`custom fields sets the association for fields for hasOne and belongsTo 1`] = ` "{ \\"version\\": 1, \\"models\\": { @@ -3623,7 +3625,7 @@ exports[`custom fields sets the association for fields for hasOne 1`] = ` \\"association\\": { \\"connectionType\\": \\"BELONGS_TO\\", \\"targetNames\\": [ - \\"relatedLegacyPrimaryId\\" + \\"primaryId\\" ] } }, @@ -3664,12 +3666,12 @@ exports[`custom fields sets the association for fields for hasOne 1`] = ` }" `; -exports[`custom fields sets the association for fields for hasOne and belongsTo 1`] = ` +exports[`custom references double linked references 1`] = ` "{ \\"version\\": 1, \\"models\\": { - \\"PrimaryLegacy\\": { - \\"name\\": \\"PrimaryLegacy\\", + \\"Foo\\": { + \\"name\\": \\"Foo\\", \\"fields\\": { \\"id\\": { \\"name\\": \\"id\\", @@ -3678,28 +3680,118 @@ exports[`custom fields sets the association for fields for hasOne and belongsTo \\"isRequired\\": true, \\"attributes\\": [] }, - \\"relatedId\\": { - \\"name\\": \\"relatedId\\", + \\"bar1\\": { + \\"name\\": \\"bar1\\", \\"isArray\\": false, - \\"type\\": \\"ID\\", + \\"type\\": { + \\"model\\": \\"Bar\\" + }, \\"isRequired\\": false, - \\"attributes\\": [] + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"HAS_ONE\\", + \\"associatedWith\\": [ + \\"bar1Id\\" + ] + } }, - \\"related\\": { - \\"name\\": \\"related\\", + \\"bar2\\": { + \\"name\\": \\"bar2\\", \\"isArray\\": false, \\"type\\": { - \\"model\\": \\"RelatedLegacy\\" + \\"model\\": \\"Bar\\" }, \\"isRequired\\": false, \\"attributes\\": [], \\"association\\": { \\"connectionType\\": \\"HAS_ONE\\", \\"associatedWith\\": [ - \\"primary\\" - ], + \\"bar2Id\\" + ] + } + }, + \\"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\\": \\"Foos\\", + \\"attributes\\": [ + { + \\"type\\": \\"model\\", + \\"properties\\": {} + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + }, + \\"Bar\\": { + \\"name\\": \\"Bar\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"bar1Id\\": { + \\"name\\": \\"bar1Id\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"bar2Id\\": { + \\"name\\": \\"bar2Id\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"foo1\\": { + \\"name\\": \\"foo1\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"Foo\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"BELONGS_TO\\", \\"targetNames\\": [ - \\"relatedId\\" + \\"bar1Id\\" + ] + } + }, + \\"foo2\\": { + \\"name\\": \\"foo2\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"Foo\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"BELONGS_TO\\", + \\"targetNames\\": [ + \\"bar2Id\\" ] } }, @@ -3721,7 +3813,7 @@ exports[`custom fields sets the association for fields for hasOne and belongsTo } }, \\"syncable\\": true, - \\"pluralName\\": \\"PrimaryLegacies\\", + \\"pluralName\\": \\"Bars\\", \\"attributes\\": [ { \\"type\\": \\"model\\", @@ -3733,9 +3825,112 @@ exports[`custom fields sets the association for fields for hasOne and belongsTo \\"primaryKeyFieldName\\": \\"id\\", \\"sortKeyFieldNames\\": [] } + } + }, + \\"enums\\": {}, + \\"nonModels\\": {} +}" +`; + +exports[`custom references hasMany with sortKeyFields on primary key 1`] = ` +"{ + \\"version\\": 1, + \\"models\\": { + \\"Primary\\": { + \\"name\\": \\"Primary\\", + \\"fields\\": { + \\"tenantId\\": { + \\"name\\": \\"tenantId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"instanceId\\": { + \\"name\\": \\"instanceId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"recordId\\": { + \\"name\\": \\"recordId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"content\\": { + \\"name\\": \\"content\\", + \\"isArray\\": false, + \\"type\\": \\"String\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"related\\": { + \\"name\\": \\"related\\", + \\"isArray\\": true, + \\"type\\": { + \\"model\\": \\"Related\\" + }, + \\"isRequired\\": true, + \\"attributes\\": [], + \\"isArrayNullable\\": true, + \\"association\\": { + \\"connectionType\\": \\"HAS_MANY\\", + \\"associatedWith\\": [ + \\"primaryTenantId\\", + \\"primaryInstanceId\\", + \\"primaryRecordId\\" + ] + } + }, + \\"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\\": \\"Primaries\\", + \\"attributes\\": [ + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"tenantId\\", + \\"instanceId\\", + \\"recordId\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": true, + \\"primaryKeyFieldName\\": \\"tenantId\\", + \\"sortKeyFieldNames\\": [ + \\"instanceId\\", + \\"recordId\\" + ] + } }, - \\"RelatedLegacy\\": { - \\"name\\": \\"RelatedLegacy\\", + \\"Related\\": { + \\"name\\": \\"Related\\", \\"fields\\": { \\"id\\": { \\"name\\": \\"id\\", @@ -3744,18 +3939,48 @@ exports[`custom fields sets the association for fields for hasOne and belongsTo \\"isRequired\\": true, \\"attributes\\": [] }, + \\"content\\": { + \\"name\\": \\"content\\", + \\"isArray\\": false, + \\"type\\": \\"String\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"primaryTenantId\\": { + \\"name\\": \\"primaryTenantId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primaryInstanceId\\": { + \\"name\\": \\"primaryInstanceId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primaryRecordId\\": { + \\"name\\": \\"primaryRecordId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, \\"primary\\": { \\"name\\": \\"primary\\", \\"isArray\\": false, \\"type\\": { - \\"model\\": \\"PrimaryLegacy\\" + \\"model\\": \\"Primary\\" }, \\"isRequired\\": false, \\"attributes\\": [], \\"association\\": { \\"connectionType\\": \\"BELONGS_TO\\", \\"targetNames\\": [ - \\"primaryId\\" + \\"primaryTenantId\\", + \\"primaryInstanceId\\", + \\"primaryRecordId\\" ] } }, @@ -3777,7 +4002,7 @@ exports[`custom fields sets the association for fields for hasOne and belongsTo } }, \\"syncable\\": true, - \\"pluralName\\": \\"RelatedLegacies\\", + \\"pluralName\\": \\"Relateds\\", \\"attributes\\": [ { \\"type\\": \\"model\\", @@ -3796,6 +4021,599 @@ exports[`custom fields sets the association for fields for hasOne and belongsTo }" `; +exports[`custom references sets the association to the references field for hasMany/belongsTo 1`] = ` +"{ + \\"version\\": 1, + \\"models\\": { + \\"SqlPrimary\\": { + \\"name\\": \\"SqlPrimary\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"Int\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"content\\": { + \\"name\\": \\"content\\", + \\"isArray\\": false, + \\"type\\": \\"String\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"related\\": { + \\"name\\": \\"related\\", + \\"isArray\\": true, + \\"type\\": { + \\"model\\": \\"SqlRelated\\" + }, + \\"isRequired\\": true, + \\"attributes\\": [], + \\"isArrayNullable\\": true, + \\"association\\": { + \\"connectionType\\": \\"HAS_MANY\\", + \\"associatedWith\\": [ + \\"primaryId\\" + ] + } + }, + \\"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\\": \\"SqlPrimaries\\", + \\"attributes\\": [ + { + \\"type\\": \\"refersTo\\", + \\"properties\\": { + \\"name\\": \\"sql_primary\\" + } + }, + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"id\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + }, + \\"SqlRelated\\": { + \\"name\\": \\"SqlRelated\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"Int\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"content\\": { + \\"name\\": \\"content\\", + \\"isArray\\": false, + \\"type\\": \\"String\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"primaryId\\": { + \\"name\\": \\"primaryId\\", + \\"isArray\\": false, + \\"type\\": \\"Int\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primary\\": { + \\"name\\": \\"primary\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"SqlPrimary\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"BELONGS_TO\\", + \\"targetNames\\": [ + \\"primaryId\\" + ] + } + }, + \\"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\\": \\"SqlRelateds\\", + \\"attributes\\": [ + { + \\"type\\": \\"refersTo\\", + \\"properties\\": { + \\"name\\": \\"sql_related\\" + } + }, + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"id\\" + ] + } + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"name\\": \\"primary_id\\", + \\"fields\\": [ + \\"primaryId\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + } + }, + \\"enums\\": {}, + \\"nonModels\\": {} +}" +`; + +exports[`custom references sets the association to the references field for hasOne and hasMany 1`] = ` +"{ + \\"version\\": 1, + \\"models\\": { + \\"Primary\\": { + \\"name\\": \\"Primary\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"relatedMany\\": { + \\"name\\": \\"relatedMany\\", + \\"isArray\\": true, + \\"type\\": { + \\"model\\": \\"RelatedMany\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"isArrayNullable\\": true, + \\"association\\": { + \\"connectionType\\": \\"HAS_MANY\\", + \\"associatedWith\\": [ + \\"primaryId\\" + ] + } + }, + \\"relatedOne\\": { + \\"name\\": \\"relatedOne\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"RelatedOne\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"HAS_ONE\\", + \\"associatedWith\\": [ + \\"primaryId\\" + ] + } + }, + \\"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\\": \\"Primaries\\", + \\"attributes\\": [ + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"id\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + }, + \\"RelatedMany\\": { + \\"name\\": \\"RelatedMany\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primaryId\\": { + \\"name\\": \\"primaryId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primary\\": { + \\"name\\": \\"primary\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"Primary\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"BELONGS_TO\\", + \\"targetNames\\": [ + \\"primaryId\\" + ] + } + }, + \\"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\\": \\"RelatedManies\\", + \\"attributes\\": [ + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"id\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + }, + \\"RelatedOne\\": { + \\"name\\": \\"RelatedOne\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primaryId\\": { + \\"name\\": \\"primaryId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primary\\": { + \\"name\\": \\"primary\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"Primary\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"BELONGS_TO\\", + \\"targetNames\\": [ + \\"primaryId\\" + ] + } + }, + \\"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\\": \\"RelatedOnes\\", + \\"attributes\\": [ + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"id\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + } + }, + \\"enums\\": {}, + \\"nonModels\\": {} +}" +`; + +exports[`custom references sets the association to the references field for hasOne/belongsTo 1`] = ` +"{ + \\"version\\": 1, + \\"models\\": { + \\"SqlPrimary\\": { + \\"name\\": \\"SqlPrimary\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"Int\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"content\\": { + \\"name\\": \\"content\\", + \\"isArray\\": false, + \\"type\\": \\"String\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"related\\": { + \\"name\\": \\"related\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"SqlRelated\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"HAS_ONE\\", + \\"associatedWith\\": [ + \\"primaryId\\" + ] + } + }, + \\"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\\": \\"SqlPrimaries\\", + \\"attributes\\": [ + { + \\"type\\": \\"refersTo\\", + \\"properties\\": { + \\"name\\": \\"sql_primary\\" + } + }, + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"id\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + }, + \\"SqlRelated\\": { + \\"name\\": \\"SqlRelated\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"Int\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"content\\": { + \\"name\\": \\"content\\", + \\"isArray\\": false, + \\"type\\": \\"String\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"primaryId\\": { + \\"name\\": \\"primaryId\\", + \\"isArray\\": false, + \\"type\\": \\"Int\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primary\\": { + \\"name\\": \\"primary\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"SqlPrimary\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"BELONGS_TO\\", + \\"targetNames\\": [ + \\"primaryId\\" + ] + } + }, + \\"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\\": \\"SqlRelateds\\", + \\"attributes\\": [ + { + \\"type\\": \\"refersTo\\", + \\"properties\\": { + \\"name\\": \\"sql_related\\" + } + }, + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"id\\" + ] + } + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"name\\": \\"primary_id\\", + \\"fields\\": [ + \\"primaryId\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + } + }, + \\"enums\\": {}, + \\"nonModels\\": {} +}" +`; + exports[`schemas with pk on a belongsTo fk works for v1 1`] = ` "{ \\"version\\": 1, diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-model-introspection-visitor.test.ts b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-model-introspection-visitor.test.ts index 98c2423d6..329276ecf 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-model-introspection-visitor.test.ts +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-model-introspection-visitor.test.ts @@ -503,7 +503,262 @@ describe('custom fields', () => { primary: PrimaryLegacy @belongsTo(fields: [primaryId]) } `; + }); +}); + +describe('custom references', () => { + test('sets the association to the references field for hasMany/belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: [SqlRelated!] @hasMany(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(visitor.generate()).toMatchSnapshot(); + }); + + test('sets the association to the references field for hasOne/belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: SqlRelated @hasOne(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(visitor.generate()).toMatchSnapshot(); + }); + + test('sets the association to the references field for hasOne and hasMany', () => { + const schema = /* GraphQL */ ` + type Primary @model { + id: ID! @primaryKey + relatedMany: [RelatedMany] @hasMany(references: ["primaryId"]) + relatedOne: RelatedOne @hasOne(references: ["primaryId"]) + } + + type RelatedMany @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: ["primaryId"]) + } + + type RelatedOne @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: ["primaryId"]) + } + `; + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(visitor.generate()).toMatchSnapshot(); + }); + + test('double linked references', () => { + const schema = /* GraphQL */ ` + type Foo @model { + id: ID! + bar1: Bar @hasOne(references: ["bar1Id"]) + bar2: Bar @hasOne(references: ["bar2Id"]) + } + + type Bar @model { + id: ID! + bar1Id: ID + bar2Id: ID + foo1: Foo @belongsTo(references: ["bar1Id"]) + foo2: Foo @belongsTo(references: ["bar2Id"]) + } + `; + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); expect(visitor.generate()).toMatchSnapshot(); }); + + test('hasMany with sortKeyFields on primary key', () => { + const schema = /* GraphQL */ ` + type Primary @model { + tenantId: ID! @primaryKey(sortKeyFields: ["instanceId", "recordId"]) + instanceId: ID! + recordId: ID! + content: String + related: [Related!] @hasMany(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + + type Related @model { + content: String + primaryTenantId: ID! + primaryInstanceId: ID! + primaryRecordId: ID! + primary: Primary @belongsTo(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(visitor.generate()).toMatchSnapshot(); + }); + + test('throws error when using fields and references on hasMany', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: [SqlRelated!] @hasMany(references: ["primaryId"], fields: ["content"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(() => visitor.generate()) + .toThrowError(`'fields' and 'references' cannot be used together.`); + }); + + test('throws error when using fields and references on belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: [SqlRelated!] @hasMany(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"], fields: ["content"]) + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(() => visitor.generate()) + .toThrowError(`'fields' and 'references' cannot be used together.`); + }); + + test('throws error when using fields and references on hasOne', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: SqlRelated @hasOne(references: ["primaryId"], fields: ["content"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(() => visitor.generate()) + .toThrowError(`'fields' and 'references' cannot be used together.`); + }); + + test('throws error when missing references on hasOne related model', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: SqlRelated @hasOne(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(() => visitor.generate()) + .toThrowError(`Error processing @hasOne directive on SqlPrimary.related. @belongsTo directive with references ["primaryId"] was not found in connected model SqlRelated`); + }); + + test('throws error when missing references on hasOne primary model', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: SqlRelated @hasOne + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(() => visitor.generate()) + .toThrowError(`Error processing @belongsTo directive on SqlRelated.primary. @hasOne or @hasMany directive with references ["primaryId"] was not found in connected model SqlPrimary`); + }); + + test('throws error when missing references on hasMany related model', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: [SqlRelated] @hasMany(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(() => visitor.generate()) + .toThrowError(`Error processing @hasMany directive on SqlPrimary.related. @belongsTo directive with references ["primaryId"] was not found in connected model SqlRelated`); + }); + + test('throws error when missing references on hasMany primary model', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: [SqlRelated] @hasMany + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(() => visitor.generate()) + .toThrowError(`Error processing @belongsTo directive on SqlRelated.primary. @hasOne or @hasMany directive with references ["primaryId"] was not found in connected model SqlPrimary`); + }); }); diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-visitor.test.ts b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-visitor.test.ts index 2f5fedc0e..e0a16d333 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-visitor.test.ts +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-visitor.test.ts @@ -1410,4 +1410,37 @@ describe('AppSyncModelVisitor', () => { expect(interfaces).toMatchSnapshot(); }); }) + + describe('references field on hasOne, hasMany, and belongsTo directive', () => { + test('converts string argument to list of string', () => { + const schema = /* GraphQL */ ` + type Primary @model { + id: ID! @primaryKey + relatedMany: [RelatedMany] @hasMany(references: "primaryId") + relatedOne: RelatedOne @hasOne(references: "primaryId") + } + + type RelatedMany @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: "primaryId") + } + + type RelatedOne @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: "primaryId") + } + `; + const ast = parse(schema); + const stringDirectives = DefaultDirectives.map(directive => directive.definition).join('\n'); + const builtSchema = buildSchemaWithDirectives(schema, stringDirectives); + const visitor = new AppSyncModelVisitor(builtSchema, { directives: stringDirectives, target: 'android', generate: CodeGenGenerateEnum.code }, {}); + visit(ast, { leave: visitor }); + expect(visitor.models.Primary.fields[1].directives[0].arguments).toEqual({ references: ['primaryId'] }); + expect(visitor.models.Primary.fields[2].directives[0].arguments).toEqual({ references: ['primaryId'] }); + expect(visitor.models.RelatedMany.fields[2].directives[0].arguments).toEqual({ references: ['primaryId'] }); + expect(visitor.models.RelatedOne.fields[2].directives[0].arguments).toEqual({ references: ['primaryId'] }); + }); + }); }); diff --git a/packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json b/packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json index d92926be2..6b37c37bc 100644 --- a/packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json +++ b/packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json @@ -275,8 +275,7 @@ }, "required": [ "associatedWith", - "connectionType", - "targetNames" + "connectionType" ] }, "AssociationBelongsTo": { diff --git a/packages/appsync-modelgen-plugin/src/utils/process-belongs-to.ts b/packages/appsync-modelgen-plugin/src/utils/process-belongs-to.ts index 0d951f252..76cf7623a 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-belongs-to.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-belongs-to.ts @@ -6,7 +6,7 @@ import { flattenFieldDirectives, makeConnectionAttributeName, } from './process-connections'; -import { getConnectedFieldV2 } from './process-connections-v2'; +import { getConnectedFieldV2, fieldsAndReferencesErrorMessage } from './process-connections-v2'; export function processBelongsToConnection( @@ -31,14 +31,19 @@ export function processBelongsToConnection( const otherSideField = isCustomPKEnabled ? otherSideConnectedFields[0] : getConnectedFieldV2(field, model, otherSide, connectionDirective.name); const connectionFields = connectionDirective.arguments.fields || []; + const references = connectionDirective.arguments.references || []; + + if (connectionFields.length > 0 && references.length > 0) { + throw new Error(fieldsAndReferencesErrorMessage); + } // if a type is connected using name, then amplify-graphql-relational-transformer adds a field to // track the connection and that field is not part of the selection set // but if the field are connected using fields argument in connection directive // we are reusing the field and it should be preserved in selection set const otherSideHasMany = otherSideField.isList; - const isConnectingFieldAutoCreated = false; + const isUsingReferences = references.length > 0; // New metada type introduced by custom PK v2 support - let targetNames: string[] = [ ...connectionFields ]; + let targetNames: string[] = [ ...connectionFields, ...references ]; if (targetNames.length === 0) { if (otherSideHasMany) { targetNames = isCustomPKEnabled @@ -55,9 +60,10 @@ export function processBelongsToConnection( return { kind: CodeGenConnectionType.BELONGS_TO, connectedModel: otherSide, - isConnectingFieldAutoCreated, + isConnectingFieldAutoCreated: false, targetName: targetNames[0], targetNames, + isUsingReferences, }; } @@ -76,4 +82,4 @@ export function getBelongsToConnectedFields(model: CodeGenModel, connectedModel: return otherSideDirectives.map(dir => { return connectedModel.fields.find(connField => connField.name === dir.fieldName)! }); -} \ No newline at end of file +} diff --git a/packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts b/packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts index ac6811285..851f541e3 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts @@ -20,8 +20,23 @@ export function getConnectedFieldV2( throw new Error(`The ${field.name} on model ${model.name} is not connected`); } + const references = connectionInfo.arguments.references; if (connectionInfo.name === 'belongsTo') { let connectedFieldsBelongsTo = getBelongsToConnectedFields(model, connectedModel); + if (references) { + const connectedField = connectedFieldsBelongsTo.find((field) => { + return field.directives.some((dir) => { + return (dir.name === 'hasOne' || dir.name === 'hasMany') + && dir.arguments.references + && JSON.stringify(dir.arguments.references) === JSON.stringify(connectionInfo.arguments.references); + }); + }); + if (!connectedField) { + throw new Error(`Error processing @belongsTo directive on ${model.name}.${field.name}. @hasOne or @hasMany directive with references ${JSON.stringify(connectionInfo.arguments?.references)} was not found in connected model ${connectedModel.name}`); + } + return connectedField; + } + if (connectedFieldsBelongsTo.length === 1) { return connectedFieldsBelongsTo[0]; } @@ -29,10 +44,25 @@ export function getConnectedFieldV2( const indexName = connectionInfo.arguments.indexName; const connectionFields = connectionInfo.arguments.fields; - if (connectionFields || directiveName === 'hasOne') { + if (connectionFields && references) { + throw new Error(fieldsAndReferencesErrorMessage); + } + if (references || connectionFields || directiveName === 'hasOne') { let connectionDirective; + if (references) { + if (connectionInfo) { + connectionDirective = flattenFieldDirectives(connectedModel).find((dir) => { + return dir.arguments.references + && JSON.stringify(dir.arguments.references) === JSON.stringify(connectionInfo.arguments.references); + }); + if (!connectionDirective) { + throw new Error(`Error processing @${connectionInfo.name} directive on ${model.name}.${field.name}. @belongsTo directive with references ${JSON.stringify(connectionInfo.arguments?.references)} was not found in connected model ${connectedModel.name}`); + } + } + } + // Find gsi on other side if index is defined - if (indexName) { + else if (indexName) { connectionDirective = flattenFieldDirectives(connectedModel).find(dir => { return dir.name === 'index' && dir.arguments.name === indexName; }); @@ -147,3 +177,5 @@ export function processConnectionsV2( } } } + +export const fieldsAndReferencesErrorMessage = `'fields' and 'references' cannot be used together.`; diff --git a/packages/appsync-modelgen-plugin/src/utils/process-connections.ts b/packages/appsync-modelgen-plugin/src/utils/process-connections.ts index 28e5fa26b..2ad12d3db 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-connections.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-connections.ts @@ -17,14 +17,14 @@ export type CodeGenFieldConnectionBelongsTo = CodeGenConnectionTypeBase & { kind: CodeGenConnectionType.BELONGS_TO; targetName: string; // Legacy field remained for backward compatability targetNames: string[]; // New attribute for v2 custom pk support - + isUsingReferences?: boolean; }; export type CodeGenFieldConnectionHasOne = CodeGenConnectionTypeBase & { kind: CodeGenConnectionType.HAS_ONE; associatedWith: CodeGenField;// Legacy field remained for backward compatability associatedWithFields: CodeGenField[]; // New attribute for v2 custom pk support - targetName: string; // Legacy field remained for backward compatability - targetNames: string[]; // New attribute for v2 custom pk support + targetName?: string; // Legacy field remained for backward compatability + targetNames?: string[]; // New attribute for v2 custom pk support }; export type CodeGenFieldConnectionHasMany = CodeGenConnectionTypeBase & { diff --git a/packages/appsync-modelgen-plugin/src/utils/process-has-many.ts b/packages/appsync-modelgen-plugin/src/utils/process-has-many.ts index 993bebdb2..2d0c6427c 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-has-many.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-has-many.ts @@ -9,7 +9,7 @@ import { flattenFieldDirectives, CodeGenFieldConnectionHasMany, } from './process-connections'; -import { getConnectedFieldV2 } from './process-connections-v2'; +import { getConnectedFieldV2, fieldsAndReferencesErrorMessage } from './process-connections-v2'; export function processHasManyConnection( @@ -25,6 +25,25 @@ export function processHasManyConnection( } const otherSide = modelMap[field.type]; const connectionFields = connectionDirective.arguments.fields || []; + const references = connectionDirective.arguments.references || []; + + if (connectionFields.length > 0 && references.length > 0) { + throw new Error(fieldsAndReferencesErrorMessage); + } + + if (references.length > 0) { + // ensure there is a matching belongsTo field with references + getConnectedFieldV2(field, model, otherSide, connectionDirective.name, shouldUseModelNameFieldInHasManyAndBelongsTo) + const associatedWithFields = references.map((reference: string) => otherSide.fields.find((field) => reference === field.name)) + return { + kind: CodeGenConnectionType.HAS_MANY, + associatedWith: associatedWithFields[0], + associatedWithFields, + isConnectingFieldAutoCreated: false, + connectedModel: otherSide, + }; + } + const otherSideFields = isCustomPKEnabled ? getConnectedFieldsForHasMany(field, model, otherSide, shouldUseModelNameFieldInHasManyAndBelongsTo) : [getConnectedFieldV2(field, model, otherSide, connectionDirective.name, shouldUseModelNameFieldInHasManyAndBelongsTo)]; diff --git a/packages/appsync-modelgen-plugin/src/utils/process-has-one.ts b/packages/appsync-modelgen-plugin/src/utils/process-has-one.ts index 03891f3f9..23f57a768 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-has-one.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-has-one.ts @@ -4,7 +4,7 @@ import { CodeGenFieldConnection, makeConnectionAttributeName, } from './process-connections'; -import { getConnectedFieldV2 } from './process-connections-v2'; +import { getConnectedFieldV2, fieldsAndReferencesErrorMessage } from './process-connections-v2'; import { getModelPrimaryKeyComponentFields } from './fieldUtils'; import { getOtherSideBelongsToField } from './fieldUtils'; @@ -22,14 +22,32 @@ export function processHasOneConnection( if (field.isList || (otherSideBelongsToField && otherSideBelongsToField.isList)) { throw new Error("A hasOne relationship should be 1:1, no lists"); } + + const connectionFields = connectionDirective.arguments.fields || []; + const references = connectionDirective.arguments.references || []; + + if (connectionFields.length > 0 && references.length > 0) { + throw new Error(fieldsAndReferencesErrorMessage); + } + let associatedWithFields; - if (isCustomPKEnabled) { + if (references.length > 0) { + // ensure there is a matching belongsTo field with references + getConnectedFieldV2(field, model, otherSide, connectionDirective.name); + associatedWithFields = references.map((reference: string) => otherSide.fields.find((field) => reference === field.name)) + return { + kind: CodeGenConnectionType.HAS_ONE, + associatedWith: associatedWithFields[0], + associatedWithFields, + connectedModel: otherSide, + isConnectingFieldAutoCreated: false, + }; + } else if (isCustomPKEnabled) { associatedWithFields = getConnectedFieldsForHasOne(otherSideBelongsToField, otherSide, shouldUseFieldsInAssociatedWithInHasOne); } else { const otherSideField = getConnectedFieldV2(field, model, otherSide, connectionDirective.name); associatedWithFields = [otherSideField]; } - const connectionFields = connectionDirective.arguments.fields || []; // TODO: Update comment, graphql-connection-transformer is the v1 package and this file is created for vNext // if a type is connected using name, then graphql-connection-transformer adds a field to diff --git a/packages/appsync-modelgen-plugin/src/visitors/appsync-java-visitor.ts b/packages/appsync-modelgen-plugin/src/visitors/appsync-java-visitor.ts index 6a361e61c..d4699b6fd 100644 --- a/packages/appsync-modelgen-plugin/src/visitors/appsync-java-visitor.ts +++ b/packages/appsync-modelgen-plugin/src/visitors/appsync-java-visitor.ts @@ -1111,7 +1111,7 @@ export class AppSyncModelJavaVisitor< case CodeGenConnectionType.HAS_ONE: connectionDirectiveName = 'HasOne'; connectionArguments.push(`associatedWith = "${this.getFieldName(connectionInfo.associatedWith)}"`); - if (this.isCustomPKEnabled() && this.isGenerateModelsForLazyLoadAndCustomSelectionSet()) { + if (this.isCustomPKEnabled() && this.isGenerateModelsForLazyLoadAndCustomSelectionSet() && connectionInfo.targetNames) { const hasOneTargetNamesArgs = `targetNames = {${connectionInfo.targetNames.map(target => `"${target}"`).join(', ')}}`; connectionArguments.push(hasOneTargetNamesArgs); } diff --git a/packages/appsync-modelgen-plugin/src/visitors/appsync-swift-visitor.ts b/packages/appsync-modelgen-plugin/src/visitors/appsync-swift-visitor.ts index b296c00c1..2e61897a6 100644 --- a/packages/appsync-modelgen-plugin/src/visitors/appsync-swift-visitor.ts +++ b/packages/appsync-modelgen-plugin/src/visitors/appsync-swift-visitor.ts @@ -624,8 +624,8 @@ export class AppSyncSwiftVisitor< connectionInfo.connectedModel, )}.keys.${this.getFieldName(connectionInfo.associatedWith)})`; } - if (connectionInfo.kind === CodeGenConnectionType.HAS_ONE) { - const targetNameAttrStr = this.isCustomPKEnabled() + if (connectionInfo.kind === CodeGenConnectionType.HAS_ONE && (connectionInfo.targetNames || connectionInfo.targetName)) { + const targetNameAttrStr = this.isCustomPKEnabled() && connectionInfo.targetNames ? `targetNames: [${connectionInfo.targetNames.map(target => `"${target}"`).join(', ')}]` : `targetName: "${connectionInfo.targetName}"`; return `.hasOne(${name}, is: ${isRequired}, ofType: ${typeName}, associatedWith: ${this.getModelName( diff --git a/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts b/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts index 603ff91ca..cb2cea965 100644 --- a/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts +++ b/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts @@ -516,6 +516,15 @@ export class AppSyncModelVisitor< if (directive.arguments) { directive.arguments.reduce((acc, arg) => { directiveArguments[arg.name.value] = valueFromASTUntyped(arg.value); + + // convert references: 'primaryId' to references: ['primaryId'] + if ( + (directive.name.value === 'hasOne' || directive.name.value === 'belongsTo' || directive.name.value === 'hasMany') && + directiveArguments.references && + !Array.isArray(directiveArguments.references) + ) { + directiveArguments.references = [directiveArguments.references]; + } return directiveArguments; }, directiveArguments); } @@ -814,7 +823,7 @@ export class AppSyncModelVisitor< if (connectionInfo.kind === CodeGenConnectionType.HAS_MANY || connectionInfo.kind === CodeGenConnectionType.HAS_ONE) { // Need to update the other side of the connection even if there is no connection directive addFieldToModel(connectionInfo.connectedModel, connectionInfo.associatedWith); - } else if (connectionInfo.targetName !== this.getModelPrimaryKeyField(model)?.name ?? 'id') { + } else if (connectionInfo.targetName && (connectionInfo.targetName !== this.getModelPrimaryKeyField(model)?.name ?? 'id')) { // Need to remove the field that is targetName removeFieldFromModel(model, connectionInfo.targetName); } @@ -1096,7 +1105,7 @@ export class AppSyncModelVisitor< } else if (connectionInfo.kind === CodeGenConnectionType.HAS_ONE) { if (isCustomPKEnabled) { const connectedModelFields = getModelPrimaryKeyComponentFields(connectionInfo.connectedModel); - if (connectedModelFields?.length > 0) { + if (connectedModelFields?.length > 0 && connectionInfo.targetNames) { connectionInfo.targetNames.forEach((target, index) => { addFieldToModel(model, { name: target, @@ -1107,7 +1116,7 @@ export class AppSyncModelVisitor< }); }); } - } else { + } else if (connectionInfo.targetName) { addFieldToModel(model, { name: connectionInfo.targetName, directives: [], @@ -1171,6 +1180,7 @@ export class AppSyncModelVisitor< connectionInfo && connectionInfo.kind !== CodeGenConnectionType.HAS_MANY && connectionInfo.kind !== CodeGenConnectionType.HAS_ONE && + connectionInfo.targetNames && connectionInfo.targetName !== 'id' ) { // Need to remove the field that is targetName @@ -1189,7 +1199,9 @@ export class AppSyncModelVisitor< connectionInfo && connectionInfo.kind !== CodeGenConnectionType.HAS_MANY && connectionInfo.kind !== CodeGenConnectionType.HAS_ONE && + connectionInfo.targetName && connectionInfo.targetName !== 'id' && + !connectionInfo.isUsingReferences && !(this.config.target === 'introspection' && primaryKeyName && primaryKeyName === connectionInfo.targetName) ) { From 02a581f6a9700961d2522d1b14f0f808b8758999 Mon Sep 17 00:00:00 2001 From: Zeyu Li Date: Tue, 16 Apr 2024 17:47:52 -0700 Subject: [PATCH 3/8] fix: missing targetNames in hasOne reference --- .../appsync-model-introspection-visitor.test.ts.snap | 12 ++++++++---- .../visitors/appsync-model-introspection-visitor.ts | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap index 2efe4ed99..ca3c210b7 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap @@ -3692,7 +3692,8 @@ exports[`custom references double linked references 1`] = ` \\"connectionType\\": \\"HAS_ONE\\", \\"associatedWith\\": [ \\"bar1Id\\" - ] + ], + \\"targetNames\\": [] } }, \\"bar2\\": { @@ -3707,7 +3708,8 @@ exports[`custom references double linked references 1`] = ` \\"connectionType\\": \\"HAS_ONE\\", \\"associatedWith\\": [ \\"bar2Id\\" - ] + ], + \\"targetNames\\": [] } }, \\"createdAt\\": { @@ -4244,7 +4246,8 @@ exports[`custom references sets the association to the references field for hasO \\"connectionType\\": \\"HAS_ONE\\", \\"associatedWith\\": [ \\"primaryId\\" - ] + ], + \\"targetNames\\": [] } }, \\"createdAt\\": { @@ -4467,7 +4470,8 @@ exports[`custom references sets the association to the references field for hasO \\"connectionType\\": \\"HAS_ONE\\", \\"associatedWith\\": [ \\"primaryId\\" - ] + ], + \\"targetNames\\": [] } }, \\"createdAt\\": { diff --git a/packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts b/packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts index fdf9244c5..ca79c2bcb 100644 --- a/packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts +++ b/packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts @@ -115,7 +115,7 @@ export class AppSyncModelIntrospectionVisitor< connectionAttribute.associatedWith = connectionInfo.associatedWithFields.map(f => this.getFieldName(f)); } else if (connectionInfo.kind === CodeGenConnectionType.HAS_ONE) { connectionAttribute.associatedWith = connectionInfo.associatedWithFields.map(f => this.getFieldName(f)); - connectionAttribute.targetNames = connectionInfo.targetNames; + connectionAttribute.targetNames = connectionInfo.targetNames ?? []; } else { connectionAttribute.targetNames = connectionInfo.targetNames; } From de394dda82febe22e1cdeccf22d4c36fae91cf2b Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Fri, 19 Apr 2024 10:47:39 -0600 Subject: [PATCH 4/8] fix: do not remove belongsTo target names when using references (#814) --- .../appsync-dart-visitor.test.ts.snap | 3687 +++++++++++++++++ .../appsync-java-visitor.test.ts.snap | 3073 ++++++++++++++ ...c-model-introspection-visitor.test.ts.snap | 189 + .../appsync-swift-visitor.test.ts.snap | 1758 ++++++++ .../visitors/appsync-dart-visitor.test.ts | 180 + .../visitors/appsync-java-visitor.test.ts | 156 + ...ppsync-model-introspection-visitor.test.ts | 22 + .../visitors/appsync-swift-visitor.test.ts | 196 + .../src/visitors/appsync-visitor.ts | 3 +- 9 files changed, 9263 insertions(+), 1 deletion(-) diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap index 6e6c50422..542a3a4b8 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap @@ -11597,3 +11597,3690 @@ class CpkOneToOneBidirectionalChildExplicitModelIdentifier implements amplify_co name.hashCode; }" `; + +exports[`AppSync Dart Visitor custom references double linked references 1`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the Foo type in your schema. */ +class Foo extends amplify_core.Model { + static const classType = const _FooModelType(); + final String id; + final Bar? _bar1; + final Bar? _bar2; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + FooModelIdentifier get modelIdentifier { + return FooModelIdentifier( + id: id + ); + } + + Bar? get bar1 { + return _bar1; + } + + Bar? get bar2 { + return _bar2; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const Foo._internal({required this.id, bar1, bar2, createdAt, updatedAt}): _bar1 = bar1, _bar2 = bar2, _createdAt = createdAt, _updatedAt = updatedAt; + + factory Foo({String? id, Bar? bar1, Bar? bar2}) { + return Foo._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + bar1: bar1, + bar2: bar2); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is Foo && + id == other.id && + _bar1 == other._bar1 && + _bar2 == other._bar2; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"Foo {\\"); + buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + Foo copyWith({Bar? bar1, Bar? bar2}) { + return Foo._internal( + id: id, + bar1: bar1 ?? this.bar1, + bar2: bar2 ?? this.bar2); + } + + Foo copyWithModelFieldValues({ + ModelFieldValue? bar1, + ModelFieldValue? bar2 + }) { + return Foo._internal( + id: id, + bar1: bar1 == null ? this.bar1 : bar1.value, + bar2: bar2 == null ? this.bar2 : bar2.value + ); + } + + Foo.fromJson(Map json) + : id = json['id'], + _bar1 = json['bar1']?['serializedData'] != null + ? Bar.fromJson(new Map.from(json['bar1']['serializedData'])) + : null, + _bar2 = json['bar2']?['serializedData'] != null + ? Bar.fromJson(new Map.from(json['bar2']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'bar1': _bar1?.toJson(), 'bar2': _bar2?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'bar1': _bar1, + 'bar2': _bar2, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final BAR1 = amplify_core.QueryField( + fieldName: \\"bar1\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Bar')); + static final BAR2 = amplify_core.QueryField( + fieldName: \\"bar2\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Bar')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"Foo\\"; + modelSchemaDefinition.pluralName = \\"Foos\\"; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasOne( + key: Foo.BAR1, + isRequired: false, + ofModelName: 'Bar', + associatedKey: Bar.BAR1ID + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasOne( + key: Foo.BAR2, + isRequired: false, + ofModelName: 'Bar', + associatedKey: Bar.BAR2ID + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _FooModelType extends amplify_core.ModelType { + const _FooModelType(); + + @override + Foo fromJson(Map jsonData) { + return Foo.fromJson(jsonData); + } + + @override + String modelName() { + return 'Foo'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [Foo] in your schema. + */ +class FooModelIdentifier implements amplify_core.ModelIdentifier { + final String id; + + /** Create an instance of FooModelIdentifier using [id] the primary key. */ + const FooModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'FooModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is FooModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references double linked references 2`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the Bar type in your schema. */ +class Bar extends amplify_core.Model { + static const classType = const _BarModelType(); + final String id; + final String? _bar1Id; + final String? _bar2Id; + final Foo? _foo1; + final Foo? _foo2; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + BarModelIdentifier get modelIdentifier { + return BarModelIdentifier( + id: id + ); + } + + String? get bar1Id { + return _bar1Id; + } + + String? get bar2Id { + return _bar2Id; + } + + Foo? get foo1 { + return _foo1; + } + + Foo? get foo2 { + return _foo2; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const Bar._internal({required this.id, bar1Id, bar2Id, foo1, foo2, createdAt, updatedAt}): _bar1Id = bar1Id, _bar2Id = bar2Id, _foo1 = foo1, _foo2 = foo2, _createdAt = createdAt, _updatedAt = updatedAt; + + factory Bar({String? id, String? bar1Id, String? bar2Id, Foo? foo1, Foo? foo2}) { + return Bar._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + bar1Id: bar1Id, + bar2Id: bar2Id, + foo1: foo1, + foo2: foo2); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is Bar && + id == other.id && + _bar1Id == other._bar1Id && + _bar2Id == other._bar2Id && + _foo1 == other._foo1 && + _foo2 == other._foo2; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"Bar {\\"); + buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); + buffer.write(\\"bar1Id=\\" + \\"$_bar1Id\\" + \\", \\"); + buffer.write(\\"bar2Id=\\" + \\"$_bar2Id\\" + \\", \\"); + buffer.write(\\"foo1=\\" + (_foo1 != null ? _foo1!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"foo2=\\" + (_foo2 != null ? _foo2!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + Bar copyWith({String? bar1Id, String? bar2Id, Foo? foo1, Foo? foo2}) { + return Bar._internal( + id: id, + bar1Id: bar1Id ?? this.bar1Id, + bar2Id: bar2Id ?? this.bar2Id, + foo1: foo1 ?? this.foo1, + foo2: foo2 ?? this.foo2); + } + + Bar copyWithModelFieldValues({ + ModelFieldValue? bar1Id, + ModelFieldValue? bar2Id, + ModelFieldValue? foo1, + ModelFieldValue? foo2 + }) { + return Bar._internal( + id: id, + bar1Id: bar1Id == null ? this.bar1Id : bar1Id.value, + bar2Id: bar2Id == null ? this.bar2Id : bar2Id.value, + foo1: foo1 == null ? this.foo1 : foo1.value, + foo2: foo2 == null ? this.foo2 : foo2.value + ); + } + + Bar.fromJson(Map json) + : id = json['id'], + _bar1Id = json['bar1Id'], + _bar2Id = json['bar2Id'], + _foo1 = json['foo1']?['serializedData'] != null + ? Foo.fromJson(new Map.from(json['foo1']['serializedData'])) + : null, + _foo2 = json['foo2']?['serializedData'] != null + ? Foo.fromJson(new Map.from(json['foo2']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'bar1Id': _bar1Id, 'bar2Id': _bar2Id, 'foo1': _foo1?.toJson(), 'foo2': _foo2?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'bar1Id': _bar1Id, + 'bar2Id': _bar2Id, + 'foo1': _foo1, + 'foo2': _foo2, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final BAR1ID = amplify_core.QueryField(fieldName: \\"bar1Id\\"); + static final BAR2ID = amplify_core.QueryField(fieldName: \\"bar2Id\\"); + static final FOO1 = amplify_core.QueryField( + fieldName: \\"foo1\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Foo')); + static final FOO2 = amplify_core.QueryField( + fieldName: \\"foo2\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Foo')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"Bar\\"; + modelSchemaDefinition.pluralName = \\"Bars\\"; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Bar.BAR1ID, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Bar.BAR2ID, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( + key: Bar.FOO1, + isRequired: false, + targetNames: ['bar1Id'], + ofModelName: 'Foo' + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( + key: Bar.FOO2, + isRequired: false, + targetNames: ['bar2Id'], + ofModelName: 'Foo' + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _BarModelType extends amplify_core.ModelType { + const _BarModelType(); + + @override + Bar fromJson(Map jsonData) { + return Bar.fromJson(jsonData); + } + + @override + String modelName() { + return 'Bar'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [Bar] in your schema. + */ +class BarModelIdentifier implements amplify_core.ModelIdentifier { + final String id; + + /** Create an instance of BarModelIdentifier using [id] the primary key. */ + const BarModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'BarModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is BarModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references hasMany with sortKeyFields on primary key 1`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; +import 'package:collection/collection.dart'; + + +/** This is an auto generated class representing the Primary type in your schema. */ +class Primary extends amplify_core.Model { + static const classType = const _PrimaryModelType(); + final String? _tenantId; + final String? _instanceId; + final String? _recordId; + final String? _content; + final List? _related; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => modelIdentifier.serializeAsString(); + + PrimaryModelIdentifier get modelIdentifier { + try { + return PrimaryModelIdentifier( + tenantId: _tenantId!, + instanceId: _instanceId!, + recordId: _recordId! + ); + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get tenantId { + try { + return _tenantId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get instanceId { + try { + return _instanceId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get recordId { + try { + return _recordId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String? get content { + return _content; + } + + List? get related { + return _related; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const Primary._internal({required tenantId, required instanceId, required recordId, content, related, createdAt, updatedAt}): _tenantId = tenantId, _instanceId = instanceId, _recordId = recordId, _content = content, _related = related, _createdAt = createdAt, _updatedAt = updatedAt; + + factory Primary({required String tenantId, required String instanceId, required String recordId, String? content, List? related}) { + return Primary._internal( + tenantId: tenantId, + instanceId: instanceId, + recordId: recordId, + content: content, + related: related != null ? List.unmodifiable(related) : related); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is Primary && + _tenantId == other._tenantId && + _instanceId == other._instanceId && + _recordId == other._recordId && + _content == other._content && + DeepCollectionEquality().equals(_related, other._related); + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"Primary {\\"); + buffer.write(\\"tenantId=\\" + \\"$_tenantId\\" + \\", \\"); + buffer.write(\\"instanceId=\\" + \\"$_instanceId\\" + \\", \\"); + buffer.write(\\"recordId=\\" + \\"$_recordId\\" + \\", \\"); + buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + Primary copyWith({String? content, List? related}) { + return Primary._internal( + tenantId: tenantId, + instanceId: instanceId, + recordId: recordId, + content: content ?? this.content, + related: related ?? this.related); + } + + Primary copyWithModelFieldValues({ + ModelFieldValue? content, + ModelFieldValue>? related + }) { + return Primary._internal( + tenantId: tenantId, + instanceId: instanceId, + recordId: recordId, + content: content == null ? this.content : content.value, + related: related == null ? this.related : related.value + ); + } + + Primary.fromJson(Map json) + : _tenantId = json['tenantId'], + _instanceId = json['instanceId'], + _recordId = json['recordId'], + _content = json['content'], + _related = json['related'] is List + ? (json['related'] as List) + .where((e) => e?['serializedData'] != null) + .map((e) => Related.fromJson(new Map.from(e['serializedData']))) + .toList() + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'tenantId': _tenantId, 'instanceId': _instanceId, 'recordId': _recordId, 'content': _content, 'related': _related?.map((Related? e) => e?.toJson()).toList(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'tenantId': _tenantId, + 'instanceId': _instanceId, + 'recordId': _recordId, + 'content': _content, + 'related': _related, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final TENANTID = amplify_core.QueryField(fieldName: \\"tenantId\\"); + static final INSTANCEID = amplify_core.QueryField(fieldName: \\"instanceId\\"); + static final RECORDID = amplify_core.QueryField(fieldName: \\"recordId\\"); + static final CONTENT = amplify_core.QueryField(fieldName: \\"content\\"); + static final RELATED = amplify_core.QueryField( + fieldName: \\"related\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Related')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"Primary\\"; + modelSchemaDefinition.pluralName = \\"Primaries\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"tenantId\\", \\"instanceId\\", \\"recordId\\"], name: null) + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.TENANTID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.INSTANCEID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.RECORDID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.CONTENT, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasMany( + key: Primary.RELATED, + isRequired: true, + ofModelName: 'Related', + associatedKey: Related.PRIMARYTENANTID + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _PrimaryModelType extends amplify_core.ModelType { + const _PrimaryModelType(); + + @override + Primary fromJson(Map jsonData) { + return Primary.fromJson(jsonData); + } + + @override + String modelName() { + return 'Primary'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [Primary] in your schema. + */ +class PrimaryModelIdentifier implements amplify_core.ModelIdentifier { + final String tenantId; + final String instanceId; + final String recordId; + + /** + * Create an instance of PrimaryModelIdentifier using [tenantId] the primary key. + * And [instanceId], [recordId] the sort keys. + */ + const PrimaryModelIdentifier({ + required this.tenantId, + required this.instanceId, + required this.recordId}); + + @override + Map serializeAsMap() => ({ + 'tenantId': tenantId, + 'instanceId': instanceId, + 'recordId': recordId + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'PrimaryModelIdentifier(tenantId: $tenantId, instanceId: $instanceId, recordId: $recordId)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is PrimaryModelIdentifier && + tenantId == other.tenantId && + instanceId == other.instanceId && + recordId == other.recordId; + } + + @override + int get hashCode => + tenantId.hashCode ^ + instanceId.hashCode ^ + recordId.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references hasMany with sortKeyFields on primary key 2`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the Related type in your schema. */ +class Related extends amplify_core.Model { + static const classType = const _RelatedModelType(); + final String id; + final String? _content; + final String? _primaryTenantId; + final String? _primaryInstanceId; + final String? _primaryRecordId; + final Primary? _primary; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + RelatedModelIdentifier get modelIdentifier { + return RelatedModelIdentifier( + id: id + ); + } + + String? get content { + return _content; + } + + String get primaryTenantId { + try { + return _primaryTenantId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get primaryInstanceId { + try { + return _primaryInstanceId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get primaryRecordId { + try { + return _primaryRecordId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + Primary? get primary { + return _primary; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const Related._internal({required this.id, content, required primaryTenantId, required primaryInstanceId, required primaryRecordId, primary, createdAt, updatedAt}): _content = content, _primaryTenantId = primaryTenantId, _primaryInstanceId = primaryInstanceId, _primaryRecordId = primaryRecordId, _primary = primary, _createdAt = createdAt, _updatedAt = updatedAt; + + factory Related({String? id, String? content, required String primaryTenantId, required String primaryInstanceId, required String primaryRecordId, Primary? primary}) { + return Related._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + content: content, + primaryTenantId: primaryTenantId, + primaryInstanceId: primaryInstanceId, + primaryRecordId: primaryRecordId, + primary: primary); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is Related && + id == other.id && + _content == other._content && + _primaryTenantId == other._primaryTenantId && + _primaryInstanceId == other._primaryInstanceId && + _primaryRecordId == other._primaryRecordId && + _primary == other._primary; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"Related {\\"); + buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); + buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); + buffer.write(\\"primaryTenantId=\\" + \\"$_primaryTenantId\\" + \\", \\"); + buffer.write(\\"primaryInstanceId=\\" + \\"$_primaryInstanceId\\" + \\", \\"); + buffer.write(\\"primaryRecordId=\\" + \\"$_primaryRecordId\\" + \\", \\"); + buffer.write(\\"primary=\\" + (_primary != null ? _primary!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + Related copyWith({String? content, String? primaryTenantId, String? primaryInstanceId, String? primaryRecordId, Primary? primary}) { + return Related._internal( + id: id, + content: content ?? this.content, + primaryTenantId: primaryTenantId ?? this.primaryTenantId, + primaryInstanceId: primaryInstanceId ?? this.primaryInstanceId, + primaryRecordId: primaryRecordId ?? this.primaryRecordId, + primary: primary ?? this.primary); + } + + Related copyWithModelFieldValues({ + ModelFieldValue? content, + ModelFieldValue? primaryTenantId, + ModelFieldValue? primaryInstanceId, + ModelFieldValue? primaryRecordId, + ModelFieldValue? primary + }) { + return Related._internal( + id: id, + content: content == null ? this.content : content.value, + primaryTenantId: primaryTenantId == null ? this.primaryTenantId : primaryTenantId.value, + primaryInstanceId: primaryInstanceId == null ? this.primaryInstanceId : primaryInstanceId.value, + primaryRecordId: primaryRecordId == null ? this.primaryRecordId : primaryRecordId.value, + primary: primary == null ? this.primary : primary.value + ); + } + + Related.fromJson(Map json) + : id = json['id'], + _content = json['content'], + _primaryTenantId = json['primaryTenantId'], + _primaryInstanceId = json['primaryInstanceId'], + _primaryRecordId = json['primaryRecordId'], + _primary = json['primary']?['serializedData'] != null + ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'content': _content, 'primaryTenantId': _primaryTenantId, 'primaryInstanceId': _primaryInstanceId, 'primaryRecordId': _primaryRecordId, 'primary': _primary?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'content': _content, + 'primaryTenantId': _primaryTenantId, + 'primaryInstanceId': _primaryInstanceId, + 'primaryRecordId': _primaryRecordId, + 'primary': _primary, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final CONTENT = amplify_core.QueryField(fieldName: \\"content\\"); + static final PRIMARYTENANTID = amplify_core.QueryField(fieldName: \\"primaryTenantId\\"); + static final PRIMARYINSTANCEID = amplify_core.QueryField(fieldName: \\"primaryInstanceId\\"); + static final PRIMARYRECORDID = amplify_core.QueryField(fieldName: \\"primaryRecordId\\"); + static final PRIMARY = amplify_core.QueryField( + fieldName: \\"primary\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Primary')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"Related\\"; + modelSchemaDefinition.pluralName = \\"Relateds\\"; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Related.CONTENT, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Related.PRIMARYTENANTID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Related.PRIMARYINSTANCEID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Related.PRIMARYRECORDID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( + key: Related.PRIMARY, + isRequired: false, + targetNames: ['primaryTenantId', 'primaryInstanceId', 'primaryRecordId'], + ofModelName: 'Primary' + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _RelatedModelType extends amplify_core.ModelType { + const _RelatedModelType(); + + @override + Related fromJson(Map jsonData) { + return Related.fromJson(jsonData); + } + + @override + String modelName() { + return 'Related'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [Related] in your schema. + */ +class RelatedModelIdentifier implements amplify_core.ModelIdentifier { + final String id; + + /** Create an instance of RelatedModelIdentifier using [id] the primary key. */ + const RelatedModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'RelatedModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is RelatedModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references hasOne with sortKeyFields on primary key 1`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the Primary type in your schema. */ +class Primary extends amplify_core.Model { + static const classType = const _PrimaryModelType(); + final String? _tenantId; + final String? _instanceId; + final String? _recordId; + final String? _content; + final Related? _related; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => modelIdentifier.serializeAsString(); + + PrimaryModelIdentifier get modelIdentifier { + try { + return PrimaryModelIdentifier( + tenantId: _tenantId!, + instanceId: _instanceId!, + recordId: _recordId! + ); + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get tenantId { + try { + return _tenantId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get instanceId { + try { + return _instanceId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get recordId { + try { + return _recordId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String? get content { + return _content; + } + + Related? get related { + return _related; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const Primary._internal({required tenantId, required instanceId, required recordId, content, related, createdAt, updatedAt}): _tenantId = tenantId, _instanceId = instanceId, _recordId = recordId, _content = content, _related = related, _createdAt = createdAt, _updatedAt = updatedAt; + + factory Primary({required String tenantId, required String instanceId, required String recordId, String? content, Related? related}) { + return Primary._internal( + tenantId: tenantId, + instanceId: instanceId, + recordId: recordId, + content: content, + related: related); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is Primary && + _tenantId == other._tenantId && + _instanceId == other._instanceId && + _recordId == other._recordId && + _content == other._content && + _related == other._related; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"Primary {\\"); + buffer.write(\\"tenantId=\\" + \\"$_tenantId\\" + \\", \\"); + buffer.write(\\"instanceId=\\" + \\"$_instanceId\\" + \\", \\"); + buffer.write(\\"recordId=\\" + \\"$_recordId\\" + \\", \\"); + buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + Primary copyWith({String? content, Related? related}) { + return Primary._internal( + tenantId: tenantId, + instanceId: instanceId, + recordId: recordId, + content: content ?? this.content, + related: related ?? this.related); + } + + Primary copyWithModelFieldValues({ + ModelFieldValue? content, + ModelFieldValue? related + }) { + return Primary._internal( + tenantId: tenantId, + instanceId: instanceId, + recordId: recordId, + content: content == null ? this.content : content.value, + related: related == null ? this.related : related.value + ); + } + + Primary.fromJson(Map json) + : _tenantId = json['tenantId'], + _instanceId = json['instanceId'], + _recordId = json['recordId'], + _content = json['content'], + _related = json['related']?['serializedData'] != null + ? Related.fromJson(new Map.from(json['related']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'tenantId': _tenantId, 'instanceId': _instanceId, 'recordId': _recordId, 'content': _content, 'related': _related?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'tenantId': _tenantId, + 'instanceId': _instanceId, + 'recordId': _recordId, + 'content': _content, + 'related': _related, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final TENANTID = amplify_core.QueryField(fieldName: \\"tenantId\\"); + static final INSTANCEID = amplify_core.QueryField(fieldName: \\"instanceId\\"); + static final RECORDID = amplify_core.QueryField(fieldName: \\"recordId\\"); + static final CONTENT = amplify_core.QueryField(fieldName: \\"content\\"); + static final RELATED = amplify_core.QueryField( + fieldName: \\"related\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Related')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"Primary\\"; + modelSchemaDefinition.pluralName = \\"Primaries\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"tenantId\\", \\"instanceId\\", \\"recordId\\"], name: null) + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.TENANTID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.INSTANCEID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.RECORDID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.CONTENT, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasOne( + key: Primary.RELATED, + isRequired: false, + ofModelName: 'Related', + associatedKey: Related.PRIMARYTENANTID + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _PrimaryModelType extends amplify_core.ModelType { + const _PrimaryModelType(); + + @override + Primary fromJson(Map jsonData) { + return Primary.fromJson(jsonData); + } + + @override + String modelName() { + return 'Primary'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [Primary] in your schema. + */ +class PrimaryModelIdentifier implements amplify_core.ModelIdentifier { + final String tenantId; + final String instanceId; + final String recordId; + + /** + * Create an instance of PrimaryModelIdentifier using [tenantId] the primary key. + * And [instanceId], [recordId] the sort keys. + */ + const PrimaryModelIdentifier({ + required this.tenantId, + required this.instanceId, + required this.recordId}); + + @override + Map serializeAsMap() => ({ + 'tenantId': tenantId, + 'instanceId': instanceId, + 'recordId': recordId + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'PrimaryModelIdentifier(tenantId: $tenantId, instanceId: $instanceId, recordId: $recordId)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is PrimaryModelIdentifier && + tenantId == other.tenantId && + instanceId == other.instanceId && + recordId == other.recordId; + } + + @override + int get hashCode => + tenantId.hashCode ^ + instanceId.hashCode ^ + recordId.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references hasOne with sortKeyFields on primary key 2`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the Related type in your schema. */ +class Related extends amplify_core.Model { + static const classType = const _RelatedModelType(); + final String id; + final String? _content; + final String? _primaryTenantId; + final String? _primaryInstanceId; + final String? _primaryRecordId; + final Primary? _primary; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + RelatedModelIdentifier get modelIdentifier { + return RelatedModelIdentifier( + id: id + ); + } + + String? get content { + return _content; + } + + String get primaryTenantId { + try { + return _primaryTenantId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get primaryInstanceId { + try { + return _primaryInstanceId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + String get primaryRecordId { + try { + return _primaryRecordId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + Primary? get primary { + return _primary; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const Related._internal({required this.id, content, required primaryTenantId, required primaryInstanceId, required primaryRecordId, primary, createdAt, updatedAt}): _content = content, _primaryTenantId = primaryTenantId, _primaryInstanceId = primaryInstanceId, _primaryRecordId = primaryRecordId, _primary = primary, _createdAt = createdAt, _updatedAt = updatedAt; + + factory Related({String? id, String? content, required String primaryTenantId, required String primaryInstanceId, required String primaryRecordId, Primary? primary}) { + return Related._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + content: content, + primaryTenantId: primaryTenantId, + primaryInstanceId: primaryInstanceId, + primaryRecordId: primaryRecordId, + primary: primary); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is Related && + id == other.id && + _content == other._content && + _primaryTenantId == other._primaryTenantId && + _primaryInstanceId == other._primaryInstanceId && + _primaryRecordId == other._primaryRecordId && + _primary == other._primary; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"Related {\\"); + buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); + buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); + buffer.write(\\"primaryTenantId=\\" + \\"$_primaryTenantId\\" + \\", \\"); + buffer.write(\\"primaryInstanceId=\\" + \\"$_primaryInstanceId\\" + \\", \\"); + buffer.write(\\"primaryRecordId=\\" + \\"$_primaryRecordId\\" + \\", \\"); + buffer.write(\\"primary=\\" + (_primary != null ? _primary!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + Related copyWith({String? content, String? primaryTenantId, String? primaryInstanceId, String? primaryRecordId, Primary? primary}) { + return Related._internal( + id: id, + content: content ?? this.content, + primaryTenantId: primaryTenantId ?? this.primaryTenantId, + primaryInstanceId: primaryInstanceId ?? this.primaryInstanceId, + primaryRecordId: primaryRecordId ?? this.primaryRecordId, + primary: primary ?? this.primary); + } + + Related copyWithModelFieldValues({ + ModelFieldValue? content, + ModelFieldValue? primaryTenantId, + ModelFieldValue? primaryInstanceId, + ModelFieldValue? primaryRecordId, + ModelFieldValue? primary + }) { + return Related._internal( + id: id, + content: content == null ? this.content : content.value, + primaryTenantId: primaryTenantId == null ? this.primaryTenantId : primaryTenantId.value, + primaryInstanceId: primaryInstanceId == null ? this.primaryInstanceId : primaryInstanceId.value, + primaryRecordId: primaryRecordId == null ? this.primaryRecordId : primaryRecordId.value, + primary: primary == null ? this.primary : primary.value + ); + } + + Related.fromJson(Map json) + : id = json['id'], + _content = json['content'], + _primaryTenantId = json['primaryTenantId'], + _primaryInstanceId = json['primaryInstanceId'], + _primaryRecordId = json['primaryRecordId'], + _primary = json['primary']?['serializedData'] != null + ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'content': _content, 'primaryTenantId': _primaryTenantId, 'primaryInstanceId': _primaryInstanceId, 'primaryRecordId': _primaryRecordId, 'primary': _primary?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'content': _content, + 'primaryTenantId': _primaryTenantId, + 'primaryInstanceId': _primaryInstanceId, + 'primaryRecordId': _primaryRecordId, + 'primary': _primary, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final CONTENT = amplify_core.QueryField(fieldName: \\"content\\"); + static final PRIMARYTENANTID = amplify_core.QueryField(fieldName: \\"primaryTenantId\\"); + static final PRIMARYINSTANCEID = amplify_core.QueryField(fieldName: \\"primaryInstanceId\\"); + static final PRIMARYRECORDID = amplify_core.QueryField(fieldName: \\"primaryRecordId\\"); + static final PRIMARY = amplify_core.QueryField( + fieldName: \\"primary\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Primary')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"Related\\"; + modelSchemaDefinition.pluralName = \\"Relateds\\"; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Related.CONTENT, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Related.PRIMARYTENANTID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Related.PRIMARYINSTANCEID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Related.PRIMARYRECORDID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( + key: Related.PRIMARY, + isRequired: false, + targetNames: ['primaryTenantId', 'primaryInstanceId', 'primaryRecordId'], + ofModelName: 'Primary' + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _RelatedModelType extends amplify_core.ModelType { + const _RelatedModelType(); + + @override + Related fromJson(Map jsonData) { + return Related.fromJson(jsonData); + } + + @override + String modelName() { + return 'Related'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [Related] in your schema. + */ +class RelatedModelIdentifier implements amplify_core.ModelIdentifier { + final String id; + + /** Create an instance of RelatedModelIdentifier using [id] the primary key. */ + const RelatedModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'RelatedModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is RelatedModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references sets the association to the references field for hasMany/belongsTo 1`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; +import 'package:collection/collection.dart'; + + +/** This is an auto generated class representing the SqlPrimary type in your schema. */ +class SqlPrimary extends amplify_core.Model { + static const classType = const _SqlPrimaryModelType(); + final int id; + final String? _content; + final List? _related; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + SqlPrimaryModelIdentifier get modelIdentifier { + return SqlPrimaryModelIdentifier( + id: id + ); + } + + String? get content { + return _content; + } + + List? get related { + return _related; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const SqlPrimary._internal({required this.id, content, related, createdAt, updatedAt}): _content = content, _related = related, _createdAt = createdAt, _updatedAt = updatedAt; + + factory SqlPrimary({int? id, String? content, List? related}) { + return SqlPrimary._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + content: content, + related: related != null ? List.unmodifiable(related) : related); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is SqlPrimary && + id == other.id && + _content == other._content && + DeepCollectionEquality().equals(_related, other._related); + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"SqlPrimary {\\"); + buffer.write(\\"id=\\" + (id != null ? id!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + SqlPrimary copyWith({String? content, List? related}) { + return SqlPrimary._internal( + id: id, + content: content ?? this.content, + related: related ?? this.related); + } + + SqlPrimary copyWithModelFieldValues({ + ModelFieldValue? content, + ModelFieldValue>? related + }) { + return SqlPrimary._internal( + id: id, + content: content == null ? this.content : content.value, + related: related == null ? this.related : related.value + ); + } + + SqlPrimary.fromJson(Map json) + : id = (json['id'] as num?)?.toInt(), + _content = json['content'], + _related = json['related'] is List + ? (json['related'] as List) + .where((e) => e?['serializedData'] != null) + .map((e) => SqlRelated.fromJson(new Map.from(e['serializedData']))) + .toList() + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'content': _content, 'related': _related?.map((SqlRelated? e) => e?.toJson()).toList(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'content': _content, + 'related': _related, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final CONTENT = amplify_core.QueryField(fieldName: \\"content\\"); + static final RELATED = amplify_core.QueryField( + fieldName: \\"related\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'SqlRelated')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"SqlPrimary\\"; + modelSchemaDefinition.pluralName = \\"SqlPrimaries\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"id\\"], name: null) + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: SqlPrimary.CONTENT, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasMany( + key: SqlPrimary.RELATED, + isRequired: true, + ofModelName: 'SqlRelated', + associatedKey: SqlRelated.PRIMARYID + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _SqlPrimaryModelType extends amplify_core.ModelType { + const _SqlPrimaryModelType(); + + @override + SqlPrimary fromJson(Map jsonData) { + return SqlPrimary.fromJson(jsonData); + } + + @override + String modelName() { + return 'SqlPrimary'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [SqlPrimary] in your schema. + */ +class SqlPrimaryModelIdentifier implements amplify_core.ModelIdentifier { + final int id; + + /** Create an instance of SqlPrimaryModelIdentifier using [id] the primary key. */ + const SqlPrimaryModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'SqlPrimaryModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is SqlPrimaryModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references sets the association to the references field for hasMany/belongsTo 2`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the SqlRelated type in your schema. */ +class SqlRelated extends amplify_core.Model { + static const classType = const _SqlRelatedModelType(); + final int id; + final String? _content; + final int? _primaryId; + final SqlPrimary? _primary; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + SqlRelatedModelIdentifier get modelIdentifier { + return SqlRelatedModelIdentifier( + id: id + ); + } + + String? get content { + return _content; + } + + int get primaryId { + try { + return _primaryId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + SqlPrimary? get primary { + return _primary; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const SqlRelated._internal({required this.id, content, required primaryId, primary, createdAt, updatedAt}): _content = content, _primaryId = primaryId, _primary = primary, _createdAt = createdAt, _updatedAt = updatedAt; + + factory SqlRelated({int? id, String? content, required int primaryId, SqlPrimary? primary}) { + return SqlRelated._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + content: content, + primaryId: primaryId, + primary: primary); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is SqlRelated && + id == other.id && + _content == other._content && + _primaryId == other._primaryId && + _primary == other._primary; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"SqlRelated {\\"); + buffer.write(\\"id=\\" + (id != null ? id!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); + buffer.write(\\"primaryId=\\" + (_primaryId != null ? _primaryId!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"primary=\\" + (_primary != null ? _primary!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + SqlRelated copyWith({String? content, int? primaryId, SqlPrimary? primary}) { + return SqlRelated._internal( + id: id, + content: content ?? this.content, + primaryId: primaryId ?? this.primaryId, + primary: primary ?? this.primary); + } + + SqlRelated copyWithModelFieldValues({ + ModelFieldValue? content, + ModelFieldValue? primaryId, + ModelFieldValue? primary + }) { + return SqlRelated._internal( + id: id, + content: content == null ? this.content : content.value, + primaryId: primaryId == null ? this.primaryId : primaryId.value, + primary: primary == null ? this.primary : primary.value + ); + } + + SqlRelated.fromJson(Map json) + : id = (json['id'] as num?)?.toInt(), + _content = json['content'], + _primaryId = (json['primaryId'] as num?)?.toInt(), + _primary = json['primary']?['serializedData'] != null + ? SqlPrimary.fromJson(new Map.from(json['primary']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'content': _content, 'primaryId': _primaryId, 'primary': _primary?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'content': _content, + 'primaryId': _primaryId, + 'primary': _primary, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final CONTENT = amplify_core.QueryField(fieldName: \\"content\\"); + static final PRIMARYID = amplify_core.QueryField(fieldName: \\"primaryId\\"); + static final PRIMARY = amplify_core.QueryField( + fieldName: \\"primary\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'SqlPrimary')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"SqlRelated\\"; + modelSchemaDefinition.pluralName = \\"SqlRelateds\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"id\\"], name: null), + amplify_core.ModelIndex(fields: const [\\"primaryId\\"], name: \\"primary_id\\") + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: SqlRelated.CONTENT, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: SqlRelated.PRIMARYID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.int) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( + key: SqlRelated.PRIMARY, + isRequired: false, + targetNames: ['primaryId'], + ofModelName: 'SqlPrimary' + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _SqlRelatedModelType extends amplify_core.ModelType { + const _SqlRelatedModelType(); + + @override + SqlRelated fromJson(Map jsonData) { + return SqlRelated.fromJson(jsonData); + } + + @override + String modelName() { + return 'SqlRelated'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [SqlRelated] in your schema. + */ +class SqlRelatedModelIdentifier implements amplify_core.ModelIdentifier { + final int id; + + /** Create an instance of SqlRelatedModelIdentifier using [id] the primary key. */ + const SqlRelatedModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'SqlRelatedModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is SqlRelatedModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references sets the association to the references field for hasOne and hasMany 1`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; +import 'package:collection/collection.dart'; + + +/** This is an auto generated class representing the Primary type in your schema. */ +class Primary extends amplify_core.Model { + static const classType = const _PrimaryModelType(); + final String id; + final List? _relatedMany; + final RelatedOne? _relatedOne; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + PrimaryModelIdentifier get modelIdentifier { + return PrimaryModelIdentifier( + id: id + ); + } + + List? get relatedMany { + return _relatedMany; + } + + RelatedOne? get relatedOne { + return _relatedOne; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const Primary._internal({required this.id, relatedMany, relatedOne, createdAt, updatedAt}): _relatedMany = relatedMany, _relatedOne = relatedOne, _createdAt = createdAt, _updatedAt = updatedAt; + + factory Primary({String? id, List? relatedMany, RelatedOne? relatedOne}) { + return Primary._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + relatedMany: relatedMany != null ? List.unmodifiable(relatedMany) : relatedMany, + relatedOne: relatedOne); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is Primary && + id == other.id && + DeepCollectionEquality().equals(_relatedMany, other._relatedMany) && + _relatedOne == other._relatedOne; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"Primary {\\"); + buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + Primary copyWith({List? relatedMany, RelatedOne? relatedOne}) { + return Primary._internal( + id: id, + relatedMany: relatedMany ?? this.relatedMany, + relatedOne: relatedOne ?? this.relatedOne); + } + + Primary copyWithModelFieldValues({ + ModelFieldValue?>? relatedMany, + ModelFieldValue? relatedOne + }) { + return Primary._internal( + id: id, + relatedMany: relatedMany == null ? this.relatedMany : relatedMany.value, + relatedOne: relatedOne == null ? this.relatedOne : relatedOne.value + ); + } + + Primary.fromJson(Map json) + : id = json['id'], + _relatedMany = json['relatedMany'] is List + ? (json['relatedMany'] as List) + .where((e) => e?['serializedData'] != null) + .map((e) => RelatedMany.fromJson(new Map.from(e['serializedData']))) + .toList() + : null, + _relatedOne = json['relatedOne']?['serializedData'] != null + ? RelatedOne.fromJson(new Map.from(json['relatedOne']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'relatedMany': _relatedMany?.map((RelatedMany? e) => e?.toJson()).toList(), 'relatedOne': _relatedOne?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'relatedMany': _relatedMany, + 'relatedOne': _relatedOne, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final RELATEDMANY = amplify_core.QueryField( + fieldName: \\"relatedMany\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'RelatedMany')); + static final RELATEDONE = amplify_core.QueryField( + fieldName: \\"relatedOne\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'RelatedOne')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"Primary\\"; + modelSchemaDefinition.pluralName = \\"Primaries\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"id\\"], name: null) + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasMany( + key: Primary.RELATEDMANY, + isRequired: false, + ofModelName: 'RelatedMany', + associatedKey: RelatedMany.PRIMARYID + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasOne( + key: Primary.RELATEDONE, + isRequired: false, + ofModelName: 'RelatedOne', + associatedKey: RelatedOne.PRIMARYID + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _PrimaryModelType extends amplify_core.ModelType { + const _PrimaryModelType(); + + @override + Primary fromJson(Map jsonData) { + return Primary.fromJson(jsonData); + } + + @override + String modelName() { + return 'Primary'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [Primary] in your schema. + */ +class PrimaryModelIdentifier implements amplify_core.ModelIdentifier { + final String id; + + /** Create an instance of PrimaryModelIdentifier using [id] the primary key. */ + const PrimaryModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'PrimaryModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is PrimaryModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references sets the association to the references field for hasOne and hasMany 2`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the RelatedOne type in your schema. */ +class RelatedOne extends amplify_core.Model { + static const classType = const _RelatedOneModelType(); + final String id; + final String? _primaryId; + final Primary? _primary; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + RelatedOneModelIdentifier get modelIdentifier { + return RelatedOneModelIdentifier( + id: id + ); + } + + String get primaryId { + try { + return _primaryId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + Primary? get primary { + return _primary; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const RelatedOne._internal({required this.id, required primaryId, primary, createdAt, updatedAt}): _primaryId = primaryId, _primary = primary, _createdAt = createdAt, _updatedAt = updatedAt; + + factory RelatedOne({String? id, required String primaryId, Primary? primary}) { + return RelatedOne._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + primaryId: primaryId, + primary: primary); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is RelatedOne && + id == other.id && + _primaryId == other._primaryId && + _primary == other._primary; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"RelatedOne {\\"); + buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); + buffer.write(\\"primaryId=\\" + \\"$_primaryId\\" + \\", \\"); + buffer.write(\\"primary=\\" + (_primary != null ? _primary!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + RelatedOne copyWith({String? primaryId, Primary? primary}) { + return RelatedOne._internal( + id: id, + primaryId: primaryId ?? this.primaryId, + primary: primary ?? this.primary); + } + + RelatedOne copyWithModelFieldValues({ + ModelFieldValue? primaryId, + ModelFieldValue? primary + }) { + return RelatedOne._internal( + id: id, + primaryId: primaryId == null ? this.primaryId : primaryId.value, + primary: primary == null ? this.primary : primary.value + ); + } + + RelatedOne.fromJson(Map json) + : id = json['id'], + _primaryId = json['primaryId'], + _primary = json['primary']?['serializedData'] != null + ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'primaryId': _primaryId, 'primary': _primary?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'primaryId': _primaryId, + 'primary': _primary, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final PRIMARYID = amplify_core.QueryField(fieldName: \\"primaryId\\"); + static final PRIMARY = amplify_core.QueryField( + fieldName: \\"primary\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Primary')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"RelatedOne\\"; + modelSchemaDefinition.pluralName = \\"RelatedOnes\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"id\\"], name: null) + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: RelatedOne.PRIMARYID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( + key: RelatedOne.PRIMARY, + isRequired: false, + targetNames: ['primaryId'], + ofModelName: 'Primary' + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _RelatedOneModelType extends amplify_core.ModelType { + const _RelatedOneModelType(); + + @override + RelatedOne fromJson(Map jsonData) { + return RelatedOne.fromJson(jsonData); + } + + @override + String modelName() { + return 'RelatedOne'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [RelatedOne] in your schema. + */ +class RelatedOneModelIdentifier implements amplify_core.ModelIdentifier { + final String id; + + /** Create an instance of RelatedOneModelIdentifier using [id] the primary key. */ + const RelatedOneModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'RelatedOneModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is RelatedOneModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references sets the association to the references field for hasOne and hasMany 3`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the RelatedMany type in your schema. */ +class RelatedMany extends amplify_core.Model { + static const classType = const _RelatedManyModelType(); + final String id; + final String? _primaryId; + final Primary? _primary; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + RelatedManyModelIdentifier get modelIdentifier { + return RelatedManyModelIdentifier( + id: id + ); + } + + String get primaryId { + try { + return _primaryId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + Primary? get primary { + return _primary; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const RelatedMany._internal({required this.id, required primaryId, primary, createdAt, updatedAt}): _primaryId = primaryId, _primary = primary, _createdAt = createdAt, _updatedAt = updatedAt; + + factory RelatedMany({String? id, required String primaryId, Primary? primary}) { + return RelatedMany._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + primaryId: primaryId, + primary: primary); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is RelatedMany && + id == other.id && + _primaryId == other._primaryId && + _primary == other._primary; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"RelatedMany {\\"); + buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); + buffer.write(\\"primaryId=\\" + \\"$_primaryId\\" + \\", \\"); + buffer.write(\\"primary=\\" + (_primary != null ? _primary!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + RelatedMany copyWith({String? primaryId, Primary? primary}) { + return RelatedMany._internal( + id: id, + primaryId: primaryId ?? this.primaryId, + primary: primary ?? this.primary); + } + + RelatedMany copyWithModelFieldValues({ + ModelFieldValue? primaryId, + ModelFieldValue? primary + }) { + return RelatedMany._internal( + id: id, + primaryId: primaryId == null ? this.primaryId : primaryId.value, + primary: primary == null ? this.primary : primary.value + ); + } + + RelatedMany.fromJson(Map json) + : id = json['id'], + _primaryId = json['primaryId'], + _primary = json['primary']?['serializedData'] != null + ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'primaryId': _primaryId, 'primary': _primary?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'primaryId': _primaryId, + 'primary': _primary, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final PRIMARYID = amplify_core.QueryField(fieldName: \\"primaryId\\"); + static final PRIMARY = amplify_core.QueryField( + fieldName: \\"primary\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Primary')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"RelatedMany\\"; + modelSchemaDefinition.pluralName = \\"RelatedManies\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"id\\"], name: null) + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: RelatedMany.PRIMARYID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( + key: RelatedMany.PRIMARY, + isRequired: false, + targetNames: ['primaryId'], + ofModelName: 'Primary' + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _RelatedManyModelType extends amplify_core.ModelType { + const _RelatedManyModelType(); + + @override + RelatedMany fromJson(Map jsonData) { + return RelatedMany.fromJson(jsonData); + } + + @override + String modelName() { + return 'RelatedMany'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [RelatedMany] in your schema. + */ +class RelatedManyModelIdentifier implements amplify_core.ModelIdentifier { + final String id; + + /** Create an instance of RelatedManyModelIdentifier using [id] the primary key. */ + const RelatedManyModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'RelatedManyModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is RelatedManyModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references sets the association to the references field for hasOne/belongsTo 1`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the SqlPrimary type in your schema. */ +class SqlPrimary extends amplify_core.Model { + static const classType = const _SqlPrimaryModelType(); + final int id; + final String? _content; + final SqlRelated? _related; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + SqlPrimaryModelIdentifier get modelIdentifier { + return SqlPrimaryModelIdentifier( + id: id + ); + } + + String? get content { + return _content; + } + + SqlRelated? get related { + return _related; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const SqlPrimary._internal({required this.id, content, related, createdAt, updatedAt}): _content = content, _related = related, _createdAt = createdAt, _updatedAt = updatedAt; + + factory SqlPrimary({int? id, String? content, SqlRelated? related}) { + return SqlPrimary._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + content: content, + related: related); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is SqlPrimary && + id == other.id && + _content == other._content && + _related == other._related; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"SqlPrimary {\\"); + buffer.write(\\"id=\\" + (id != null ? id!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + SqlPrimary copyWith({String? content, SqlRelated? related}) { + return SqlPrimary._internal( + id: id, + content: content ?? this.content, + related: related ?? this.related); + } + + SqlPrimary copyWithModelFieldValues({ + ModelFieldValue? content, + ModelFieldValue? related + }) { + return SqlPrimary._internal( + id: id, + content: content == null ? this.content : content.value, + related: related == null ? this.related : related.value + ); + } + + SqlPrimary.fromJson(Map json) + : id = (json['id'] as num?)?.toInt(), + _content = json['content'], + _related = json['related']?['serializedData'] != null + ? SqlRelated.fromJson(new Map.from(json['related']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'content': _content, 'related': _related?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'content': _content, + 'related': _related, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final CONTENT = amplify_core.QueryField(fieldName: \\"content\\"); + static final RELATED = amplify_core.QueryField( + fieldName: \\"related\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'SqlRelated')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"SqlPrimary\\"; + modelSchemaDefinition.pluralName = \\"SqlPrimaries\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"id\\"], name: null) + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: SqlPrimary.CONTENT, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasOne( + key: SqlPrimary.RELATED, + isRequired: false, + ofModelName: 'SqlRelated', + associatedKey: SqlRelated.PRIMARYID + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _SqlPrimaryModelType extends amplify_core.ModelType { + const _SqlPrimaryModelType(); + + @override + SqlPrimary fromJson(Map jsonData) { + return SqlPrimary.fromJson(jsonData); + } + + @override + String modelName() { + return 'SqlPrimary'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [SqlPrimary] in your schema. + */ +class SqlPrimaryModelIdentifier implements amplify_core.ModelIdentifier { + final int id; + + /** Create an instance of SqlPrimaryModelIdentifier using [id] the primary key. */ + const SqlPrimaryModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'SqlPrimaryModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is SqlPrimaryModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; + +exports[`AppSync Dart Visitor custom references sets the association to the references field for hasOne/belongsTo 2`] = ` +"/* +* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the \\"License\\"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the \\"license\\" file accompanying this file. This file is distributed +* on an \\"AS IS\\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +* express or implied. See the License for the specific language governing +* permissions and limitations under the License. +*/ + +// NOTE: This file is generated and may not follow lint rules defined in your app +// Generated files can be excluded from analysis in analysis_options.yaml +// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis + +// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously + +import 'ModelProvider.dart'; +import 'package:amplify_core/amplify_core.dart' as amplify_core; + + +/** This is an auto generated class representing the SqlRelated type in your schema. */ +class SqlRelated extends amplify_core.Model { + static const classType = const _SqlRelatedModelType(); + final int id; + final String? _content; + final int? _primaryId; + final SqlPrimary? _primary; + final amplify_core.TemporalDateTime? _createdAt; + final amplify_core.TemporalDateTime? _updatedAt; + + @override + getInstanceType() => classType; + + @Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.') + @override + String getId() => id; + + SqlRelatedModelIdentifier get modelIdentifier { + return SqlRelatedModelIdentifier( + id: id + ); + } + + String? get content { + return _content; + } + + int get primaryId { + try { + return _primaryId!; + } catch(e) { + throw amplify_core.AmplifyCodeGenModelException( + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastExceptionMessage, + recoverySuggestion: + amplify_core.AmplifyExceptionMessages.codeGenRequiredFieldForceCastRecoverySuggestion, + underlyingException: e.toString() + ); + } + } + + SqlPrimary? get primary { + return _primary; + } + + amplify_core.TemporalDateTime? get createdAt { + return _createdAt; + } + + amplify_core.TemporalDateTime? get updatedAt { + return _updatedAt; + } + + const SqlRelated._internal({required this.id, content, required primaryId, primary, createdAt, updatedAt}): _content = content, _primaryId = primaryId, _primary = primary, _createdAt = createdAt, _updatedAt = updatedAt; + + factory SqlRelated({int? id, String? content, required int primaryId, SqlPrimary? primary}) { + return SqlRelated._internal( + id: id == null ? amplify_core.UUID.getUUID() : id, + content: content, + primaryId: primaryId, + primary: primary); + } + + bool equals(Object other) { + return this == other; + } + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is SqlRelated && + id == other.id && + _content == other._content && + _primaryId == other._primaryId && + _primary == other._primary; + } + + @override + int get hashCode => toString().hashCode; + + @override + String toString() { + var buffer = new StringBuffer(); + + buffer.write(\\"SqlRelated {\\"); + buffer.write(\\"id=\\" + (id != null ? id!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); + buffer.write(\\"primaryId=\\" + (_primaryId != null ? _primaryId!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"primary=\\" + (_primary != null ? _primary!.toString() : \\"null\\") + \\", \\"); + buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"}\\"); + + return buffer.toString(); + } + + SqlRelated copyWith({String? content, int? primaryId, SqlPrimary? primary}) { + return SqlRelated._internal( + id: id, + content: content ?? this.content, + primaryId: primaryId ?? this.primaryId, + primary: primary ?? this.primary); + } + + SqlRelated copyWithModelFieldValues({ + ModelFieldValue? content, + ModelFieldValue? primaryId, + ModelFieldValue? primary + }) { + return SqlRelated._internal( + id: id, + content: content == null ? this.content : content.value, + primaryId: primaryId == null ? this.primaryId : primaryId.value, + primary: primary == null ? this.primary : primary.value + ); + } + + SqlRelated.fromJson(Map json) + : id = (json['id'] as num?)?.toInt(), + _content = json['content'], + _primaryId = (json['primaryId'] as num?)?.toInt(), + _primary = json['primary']?['serializedData'] != null + ? SqlPrimary.fromJson(new Map.from(json['primary']['serializedData'])) + : null, + _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + + Map toJson() => { + 'id': id, 'content': _content, 'primaryId': _primaryId, 'primary': _primary?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + }; + + Map toMap() => { + 'id': id, + 'content': _content, + 'primaryId': _primaryId, + 'primary': _primary, + 'createdAt': _createdAt, + 'updatedAt': _updatedAt + }; + + static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); + static final ID = amplify_core.QueryField(fieldName: \\"id\\"); + static final CONTENT = amplify_core.QueryField(fieldName: \\"content\\"); + static final PRIMARYID = amplify_core.QueryField(fieldName: \\"primaryId\\"); + static final PRIMARY = amplify_core.QueryField( + fieldName: \\"primary\\", + fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'SqlPrimary')); + static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { + modelSchemaDefinition.name = \\"SqlRelated\\"; + modelSchemaDefinition.pluralName = \\"SqlRelateds\\"; + + modelSchemaDefinition.indexes = [ + amplify_core.ModelIndex(fields: const [\\"id\\"], name: null), + amplify_core.ModelIndex(fields: const [\\"primaryId\\"], name: \\"primary_id\\") + ]; + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.id()); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: SqlRelated.CONTENT, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: SqlRelated.PRIMARYID, + isRequired: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.int) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( + key: SqlRelated.PRIMARY, + isRequired: false, + targetNames: ['primaryId'], + ofModelName: 'SqlPrimary' + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'createdAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( + fieldName: 'updatedAt', + isRequired: false, + isReadOnly: true, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) + )); + }); +} + +class _SqlRelatedModelType extends amplify_core.ModelType { + const _SqlRelatedModelType(); + + @override + SqlRelated fromJson(Map jsonData) { + return SqlRelated.fromJson(jsonData); + } + + @override + String modelName() { + return 'SqlRelated'; + } +} + +/** + * This is an auto generated class representing the model identifier + * of [SqlRelated] in your schema. + */ +class SqlRelatedModelIdentifier implements amplify_core.ModelIdentifier { + final int id; + + /** Create an instance of SqlRelatedModelIdentifier using [id] the primary key. */ + const SqlRelatedModelIdentifier({ + required this.id}); + + @override + Map serializeAsMap() => ({ + 'id': id + }); + + @override + List> serializeAsList() => serializeAsMap() + .entries + .map((entry) => ({ entry.key: entry.value })) + .toList(); + + @override + String serializeAsString() => serializeAsMap().values.join('#'); + + @override + String toString() => 'SqlRelatedModelIdentifier(id: $id)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is SqlRelatedModelIdentifier && + id == other.id; + } + + @override + int get hashCode => + id.hashCode; +}" +`; diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-java-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-java-visitor.test.ts.snap index b973bf217..d82be5ff2 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-java-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-java-visitor.test.ts.snap @@ -7845,6 +7845,3079 @@ public final class Todo implements Model { " `; +exports[`AppSyncModelVisitor custom references double linked references 1`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.HasOne; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the Foo type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"Foos\\", type = Model.Type.USER, version = 1) +public final class Foo implements Model { + public static final QueryField ID = field(\\"Foo\\", \\"id\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; + private final @ModelField(targetType=\\"Bar\\") @HasOne(associatedWith = \\"bar1Id\\", type = Bar.class) Bar bar1 = null; + private final @ModelField(targetType=\\"Bar\\") @HasOne(associatedWith = \\"bar2Id\\", type = Bar.class) Bar bar2 = null; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public String resolveIdentifier() { + return id; + } + + public String getId() { + return id; + } + + public Bar getBar1() { + return bar1; + } + + public Bar getBar2() { + return bar2; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private Foo(String id) { + this.id = id; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + Foo foo = (Foo) obj; + return ObjectsCompat.equals(getId(), foo.getId()) && + ObjectsCompat.equals(getCreatedAt(), foo.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), foo.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"Foo {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static BuildStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static Foo justId(String id) { + return new Foo( + id + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id); + } + public interface BuildStep { + Foo build(); + BuildStep id(String id); + } + + + public static class Builder implements BuildStep { + private String id; + public Builder() { + + } + + private Builder(String id) { + this.id = id; + } + + @Override + public Foo build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new Foo( + id); + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String id) { + super(id); + + } + } + + + public static class FooIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public FooIdentifier(String id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references double linked references 2`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.BelongsTo; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the Bar type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"Bars\\", type = Model.Type.USER, version = 1) +public final class Bar implements Model { + public static final QueryField ID = field(\\"Bar\\", \\"id\\"); + public static final QueryField BAR1_ID = field(\\"Bar\\", \\"bar1Id\\"); + public static final QueryField BAR2_ID = field(\\"Bar\\", \\"bar2Id\\"); + public static final QueryField FOO1 = field(\\"Bar\\", \\"bar1Id\\"); + public static final QueryField FOO2 = field(\\"Bar\\", \\"bar2Id\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; + private final @ModelField(targetType=\\"ID\\") String bar1Id; + private final @ModelField(targetType=\\"ID\\") String bar2Id; + private final @ModelField(targetType=\\"Foo\\") @BelongsTo(targetName = \\"bar1Id\\", targetNames = {\\"bar1Id\\"}, type = Foo.class) Foo foo1; + private final @ModelField(targetType=\\"Foo\\") @BelongsTo(targetName = \\"bar2Id\\", targetNames = {\\"bar2Id\\"}, type = Foo.class) Foo foo2; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public String resolveIdentifier() { + return id; + } + + public String getId() { + return id; + } + + public String getBar1Id() { + return bar1Id; + } + + public String getBar2Id() { + return bar2Id; + } + + public Foo getFoo1() { + return foo1; + } + + public Foo getFoo2() { + return foo2; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private Bar(String id, String bar1Id, String bar2Id, Foo foo1, Foo foo2) { + this.id = id; + this.bar1Id = bar1Id; + this.bar2Id = bar2Id; + this.foo1 = foo1; + this.foo2 = foo2; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + Bar bar = (Bar) obj; + return ObjectsCompat.equals(getId(), bar.getId()) && + ObjectsCompat.equals(getBar1Id(), bar.getBar1Id()) && + ObjectsCompat.equals(getBar2Id(), bar.getBar2Id()) && + ObjectsCompat.equals(getFoo1(), bar.getFoo1()) && + ObjectsCompat.equals(getFoo2(), bar.getFoo2()) && + ObjectsCompat.equals(getCreatedAt(), bar.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), bar.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getBar1Id()) + .append(getBar2Id()) + .append(getFoo1()) + .append(getFoo2()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"Bar {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"bar1Id=\\" + String.valueOf(getBar1Id()) + \\", \\") + .append(\\"bar2Id=\\" + String.valueOf(getBar2Id()) + \\", \\") + .append(\\"foo1=\\" + String.valueOf(getFoo1()) + \\", \\") + .append(\\"foo2=\\" + String.valueOf(getFoo2()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static BuildStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static Bar justId(String id) { + return new Bar( + id, + null, + null, + null, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + bar1Id, + bar2Id, + foo1, + foo2); + } + public interface BuildStep { + Bar build(); + BuildStep id(String id); + BuildStep bar1Id(String bar1Id); + BuildStep bar2Id(String bar2Id); + BuildStep foo1(Foo foo1); + BuildStep foo2(Foo foo2); + } + + + public static class Builder implements BuildStep { + private String id; + private String bar1Id; + private String bar2Id; + private Foo foo1; + private Foo foo2; + public Builder() { + + } + + private Builder(String id, String bar1Id, String bar2Id, Foo foo1, Foo foo2) { + this.id = id; + this.bar1Id = bar1Id; + this.bar2Id = bar2Id; + this.foo1 = foo1; + this.foo2 = foo2; + } + + @Override + public Bar build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new Bar( + id, + bar1Id, + bar2Id, + foo1, + foo2); + } + + @Override + public BuildStep bar1Id(String bar1Id) { + this.bar1Id = bar1Id; + return this; + } + + @Override + public BuildStep bar2Id(String bar2Id) { + this.bar2Id = bar2Id; + return this; + } + + @Override + public BuildStep foo1(Foo foo1) { + this.foo1 = foo1; + return this; + } + + @Override + public BuildStep foo2(Foo foo2) { + this.foo2 = foo2; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String id, String bar1Id, String bar2Id, Foo foo1, Foo foo2) { + super(id, bar1Id, bar2Id, foo1, foo2); + + } + + @Override + public CopyOfBuilder bar1Id(String bar1Id) { + return (CopyOfBuilder) super.bar1Id(bar1Id); + } + + @Override + public CopyOfBuilder bar2Id(String bar2Id) { + return (CopyOfBuilder) super.bar2Id(bar2Id); + } + + @Override + public CopyOfBuilder foo1(Foo foo1) { + return (CopyOfBuilder) super.foo1(foo1); + } + + @Override + public CopyOfBuilder foo2(Foo foo2) { + return (CopyOfBuilder) super.foo2(foo2); + } + } + + + public static class BarIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public BarIdentifier(String id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references hasMany with sortKeyFields on primary key 1`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.HasMany; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the Primary type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"Primaries\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"tenantId\\",\\"instanceId\\",\\"recordId\\"}) +public final class Primary implements Model { + public static final QueryField TENANT_ID = field(\\"Primary\\", \\"tenantId\\"); + public static final QueryField INSTANCE_ID = field(\\"Primary\\", \\"instanceId\\"); + public static final QueryField RECORD_ID = field(\\"Primary\\", \\"recordId\\"); + public static final QueryField CONTENT = field(\\"Primary\\", \\"content\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String tenantId; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String instanceId; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String recordId; + private final @ModelField(targetType=\\"String\\") String content; + private final @ModelField(targetType=\\"Related\\") @HasMany(associatedWith = \\"primaryTenantId\\", type = Related.class) List related = null; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + private PrimaryIdentifier primaryIdentifier; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public PrimaryIdentifier resolveIdentifier() { + if (primaryIdentifier == null) { + this.primaryIdentifier = new PrimaryIdentifier(tenantId, instanceId, recordId); + } + return primaryIdentifier; + } + + public String getTenantId() { + return tenantId; + } + + public String getInstanceId() { + return instanceId; + } + + public String getRecordId() { + return recordId; + } + + public String getContent() { + return content; + } + + public List getRelated() { + return related; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private Primary(String tenantId, String instanceId, String recordId, String content) { + this.tenantId = tenantId; + this.instanceId = instanceId; + this.recordId = recordId; + this.content = content; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + Primary primary = (Primary) obj; + return ObjectsCompat.equals(getTenantId(), primary.getTenantId()) && + ObjectsCompat.equals(getInstanceId(), primary.getInstanceId()) && + ObjectsCompat.equals(getRecordId(), primary.getRecordId()) && + ObjectsCompat.equals(getContent(), primary.getContent()) && + ObjectsCompat.equals(getCreatedAt(), primary.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), primary.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getTenantId()) + .append(getInstanceId()) + .append(getRecordId()) + .append(getContent()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"Primary {\\") + .append(\\"tenantId=\\" + String.valueOf(getTenantId()) + \\", \\") + .append(\\"instanceId=\\" + String.valueOf(getInstanceId()) + \\", \\") + .append(\\"recordId=\\" + String.valueOf(getRecordId()) + \\", \\") + .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static TenantIdStep builder() { + return new Builder(); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(tenantId, + instanceId, + recordId, + content); + } + public interface TenantIdStep { + InstanceIdStep tenantId(String tenantId); + } + + + public interface InstanceIdStep { + RecordIdStep instanceId(String instanceId); + } + + + public interface RecordIdStep { + BuildStep recordId(String recordId); + } + + + public interface BuildStep { + Primary build(); + BuildStep content(String content); + } + + + public static class Builder implements TenantIdStep, InstanceIdStep, RecordIdStep, BuildStep { + private String tenantId; + private String instanceId; + private String recordId; + private String content; + public Builder() { + + } + + private Builder(String tenantId, String instanceId, String recordId, String content) { + this.tenantId = tenantId; + this.instanceId = instanceId; + this.recordId = recordId; + this.content = content; + } + + @Override + public Primary build() { + + return new Primary( + tenantId, + instanceId, + recordId, + content); + } + + @Override + public InstanceIdStep tenantId(String tenantId) { + Objects.requireNonNull(tenantId); + this.tenantId = tenantId; + return this; + } + + @Override + public RecordIdStep instanceId(String instanceId) { + Objects.requireNonNull(instanceId); + this.instanceId = instanceId; + return this; + } + + @Override + public BuildStep recordId(String recordId) { + Objects.requireNonNull(recordId); + this.recordId = recordId; + return this; + } + + @Override + public BuildStep content(String content) { + this.content = content; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String tenantId, String instanceId, String recordId, String content) { + super(tenantId, instanceId, recordId, content); + Objects.requireNonNull(tenantId); + Objects.requireNonNull(instanceId); + Objects.requireNonNull(recordId); + } + + @Override + public CopyOfBuilder tenantId(String tenantId) { + return (CopyOfBuilder) super.tenantId(tenantId); + } + + @Override + public CopyOfBuilder instanceId(String instanceId) { + return (CopyOfBuilder) super.instanceId(instanceId); + } + + @Override + public CopyOfBuilder recordId(String recordId) { + return (CopyOfBuilder) super.recordId(recordId); + } + + @Override + public CopyOfBuilder content(String content) { + return (CopyOfBuilder) super.content(content); + } + } + + + public static class PrimaryIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public PrimaryIdentifier(String tenantId, String instanceId, String recordId) { + super(tenantId, instanceId, recordId); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references hasMany with sortKeyFields on primary key 2`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.BelongsTo; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the Related type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"Relateds\\", type = Model.Type.USER, version = 1) +public final class Related implements Model { + public static final QueryField ID = field(\\"Related\\", \\"id\\"); + public static final QueryField CONTENT = field(\\"Related\\", \\"content\\"); + public static final QueryField PRIMARY_TENANT_ID = field(\\"Related\\", \\"primaryTenantId\\"); + public static final QueryField PRIMARY_INSTANCE_ID = field(\\"Related\\", \\"primaryInstanceId\\"); + public static final QueryField PRIMARY_RECORD_ID = field(\\"Related\\", \\"primaryRecordId\\"); + public static final QueryField PRIMARY = field(\\"Related\\", \\"primaryTenantId\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; + private final @ModelField(targetType=\\"String\\") String content; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryTenantId; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryInstanceId; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryRecordId; + private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryTenantId\\", targetNames = {\\"primaryTenantId\\", \\"primaryInstanceId\\", \\"primaryRecordId\\"}, type = Primary.class) Primary primary; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public String resolveIdentifier() { + return id; + } + + public String getId() { + return id; + } + + public String getContent() { + return content; + } + + public String getPrimaryTenantId() { + return primaryTenantId; + } + + public String getPrimaryInstanceId() { + return primaryInstanceId; + } + + public String getPrimaryRecordId() { + return primaryRecordId; + } + + public Primary getPrimary() { + return primary; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private Related(String id, String content, String primaryTenantId, String primaryInstanceId, String primaryRecordId, Primary primary) { + this.id = id; + this.content = content; + this.primaryTenantId = primaryTenantId; + this.primaryInstanceId = primaryInstanceId; + this.primaryRecordId = primaryRecordId; + this.primary = primary; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + Related related = (Related) obj; + return ObjectsCompat.equals(getId(), related.getId()) && + ObjectsCompat.equals(getContent(), related.getContent()) && + ObjectsCompat.equals(getPrimaryTenantId(), related.getPrimaryTenantId()) && + ObjectsCompat.equals(getPrimaryInstanceId(), related.getPrimaryInstanceId()) && + ObjectsCompat.equals(getPrimaryRecordId(), related.getPrimaryRecordId()) && + ObjectsCompat.equals(getPrimary(), related.getPrimary()) && + ObjectsCompat.equals(getCreatedAt(), related.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), related.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getContent()) + .append(getPrimaryTenantId()) + .append(getPrimaryInstanceId()) + .append(getPrimaryRecordId()) + .append(getPrimary()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"Related {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") + .append(\\"primaryTenantId=\\" + String.valueOf(getPrimaryTenantId()) + \\", \\") + .append(\\"primaryInstanceId=\\" + String.valueOf(getPrimaryInstanceId()) + \\", \\") + .append(\\"primaryRecordId=\\" + String.valueOf(getPrimaryRecordId()) + \\", \\") + .append(\\"primary=\\" + String.valueOf(getPrimary()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static PrimaryTenantIdStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static Related justId(String id) { + return new Related( + id, + null, + null, + null, + null, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + content, + primaryTenantId, + primaryInstanceId, + primaryRecordId, + primary); + } + public interface PrimaryTenantIdStep { + PrimaryInstanceIdStep primaryTenantId(String primaryTenantId); + } + + + public interface PrimaryInstanceIdStep { + PrimaryRecordIdStep primaryInstanceId(String primaryInstanceId); + } + + + public interface PrimaryRecordIdStep { + BuildStep primaryRecordId(String primaryRecordId); + } + + + public interface BuildStep { + Related build(); + BuildStep id(String id); + BuildStep content(String content); + BuildStep primary(Primary primary); + } + + + public static class Builder implements PrimaryTenantIdStep, PrimaryInstanceIdStep, PrimaryRecordIdStep, BuildStep { + private String id; + private String primaryTenantId; + private String primaryInstanceId; + private String primaryRecordId; + private String content; + private Primary primary; + public Builder() { + + } + + private Builder(String id, String content, String primaryTenantId, String primaryInstanceId, String primaryRecordId, Primary primary) { + this.id = id; + this.content = content; + this.primaryTenantId = primaryTenantId; + this.primaryInstanceId = primaryInstanceId; + this.primaryRecordId = primaryRecordId; + this.primary = primary; + } + + @Override + public Related build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new Related( + id, + content, + primaryTenantId, + primaryInstanceId, + primaryRecordId, + primary); + } + + @Override + public PrimaryInstanceIdStep primaryTenantId(String primaryTenantId) { + Objects.requireNonNull(primaryTenantId); + this.primaryTenantId = primaryTenantId; + return this; + } + + @Override + public PrimaryRecordIdStep primaryInstanceId(String primaryInstanceId) { + Objects.requireNonNull(primaryInstanceId); + this.primaryInstanceId = primaryInstanceId; + return this; + } + + @Override + public BuildStep primaryRecordId(String primaryRecordId) { + Objects.requireNonNull(primaryRecordId); + this.primaryRecordId = primaryRecordId; + return this; + } + + @Override + public BuildStep content(String content) { + this.content = content; + return this; + } + + @Override + public BuildStep primary(Primary primary) { + this.primary = primary; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String id, String content, String primaryTenantId, String primaryInstanceId, String primaryRecordId, Primary primary) { + super(id, content, primaryTenantId, primaryInstanceId, primaryRecordId, primary); + Objects.requireNonNull(primaryTenantId); + Objects.requireNonNull(primaryInstanceId); + Objects.requireNonNull(primaryRecordId); + } + + @Override + public CopyOfBuilder primaryTenantId(String primaryTenantId) { + return (CopyOfBuilder) super.primaryTenantId(primaryTenantId); + } + + @Override + public CopyOfBuilder primaryInstanceId(String primaryInstanceId) { + return (CopyOfBuilder) super.primaryInstanceId(primaryInstanceId); + } + + @Override + public CopyOfBuilder primaryRecordId(String primaryRecordId) { + return (CopyOfBuilder) super.primaryRecordId(primaryRecordId); + } + + @Override + public CopyOfBuilder content(String content) { + return (CopyOfBuilder) super.content(content); + } + + @Override + public CopyOfBuilder primary(Primary primary) { + return (CopyOfBuilder) super.primary(primary); + } + } + + + public static class RelatedIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public RelatedIdentifier(String id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references hasOne with sortKeyFields on primary key 1`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.HasOne; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the Primary type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"Primaries\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"tenantId\\",\\"instanceId\\",\\"recordId\\"}) +public final class Primary implements Model { + public static final QueryField TENANT_ID = field(\\"Primary\\", \\"tenantId\\"); + public static final QueryField INSTANCE_ID = field(\\"Primary\\", \\"instanceId\\"); + public static final QueryField RECORD_ID = field(\\"Primary\\", \\"recordId\\"); + public static final QueryField CONTENT = field(\\"Primary\\", \\"content\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String tenantId; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String instanceId; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String recordId; + private final @ModelField(targetType=\\"String\\") String content; + private final @ModelField(targetType=\\"Related\\") @HasOne(associatedWith = \\"primaryTenantId\\", type = Related.class) Related related = null; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + private PrimaryIdentifier primaryIdentifier; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public PrimaryIdentifier resolveIdentifier() { + if (primaryIdentifier == null) { + this.primaryIdentifier = new PrimaryIdentifier(tenantId, instanceId, recordId); + } + return primaryIdentifier; + } + + public String getTenantId() { + return tenantId; + } + + public String getInstanceId() { + return instanceId; + } + + public String getRecordId() { + return recordId; + } + + public String getContent() { + return content; + } + + public Related getRelated() { + return related; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private Primary(String tenantId, String instanceId, String recordId, String content) { + this.tenantId = tenantId; + this.instanceId = instanceId; + this.recordId = recordId; + this.content = content; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + Primary primary = (Primary) obj; + return ObjectsCompat.equals(getTenantId(), primary.getTenantId()) && + ObjectsCompat.equals(getInstanceId(), primary.getInstanceId()) && + ObjectsCompat.equals(getRecordId(), primary.getRecordId()) && + ObjectsCompat.equals(getContent(), primary.getContent()) && + ObjectsCompat.equals(getCreatedAt(), primary.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), primary.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getTenantId()) + .append(getInstanceId()) + .append(getRecordId()) + .append(getContent()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"Primary {\\") + .append(\\"tenantId=\\" + String.valueOf(getTenantId()) + \\", \\") + .append(\\"instanceId=\\" + String.valueOf(getInstanceId()) + \\", \\") + .append(\\"recordId=\\" + String.valueOf(getRecordId()) + \\", \\") + .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static TenantIdStep builder() { + return new Builder(); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(tenantId, + instanceId, + recordId, + content); + } + public interface TenantIdStep { + InstanceIdStep tenantId(String tenantId); + } + + + public interface InstanceIdStep { + RecordIdStep instanceId(String instanceId); + } + + + public interface RecordIdStep { + BuildStep recordId(String recordId); + } + + + public interface BuildStep { + Primary build(); + BuildStep content(String content); + } + + + public static class Builder implements TenantIdStep, InstanceIdStep, RecordIdStep, BuildStep { + private String tenantId; + private String instanceId; + private String recordId; + private String content; + public Builder() { + + } + + private Builder(String tenantId, String instanceId, String recordId, String content) { + this.tenantId = tenantId; + this.instanceId = instanceId; + this.recordId = recordId; + this.content = content; + } + + @Override + public Primary build() { + + return new Primary( + tenantId, + instanceId, + recordId, + content); + } + + @Override + public InstanceIdStep tenantId(String tenantId) { + Objects.requireNonNull(tenantId); + this.tenantId = tenantId; + return this; + } + + @Override + public RecordIdStep instanceId(String instanceId) { + Objects.requireNonNull(instanceId); + this.instanceId = instanceId; + return this; + } + + @Override + public BuildStep recordId(String recordId) { + Objects.requireNonNull(recordId); + this.recordId = recordId; + return this; + } + + @Override + public BuildStep content(String content) { + this.content = content; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String tenantId, String instanceId, String recordId, String content) { + super(tenantId, instanceId, recordId, content); + Objects.requireNonNull(tenantId); + Objects.requireNonNull(instanceId); + Objects.requireNonNull(recordId); + } + + @Override + public CopyOfBuilder tenantId(String tenantId) { + return (CopyOfBuilder) super.tenantId(tenantId); + } + + @Override + public CopyOfBuilder instanceId(String instanceId) { + return (CopyOfBuilder) super.instanceId(instanceId); + } + + @Override + public CopyOfBuilder recordId(String recordId) { + return (CopyOfBuilder) super.recordId(recordId); + } + + @Override + public CopyOfBuilder content(String content) { + return (CopyOfBuilder) super.content(content); + } + } + + + public static class PrimaryIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public PrimaryIdentifier(String tenantId, String instanceId, String recordId) { + super(tenantId, instanceId, recordId); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references hasOne with sortKeyFields on primary key 2`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.BelongsTo; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the Related type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"Relateds\\", type = Model.Type.USER, version = 1) +public final class Related implements Model { + public static final QueryField ID = field(\\"Related\\", \\"id\\"); + public static final QueryField CONTENT = field(\\"Related\\", \\"content\\"); + public static final QueryField PRIMARY_TENANT_ID = field(\\"Related\\", \\"primaryTenantId\\"); + public static final QueryField PRIMARY_INSTANCE_ID = field(\\"Related\\", \\"primaryInstanceId\\"); + public static final QueryField PRIMARY_RECORD_ID = field(\\"Related\\", \\"primaryRecordId\\"); + public static final QueryField PRIMARY = field(\\"Related\\", \\"primaryTenantId\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; + private final @ModelField(targetType=\\"String\\") String content; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryTenantId; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryInstanceId; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryRecordId; + private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryTenantId\\", targetNames = {\\"primaryTenantId\\", \\"primaryInstanceId\\", \\"primaryRecordId\\"}, type = Primary.class) Primary primary; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public String resolveIdentifier() { + return id; + } + + public String getId() { + return id; + } + + public String getContent() { + return content; + } + + public String getPrimaryTenantId() { + return primaryTenantId; + } + + public String getPrimaryInstanceId() { + return primaryInstanceId; + } + + public String getPrimaryRecordId() { + return primaryRecordId; + } + + public Primary getPrimary() { + return primary; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private Related(String id, String content, String primaryTenantId, String primaryInstanceId, String primaryRecordId, Primary primary) { + this.id = id; + this.content = content; + this.primaryTenantId = primaryTenantId; + this.primaryInstanceId = primaryInstanceId; + this.primaryRecordId = primaryRecordId; + this.primary = primary; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + Related related = (Related) obj; + return ObjectsCompat.equals(getId(), related.getId()) && + ObjectsCompat.equals(getContent(), related.getContent()) && + ObjectsCompat.equals(getPrimaryTenantId(), related.getPrimaryTenantId()) && + ObjectsCompat.equals(getPrimaryInstanceId(), related.getPrimaryInstanceId()) && + ObjectsCompat.equals(getPrimaryRecordId(), related.getPrimaryRecordId()) && + ObjectsCompat.equals(getPrimary(), related.getPrimary()) && + ObjectsCompat.equals(getCreatedAt(), related.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), related.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getContent()) + .append(getPrimaryTenantId()) + .append(getPrimaryInstanceId()) + .append(getPrimaryRecordId()) + .append(getPrimary()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"Related {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") + .append(\\"primaryTenantId=\\" + String.valueOf(getPrimaryTenantId()) + \\", \\") + .append(\\"primaryInstanceId=\\" + String.valueOf(getPrimaryInstanceId()) + \\", \\") + .append(\\"primaryRecordId=\\" + String.valueOf(getPrimaryRecordId()) + \\", \\") + .append(\\"primary=\\" + String.valueOf(getPrimary()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static PrimaryTenantIdStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static Related justId(String id) { + return new Related( + id, + null, + null, + null, + null, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + content, + primaryTenantId, + primaryInstanceId, + primaryRecordId, + primary); + } + public interface PrimaryTenantIdStep { + PrimaryInstanceIdStep primaryTenantId(String primaryTenantId); + } + + + public interface PrimaryInstanceIdStep { + PrimaryRecordIdStep primaryInstanceId(String primaryInstanceId); + } + + + public interface PrimaryRecordIdStep { + BuildStep primaryRecordId(String primaryRecordId); + } + + + public interface BuildStep { + Related build(); + BuildStep id(String id); + BuildStep content(String content); + BuildStep primary(Primary primary); + } + + + public static class Builder implements PrimaryTenantIdStep, PrimaryInstanceIdStep, PrimaryRecordIdStep, BuildStep { + private String id; + private String primaryTenantId; + private String primaryInstanceId; + private String primaryRecordId; + private String content; + private Primary primary; + public Builder() { + + } + + private Builder(String id, String content, String primaryTenantId, String primaryInstanceId, String primaryRecordId, Primary primary) { + this.id = id; + this.content = content; + this.primaryTenantId = primaryTenantId; + this.primaryInstanceId = primaryInstanceId; + this.primaryRecordId = primaryRecordId; + this.primary = primary; + } + + @Override + public Related build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new Related( + id, + content, + primaryTenantId, + primaryInstanceId, + primaryRecordId, + primary); + } + + @Override + public PrimaryInstanceIdStep primaryTenantId(String primaryTenantId) { + Objects.requireNonNull(primaryTenantId); + this.primaryTenantId = primaryTenantId; + return this; + } + + @Override + public PrimaryRecordIdStep primaryInstanceId(String primaryInstanceId) { + Objects.requireNonNull(primaryInstanceId); + this.primaryInstanceId = primaryInstanceId; + return this; + } + + @Override + public BuildStep primaryRecordId(String primaryRecordId) { + Objects.requireNonNull(primaryRecordId); + this.primaryRecordId = primaryRecordId; + return this; + } + + @Override + public BuildStep content(String content) { + this.content = content; + return this; + } + + @Override + public BuildStep primary(Primary primary) { + this.primary = primary; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String id, String content, String primaryTenantId, String primaryInstanceId, String primaryRecordId, Primary primary) { + super(id, content, primaryTenantId, primaryInstanceId, primaryRecordId, primary); + Objects.requireNonNull(primaryTenantId); + Objects.requireNonNull(primaryInstanceId); + Objects.requireNonNull(primaryRecordId); + } + + @Override + public CopyOfBuilder primaryTenantId(String primaryTenantId) { + return (CopyOfBuilder) super.primaryTenantId(primaryTenantId); + } + + @Override + public CopyOfBuilder primaryInstanceId(String primaryInstanceId) { + return (CopyOfBuilder) super.primaryInstanceId(primaryInstanceId); + } + + @Override + public CopyOfBuilder primaryRecordId(String primaryRecordId) { + return (CopyOfBuilder) super.primaryRecordId(primaryRecordId); + } + + @Override + public CopyOfBuilder content(String content) { + return (CopyOfBuilder) super.content(content); + } + + @Override + public CopyOfBuilder primary(Primary primary) { + return (CopyOfBuilder) super.primary(primary); + } + } + + + public static class RelatedIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public RelatedIdentifier(String id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references sets the association to the references field for hasMany/belongsTo 1`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.HasMany; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the SqlPrimary type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"SqlPrimaries\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"id\\"}) +public final class SqlPrimary implements Model { + public static final QueryField ID = field(\\"SqlPrimary\\", \\"id\\"); + public static final QueryField CONTENT = field(\\"SqlPrimary\\", \\"content\\"); + private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer id; + private final @ModelField(targetType=\\"String\\") String content; + private final @ModelField(targetType=\\"SqlRelated\\") @HasMany(associatedWith = \\"primaryId\\", type = SqlRelated.class) List related = null; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public Integer resolveIdentifier() { + return id; + } + + public Integer getId() { + return id; + } + + public String getContent() { + return content; + } + + public List getRelated() { + return related; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private SqlPrimary(Integer id, String content) { + this.id = id; + this.content = content; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + SqlPrimary sqlPrimary = (SqlPrimary) obj; + return ObjectsCompat.equals(getId(), sqlPrimary.getId()) && + ObjectsCompat.equals(getContent(), sqlPrimary.getContent()) && + ObjectsCompat.equals(getCreatedAt(), sqlPrimary.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), sqlPrimary.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getContent()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"SqlPrimary {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static BuildStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static SqlPrimary justId(String id) { + return new SqlPrimary( + id, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + content); + } + public interface BuildStep { + SqlPrimary build(); + BuildStep id(String id); + BuildStep content(String content); + } + + + public static class Builder implements BuildStep { + private Integer id; + private String content; + public Builder() { + + } + + private Builder(Integer id, String content) { + this.id = id; + this.content = content; + } + + @Override + public SqlPrimary build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new SqlPrimary( + id, + content); + } + + @Override + public BuildStep content(String content) { + this.content = content; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(Integer id, String content) { + super(id, content); + + } + + @Override + public CopyOfBuilder content(String content) { + return (CopyOfBuilder) super.content(content); + } + } + + + public static class SqlPrimaryIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public SqlPrimaryIdentifier(Integer id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references sets the association to the references field for hasMany/belongsTo 2`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.BelongsTo; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the SqlRelated type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"SqlRelateds\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"id\\"}) +@Index(name = \\"primary_id\\", fields = {\\"primaryId\\"}) +public final class SqlRelated implements Model { + public static final QueryField ID = field(\\"SqlRelated\\", \\"id\\"); + public static final QueryField CONTENT = field(\\"SqlRelated\\", \\"content\\"); + public static final QueryField PRIMARY_ID = field(\\"SqlRelated\\", \\"primaryId\\"); + public static final QueryField PRIMARY = field(\\"SqlRelated\\", \\"primaryId\\"); + private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer id; + private final @ModelField(targetType=\\"String\\") String content; + private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer primaryId; + private final @ModelField(targetType=\\"SqlPrimary\\") @BelongsTo(targetName = \\"primaryId\\", targetNames = {\\"primaryId\\"}, type = SqlPrimary.class) SqlPrimary primary; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public Integer resolveIdentifier() { + return id; + } + + public Integer getId() { + return id; + } + + public String getContent() { + return content; + } + + public Integer getPrimaryId() { + return primaryId; + } + + public SqlPrimary getPrimary() { + return primary; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private SqlRelated(Integer id, String content, Integer primaryId, SqlPrimary primary) { + this.id = id; + this.content = content; + this.primaryId = primaryId; + this.primary = primary; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + SqlRelated sqlRelated = (SqlRelated) obj; + return ObjectsCompat.equals(getId(), sqlRelated.getId()) && + ObjectsCompat.equals(getContent(), sqlRelated.getContent()) && + ObjectsCompat.equals(getPrimaryId(), sqlRelated.getPrimaryId()) && + ObjectsCompat.equals(getPrimary(), sqlRelated.getPrimary()) && + ObjectsCompat.equals(getCreatedAt(), sqlRelated.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), sqlRelated.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getContent()) + .append(getPrimaryId()) + .append(getPrimary()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"SqlRelated {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") + .append(\\"primaryId=\\" + String.valueOf(getPrimaryId()) + \\", \\") + .append(\\"primary=\\" + String.valueOf(getPrimary()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static PrimaryIdStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static SqlRelated justId(String id) { + return new SqlRelated( + id, + null, + null, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + content, + primaryId, + primary); + } + public interface PrimaryIdStep { + BuildStep primaryId(Integer primaryId); + } + + + public interface BuildStep { + SqlRelated build(); + BuildStep id(String id); + BuildStep content(String content); + BuildStep primary(SqlPrimary primary); + } + + + public static class Builder implements PrimaryIdStep, BuildStep { + private Integer id; + private Integer primaryId; + private String content; + private SqlPrimary primary; + public Builder() { + + } + + private Builder(Integer id, String content, Integer primaryId, SqlPrimary primary) { + this.id = id; + this.content = content; + this.primaryId = primaryId; + this.primary = primary; + } + + @Override + public SqlRelated build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new SqlRelated( + id, + content, + primaryId, + primary); + } + + @Override + public BuildStep primaryId(Integer primaryId) { + Objects.requireNonNull(primaryId); + this.primaryId = primaryId; + return this; + } + + @Override + public BuildStep content(String content) { + this.content = content; + return this; + } + + @Override + public BuildStep primary(SqlPrimary primary) { + this.primary = primary; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(Integer id, String content, Integer primaryId, SqlPrimary primary) { + super(id, content, primaryId, primary); + Objects.requireNonNull(primaryId); + } + + @Override + public CopyOfBuilder primaryId(Integer primaryId) { + return (CopyOfBuilder) super.primaryId(primaryId); + } + + @Override + public CopyOfBuilder content(String content) { + return (CopyOfBuilder) super.content(content); + } + + @Override + public CopyOfBuilder primary(SqlPrimary primary) { + return (CopyOfBuilder) super.primary(primary); + } + } + + + public static class SqlRelatedIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public SqlRelatedIdentifier(Integer id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references sets the association to the references field for hasOne and hasMany 1`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.HasMany; +import com.amplifyframework.core.model.annotations.HasOne; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the Primary type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"Primaries\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"id\\"}) +public final class Primary implements Model { + public static final QueryField ID = field(\\"Primary\\", \\"id\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; + private final @ModelField(targetType=\\"RelatedMany\\") @HasMany(associatedWith = \\"primaryId\\", type = RelatedMany.class) List relatedMany = null; + private final @ModelField(targetType=\\"RelatedOne\\") @HasOne(associatedWith = \\"primaryId\\", type = RelatedOne.class) RelatedOne relatedOne = null; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public String resolveIdentifier() { + return id; + } + + public String getId() { + return id; + } + + public List getRelatedMany() { + return relatedMany; + } + + public RelatedOne getRelatedOne() { + return relatedOne; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private Primary(String id) { + this.id = id; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + Primary primary = (Primary) obj; + return ObjectsCompat.equals(getId(), primary.getId()) && + ObjectsCompat.equals(getCreatedAt(), primary.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), primary.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"Primary {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static BuildStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static Primary justId(String id) { + return new Primary( + id + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id); + } + public interface BuildStep { + Primary build(); + BuildStep id(String id); + } + + + public static class Builder implements BuildStep { + private String id; + public Builder() { + + } + + private Builder(String id) { + this.id = id; + } + + @Override + public Primary build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new Primary( + id); + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String id) { + super(id); + + } + } + + + public static class PrimaryIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public PrimaryIdentifier(String id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references sets the association to the references field for hasOne and hasMany 2`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.BelongsTo; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the RelatedMany type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"RelatedManies\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"id\\"}) +public final class RelatedMany implements Model { + public static final QueryField ID = field(\\"RelatedMany\\", \\"id\\"); + public static final QueryField PRIMARY_ID = field(\\"RelatedMany\\", \\"primaryId\\"); + public static final QueryField PRIMARY = field(\\"RelatedMany\\", \\"primaryId\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryId; + private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryId\\", targetNames = {\\"primaryId\\"}, type = Primary.class) Primary primary; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public String resolveIdentifier() { + return id; + } + + public String getId() { + return id; + } + + public String getPrimaryId() { + return primaryId; + } + + public Primary getPrimary() { + return primary; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private RelatedMany(String id, String primaryId, Primary primary) { + this.id = id; + this.primaryId = primaryId; + this.primary = primary; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + RelatedMany relatedMany = (RelatedMany) obj; + return ObjectsCompat.equals(getId(), relatedMany.getId()) && + ObjectsCompat.equals(getPrimaryId(), relatedMany.getPrimaryId()) && + ObjectsCompat.equals(getPrimary(), relatedMany.getPrimary()) && + ObjectsCompat.equals(getCreatedAt(), relatedMany.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), relatedMany.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getPrimaryId()) + .append(getPrimary()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"RelatedMany {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"primaryId=\\" + String.valueOf(getPrimaryId()) + \\", \\") + .append(\\"primary=\\" + String.valueOf(getPrimary()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static PrimaryIdStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static RelatedMany justId(String id) { + return new RelatedMany( + id, + null, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + primaryId, + primary); + } + public interface PrimaryIdStep { + BuildStep primaryId(String primaryId); + } + + + public interface BuildStep { + RelatedMany build(); + BuildStep id(String id); + BuildStep primary(Primary primary); + } + + + public static class Builder implements PrimaryIdStep, BuildStep { + private String id; + private String primaryId; + private Primary primary; + public Builder() { + + } + + private Builder(String id, String primaryId, Primary primary) { + this.id = id; + this.primaryId = primaryId; + this.primary = primary; + } + + @Override + public RelatedMany build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new RelatedMany( + id, + primaryId, + primary); + } + + @Override + public BuildStep primaryId(String primaryId) { + Objects.requireNonNull(primaryId); + this.primaryId = primaryId; + return this; + } + + @Override + public BuildStep primary(Primary primary) { + this.primary = primary; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String id, String primaryId, Primary primary) { + super(id, primaryId, primary); + Objects.requireNonNull(primaryId); + } + + @Override + public CopyOfBuilder primaryId(String primaryId) { + return (CopyOfBuilder) super.primaryId(primaryId); + } + + @Override + public CopyOfBuilder primary(Primary primary) { + return (CopyOfBuilder) super.primary(primary); + } + } + + + public static class RelatedManyIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public RelatedManyIdentifier(String id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references sets the association to the references field for hasOne and hasMany 3`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.BelongsTo; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the RelatedOne type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"RelatedOnes\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"id\\"}) +public final class RelatedOne implements Model { + public static final QueryField ID = field(\\"RelatedOne\\", \\"id\\"); + public static final QueryField PRIMARY_ID = field(\\"RelatedOne\\", \\"primaryId\\"); + public static final QueryField PRIMARY = field(\\"RelatedOne\\", \\"primaryId\\"); + private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; + private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryId; + private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryId\\", targetNames = {\\"primaryId\\"}, type = Primary.class) Primary primary; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public String resolveIdentifier() { + return id; + } + + public String getId() { + return id; + } + + public String getPrimaryId() { + return primaryId; + } + + public Primary getPrimary() { + return primary; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private RelatedOne(String id, String primaryId, Primary primary) { + this.id = id; + this.primaryId = primaryId; + this.primary = primary; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + RelatedOne relatedOne = (RelatedOne) obj; + return ObjectsCompat.equals(getId(), relatedOne.getId()) && + ObjectsCompat.equals(getPrimaryId(), relatedOne.getPrimaryId()) && + ObjectsCompat.equals(getPrimary(), relatedOne.getPrimary()) && + ObjectsCompat.equals(getCreatedAt(), relatedOne.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), relatedOne.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getPrimaryId()) + .append(getPrimary()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"RelatedOne {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"primaryId=\\" + String.valueOf(getPrimaryId()) + \\", \\") + .append(\\"primary=\\" + String.valueOf(getPrimary()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static PrimaryIdStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static RelatedOne justId(String id) { + return new RelatedOne( + id, + null, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + primaryId, + primary); + } + public interface PrimaryIdStep { + BuildStep primaryId(String primaryId); + } + + + public interface BuildStep { + RelatedOne build(); + BuildStep id(String id); + BuildStep primary(Primary primary); + } + + + public static class Builder implements PrimaryIdStep, BuildStep { + private String id; + private String primaryId; + private Primary primary; + public Builder() { + + } + + private Builder(String id, String primaryId, Primary primary) { + this.id = id; + this.primaryId = primaryId; + this.primary = primary; + } + + @Override + public RelatedOne build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new RelatedOne( + id, + primaryId, + primary); + } + + @Override + public BuildStep primaryId(String primaryId) { + Objects.requireNonNull(primaryId); + this.primaryId = primaryId; + return this; + } + + @Override + public BuildStep primary(Primary primary) { + this.primary = primary; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(String id, String primaryId, Primary primary) { + super(id, primaryId, primary); + Objects.requireNonNull(primaryId); + } + + @Override + public CopyOfBuilder primaryId(String primaryId) { + return (CopyOfBuilder) super.primaryId(primaryId); + } + + @Override + public CopyOfBuilder primary(Primary primary) { + return (CopyOfBuilder) super.primary(primary); + } + } + + + public static class RelatedOneIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public RelatedOneIdentifier(String id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references sets the association to the references field for hasOne/belongsTo 1`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.HasOne; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the SqlPrimary type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"SqlPrimaries\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"id\\"}) +public final class SqlPrimary implements Model { + public static final QueryField ID = field(\\"SqlPrimary\\", \\"id\\"); + public static final QueryField CONTENT = field(\\"SqlPrimary\\", \\"content\\"); + private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer id; + private final @ModelField(targetType=\\"String\\") String content; + private final @ModelField(targetType=\\"SqlRelated\\") @HasOne(associatedWith = \\"primaryId\\", type = SqlRelated.class) SqlRelated related = null; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public Integer resolveIdentifier() { + return id; + } + + public Integer getId() { + return id; + } + + public String getContent() { + return content; + } + + public SqlRelated getRelated() { + return related; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private SqlPrimary(Integer id, String content) { + this.id = id; + this.content = content; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + SqlPrimary sqlPrimary = (SqlPrimary) obj; + return ObjectsCompat.equals(getId(), sqlPrimary.getId()) && + ObjectsCompat.equals(getContent(), sqlPrimary.getContent()) && + ObjectsCompat.equals(getCreatedAt(), sqlPrimary.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), sqlPrimary.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getContent()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"SqlPrimary {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static BuildStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static SqlPrimary justId(String id) { + return new SqlPrimary( + id, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + content); + } + public interface BuildStep { + SqlPrimary build(); + BuildStep id(String id); + BuildStep content(String content); + } + + + public static class Builder implements BuildStep { + private Integer id; + private String content; + public Builder() { + + } + + private Builder(Integer id, String content) { + this.id = id; + this.content = content; + } + + @Override + public SqlPrimary build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new SqlPrimary( + id, + content); + } + + @Override + public BuildStep content(String content) { + this.content = content; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(Integer id, String content) { + super(id, content); + + } + + @Override + public CopyOfBuilder content(String content) { + return (CopyOfBuilder) super.content(content); + } + } + + + public static class SqlPrimaryIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public SqlPrimaryIdentifier(Integer id) { + super(id); + } + } + +} +" +`; + +exports[`AppSyncModelVisitor custom references sets the association to the references field for hasOne/belongsTo 2`] = ` +"package com.amplifyframework.datastore.generated.model; + +import com.amplifyframework.core.model.annotations.BelongsTo; +import com.amplifyframework.core.model.temporal.Temporal; +import com.amplifyframework.core.model.ModelIdentifier; + +import java.util.List; +import java.util.UUID; +import java.util.Objects; + +import androidx.core.util.ObjectsCompat; + +import com.amplifyframework.core.model.Model; +import com.amplifyframework.core.model.annotations.Index; +import com.amplifyframework.core.model.annotations.ModelConfig; +import com.amplifyframework.core.model.annotations.ModelField; +import com.amplifyframework.core.model.query.predicate.QueryField; + +import static com.amplifyframework.core.model.query.predicate.QueryField.field; + +/** This is an auto generated class representing the SqlRelated type in your schema. */ +@SuppressWarnings(\\"all\\") +@ModelConfig(pluralName = \\"SqlRelateds\\", type = Model.Type.USER, version = 1) +@Index(name = \\"undefined\\", fields = {\\"id\\"}) +@Index(name = \\"primary_id\\", fields = {\\"primaryId\\"}) +public final class SqlRelated implements Model { + public static final QueryField ID = field(\\"SqlRelated\\", \\"id\\"); + public static final QueryField CONTENT = field(\\"SqlRelated\\", \\"content\\"); + public static final QueryField PRIMARY_ID = field(\\"SqlRelated\\", \\"primaryId\\"); + public static final QueryField PRIMARY = field(\\"SqlRelated\\", \\"primaryId\\"); + private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer id; + private final @ModelField(targetType=\\"String\\") String content; + private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer primaryId; + private final @ModelField(targetType=\\"SqlPrimary\\") @BelongsTo(targetName = \\"primaryId\\", targetNames = {\\"primaryId\\"}, type = SqlPrimary.class) SqlPrimary primary; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; + private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + /** @deprecated This API is internal to Amplify and should not be used. */ + @Deprecated + public Integer resolveIdentifier() { + return id; + } + + public Integer getId() { + return id; + } + + public String getContent() { + return content; + } + + public Integer getPrimaryId() { + return primaryId; + } + + public SqlPrimary getPrimary() { + return primary; + } + + public Temporal.DateTime getCreatedAt() { + return createdAt; + } + + public Temporal.DateTime getUpdatedAt() { + return updatedAt; + } + + private SqlRelated(Integer id, String content, Integer primaryId, SqlPrimary primary) { + this.id = id; + this.content = content; + this.primaryId = primaryId; + this.primary = primary; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if(obj == null || getClass() != obj.getClass()) { + return false; + } else { + SqlRelated sqlRelated = (SqlRelated) obj; + return ObjectsCompat.equals(getId(), sqlRelated.getId()) && + ObjectsCompat.equals(getContent(), sqlRelated.getContent()) && + ObjectsCompat.equals(getPrimaryId(), sqlRelated.getPrimaryId()) && + ObjectsCompat.equals(getPrimary(), sqlRelated.getPrimary()) && + ObjectsCompat.equals(getCreatedAt(), sqlRelated.getCreatedAt()) && + ObjectsCompat.equals(getUpdatedAt(), sqlRelated.getUpdatedAt()); + } + } + + @Override + public int hashCode() { + return new StringBuilder() + .append(getId()) + .append(getContent()) + .append(getPrimaryId()) + .append(getPrimary()) + .append(getCreatedAt()) + .append(getUpdatedAt()) + .toString() + .hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append(\\"SqlRelated {\\") + .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") + .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") + .append(\\"primaryId=\\" + String.valueOf(getPrimaryId()) + \\", \\") + .append(\\"primary=\\" + String.valueOf(getPrimary()) + \\", \\") + .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"}\\") + .toString(); + } + + public static PrimaryIdStep builder() { + return new Builder(); + } + + /** + * WARNING: This method should not be used to build an instance of this object for a CREATE mutation. + * This is a convenience method to return an instance of the object with only its ID populated + * to be used in the context of a parameter in a delete mutation or referencing a foreign key + * in a relationship. + * @param id the id of the existing item this instance will represent + * @return an instance of this model with only ID populated + */ + public static SqlRelated justId(String id) { + return new SqlRelated( + id, + null, + null, + null + ); + } + + public CopyOfBuilder copyOfBuilder() { + return new CopyOfBuilder(id, + content, + primaryId, + primary); + } + public interface PrimaryIdStep { + BuildStep primaryId(Integer primaryId); + } + + + public interface BuildStep { + SqlRelated build(); + BuildStep id(String id); + BuildStep content(String content); + BuildStep primary(SqlPrimary primary); + } + + + public static class Builder implements PrimaryIdStep, BuildStep { + private Integer id; + private Integer primaryId; + private String content; + private SqlPrimary primary; + public Builder() { + + } + + private Builder(Integer id, String content, Integer primaryId, SqlPrimary primary) { + this.id = id; + this.content = content; + this.primaryId = primaryId; + this.primary = primary; + } + + @Override + public SqlRelated build() { + String id = this.id != null ? this.id : UUID.randomUUID().toString(); + + return new SqlRelated( + id, + content, + primaryId, + primary); + } + + @Override + public BuildStep primaryId(Integer primaryId) { + Objects.requireNonNull(primaryId); + this.primaryId = primaryId; + return this; + } + + @Override + public BuildStep content(String content) { + this.content = content; + return this; + } + + @Override + public BuildStep primary(SqlPrimary primary) { + this.primary = primary; + return this; + } + + /** + * @param id id + * @return Current Builder instance, for fluent method chaining + */ + public BuildStep id(String id) { + this.id = id; + return this; + } + } + + + public final class CopyOfBuilder extends Builder { + private CopyOfBuilder(Integer id, String content, Integer primaryId, SqlPrimary primary) { + super(id, content, primaryId, primary); + Objects.requireNonNull(primaryId); + } + + @Override + public CopyOfBuilder primaryId(Integer primaryId) { + return (CopyOfBuilder) super.primaryId(primaryId); + } + + @Override + public CopyOfBuilder content(String content) { + return (CopyOfBuilder) super.content(content); + } + + @Override + public CopyOfBuilder primary(SqlPrimary primary) { + return (CopyOfBuilder) super.primary(primary); + } + } + + + public static class SqlRelatedIdentifier extends ModelIdentifier { + private static final long serialVersionUID = 1L; + public SqlRelatedIdentifier(Integer id) { + super(id); + } + } + +} +" +`; + exports[`AppSyncModelVisitor should avoid name collision on builder step 1`] = ` "package com.amplifyframework.datastore.generated.model; diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap index ca3c210b7..9b7dc4dfb 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-model-introspection-visitor.test.ts.snap @@ -4023,6 +4023,195 @@ exports[`custom references hasMany with sortKeyFields on primary key 1`] = ` }" `; +exports[`custom references hasOne with sortKeyFields on primary key 1`] = ` +"{ + \\"version\\": 1, + \\"models\\": { + \\"Primary\\": { + \\"name\\": \\"Primary\\", + \\"fields\\": { + \\"tenantId\\": { + \\"name\\": \\"tenantId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"instanceId\\": { + \\"name\\": \\"instanceId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"recordId\\": { + \\"name\\": \\"recordId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"content\\": { + \\"name\\": \\"content\\", + \\"isArray\\": false, + \\"type\\": \\"String\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"related\\": { + \\"name\\": \\"related\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"Related\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"HAS_ONE\\", + \\"associatedWith\\": [ + \\"primaryTenantId\\", + \\"primaryInstanceId\\", + \\"primaryRecordId\\" + ], + \\"targetNames\\": [] + } + }, + \\"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\\": \\"Primaries\\", + \\"attributes\\": [ + { + \\"type\\": \\"model\\", + \\"properties\\": {} + }, + { + \\"type\\": \\"key\\", + \\"properties\\": { + \\"fields\\": [ + \\"tenantId\\", + \\"instanceId\\", + \\"recordId\\" + ] + } + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": true, + \\"primaryKeyFieldName\\": \\"tenantId\\", + \\"sortKeyFieldNames\\": [ + \\"instanceId\\", + \\"recordId\\" + ] + } + }, + \\"Related\\": { + \\"name\\": \\"Related\\", + \\"fields\\": { + \\"id\\": { + \\"name\\": \\"id\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"content\\": { + \\"name\\": \\"content\\", + \\"isArray\\": false, + \\"type\\": \\"String\\", + \\"isRequired\\": false, + \\"attributes\\": [] + }, + \\"primaryTenantId\\": { + \\"name\\": \\"primaryTenantId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primaryInstanceId\\": { + \\"name\\": \\"primaryInstanceId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primaryRecordId\\": { + \\"name\\": \\"primaryRecordId\\", + \\"isArray\\": false, + \\"type\\": \\"ID\\", + \\"isRequired\\": true, + \\"attributes\\": [] + }, + \\"primary\\": { + \\"name\\": \\"primary\\", + \\"isArray\\": false, + \\"type\\": { + \\"model\\": \\"Primary\\" + }, + \\"isRequired\\": false, + \\"attributes\\": [], + \\"association\\": { + \\"connectionType\\": \\"BELONGS_TO\\", + \\"targetNames\\": [ + \\"primaryTenantId\\", + \\"primaryInstanceId\\", + \\"primaryRecordId\\" + ] + } + }, + \\"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\\": \\"Relateds\\", + \\"attributes\\": [ + { + \\"type\\": \\"model\\", + \\"properties\\": {} + } + ], + \\"primaryKeyInfo\\": { + \\"isCustomPrimaryKey\\": false, + \\"primaryKeyFieldName\\": \\"id\\", + \\"sortKeyFieldNames\\": [] + } + } + }, + \\"enums\\": {}, + \\"nonModels\\": {} +}" +`; + exports[`custom references sets the association to the references field for hasMany/belongsTo 1`] = ` "{ \\"version\\": 1, diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-swift-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-swift-visitor.test.ts.snap index 0bc3e755e..dfc173c83 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-swift-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-swift-visitor.test.ts.snap @@ -1290,3 +1290,1761 @@ extension ModelPath where ModelType == task { } }" `; + +exports[`AppSyncSwiftVisitor custom references double linked references 1`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct Foo: Model { + public let id: String + internal var _bar1: LazyReference + public var bar1: Bar? { + get async throws { + try await _bar1.get() + } + } + internal var _bar2: LazyReference + public var bar2: Bar? { + get async throws { + try await _bar2.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: String = UUID().uuidString, + bar1: Bar? = nil, + bar2: Bar? = nil) { + self.init(id: id, + bar1: bar1, + bar2: bar2, + createdAt: nil, + updatedAt: nil) + } + internal init(id: String = UUID().uuidString, + bar1: Bar? = nil, + bar2: Bar? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self._bar1 = LazyReference(bar1) + self._bar2 = LazyReference(bar2) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setBar1(_ bar1: Bar? = nil) { + self._bar1 = LazyReference(bar1) + } + public mutating func setBar2(_ bar2: Bar? = nil) { + self._bar2 = LazyReference(bar2) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(String.self, forKey: .id) + _bar1 = try values.decodeIfPresent(LazyReference.self, forKey: .bar1) ?? LazyReference(identifiers: nil) + _bar2 = try values.decodeIfPresent(LazyReference.self, forKey: .bar2) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(_bar1, forKey: .bar1) + try container.encode(_bar2, forKey: .bar2) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references double linked references 2`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension Foo { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case bar1 + case bar2 + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let foo = Foo.keys + + model.listPluralName = \\"Foos\\" + model.syncPluralName = \\"Foos\\" + + model.attributes( + .primaryKey(fields: [foo.id]) + ) + + model.fields( + .field(foo.id, is: .required, ofType: .string), + .field(foo.bar1, is: .optional, ofType: .model(Bar.self)), + .field(foo.bar2, is: .optional, ofType: .model(Bar.self)), + .field(foo.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(foo.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension Foo: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == Foo { + public var id: FieldPath { + string(\\"id\\") + } + public var bar1: ModelPath { + Bar.Path(name: \\"bar1\\", parent: self) + } + public var bar2: ModelPath { + Bar.Path(name: \\"bar2\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references double linked references 3`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct Bar: Model { + public let id: String + public var bar1Id: String? + public var bar2Id: String? + internal var _foo1: LazyReference + public var foo1: Foo? { + get async throws { + try await _foo1.get() + } + } + internal var _foo2: LazyReference + public var foo2: Foo? { + get async throws { + try await _foo2.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: String = UUID().uuidString, + bar1Id: String? = nil, + bar2Id: String? = nil, + foo1: Foo? = nil, + foo2: Foo? = nil) { + self.init(id: id, + bar1Id: bar1Id, + bar2Id: bar2Id, + foo1: foo1, + foo2: foo2, + createdAt: nil, + updatedAt: nil) + } + internal init(id: String = UUID().uuidString, + bar1Id: String? = nil, + bar2Id: String? = nil, + foo1: Foo? = nil, + foo2: Foo? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.bar1Id = bar1Id + self.bar2Id = bar2Id + self._foo1 = LazyReference(foo1) + self._foo2 = LazyReference(foo2) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setFoo1(_ foo1: Foo? = nil) { + self._foo1 = LazyReference(foo1) + } + public mutating func setFoo2(_ foo2: Foo? = nil) { + self._foo2 = LazyReference(foo2) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(String.self, forKey: .id) + bar1Id = try? values.decode(String?.self, forKey: .bar1Id) + bar2Id = try? values.decode(String?.self, forKey: .bar2Id) + _foo1 = try values.decodeIfPresent(LazyReference.self, forKey: .foo1) ?? LazyReference(identifiers: nil) + _foo2 = try values.decodeIfPresent(LazyReference.self, forKey: .foo2) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(bar1Id, forKey: .bar1Id) + try container.encode(bar2Id, forKey: .bar2Id) + try container.encode(_foo1, forKey: .foo1) + try container.encode(_foo2, forKey: .foo2) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references double linked references 4`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension Bar { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case bar1Id + case bar2Id + case foo1 + case foo2 + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let bar = Bar.keys + + model.listPluralName = \\"Bars\\" + model.syncPluralName = \\"Bars\\" + + model.attributes( + .primaryKey(fields: [bar.id]) + ) + + model.fields( + .field(bar.id, is: .required, ofType: .string), + .field(bar.bar1Id, is: .optional, ofType: .string), + .field(bar.bar2Id, is: .optional, ofType: .string), + .belongsTo(bar.foo1, is: .optional, ofType: Foo.self, targetNames: [\\"bar1Id\\"]), + .belongsTo(bar.foo2, is: .optional, ofType: Foo.self, targetNames: [\\"bar2Id\\"]), + .field(bar.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(bar.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension Bar: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == Bar { + public var id: FieldPath { + string(\\"id\\") + } + public var bar1Id: FieldPath { + string(\\"bar1Id\\") + } + public var bar2Id: FieldPath { + string(\\"bar2Id\\") + } + public var foo1: ModelPath { + Foo.Path(name: \\"foo1\\", parent: self) + } + public var foo2: ModelPath { + Foo.Path(name: \\"foo2\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references hasMany with sortKeyFields on primary key 1`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct Primary: Model { + public let tenantId: String + public let instanceId: String + public let recordId: String + public var content: String? + public var related: List? + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(tenantId: String, + instanceId: String, + recordId: String, + content: String? = nil, + related: List = []) { + self.init(tenantId: tenantId, + instanceId: instanceId, + recordId: recordId, + content: content, + related: related, + createdAt: nil, + updatedAt: nil) + } + internal init(tenantId: String, + instanceId: String, + recordId: String, + content: String? = nil, + related: List = [], + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.tenantId = tenantId + self.instanceId = instanceId + self.recordId = recordId + self.content = content + self.related = related + self.createdAt = createdAt + self.updatedAt = updatedAt + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references hasMany with sortKeyFields on primary key 2`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension Primary { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case tenantId + case instanceId + case recordId + case content + case related + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let primary = Primary.keys + + model.listPluralName = \\"Primaries\\" + model.syncPluralName = \\"Primaries\\" + + model.attributes( + .index(fields: [\\"tenantId\\", \\"instanceId\\", \\"recordId\\"], name: nil), + .primaryKey(fields: [primary.tenantId, primary.instanceId, primary.recordId]) + ) + + model.fields( + .field(primary.tenantId, is: .required, ofType: .string), + .field(primary.instanceId, is: .required, ofType: .string), + .field(primary.recordId, is: .required, ofType: .string), + .field(primary.content, is: .optional, ofType: .string), + .hasMany(primary.related, is: .optional, ofType: Related.self, associatedWith: Related.keys.primaryTenantId), + .field(primary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(primary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension Primary: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Custom + public typealias IdentifierProtocol = ModelIdentifier +} + +extension Primary.IdentifierProtocol { + public static func identifier(tenantId: String, + instanceId: String, + recordId: String) -> Self { + .make(fields:[(name: \\"tenantId\\", value: tenantId), (name: \\"instanceId\\", value: instanceId), (name: \\"recordId\\", value: recordId)]) + } +} +extension ModelPath where ModelType == Primary { + public var tenantId: FieldPath { + string(\\"tenantId\\") + } + public var instanceId: FieldPath { + string(\\"instanceId\\") + } + public var recordId: FieldPath { + string(\\"recordId\\") + } + public var content: FieldPath { + string(\\"content\\") + } + public var related: ModelPath { + Related.Path(name: \\"related\\", isCollection: true, parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references hasMany with sortKeyFields on primary key 3`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct Related: Model { + public let id: String + public var content: String? + public var primaryTenantId: String + public var primaryInstanceId: String + public var primaryRecordId: String + internal var _primary: LazyReference + public var primary: Primary? { + get async throws { + try await _primary.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: String = UUID().uuidString, + content: String? = nil, + primaryTenantId: String, + primaryInstanceId: String, + primaryRecordId: String, + primary: Primary? = nil) { + self.init(id: id, + content: content, + primaryTenantId: primaryTenantId, + primaryInstanceId: primaryInstanceId, + primaryRecordId: primaryRecordId, + primary: primary, + createdAt: nil, + updatedAt: nil) + } + internal init(id: String = UUID().uuidString, + content: String? = nil, + primaryTenantId: String, + primaryInstanceId: String, + primaryRecordId: String, + primary: Primary? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.content = content + self.primaryTenantId = primaryTenantId + self.primaryInstanceId = primaryInstanceId + self.primaryRecordId = primaryRecordId + self._primary = LazyReference(primary) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setPrimary(_ primary: Primary? = nil) { + self._primary = LazyReference(primary) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(String.self, forKey: .id) + content = try? values.decode(String?.self, forKey: .content) + primaryTenantId = try values.decode(String.self, forKey: .primaryTenantId) + primaryInstanceId = try values.decode(String.self, forKey: .primaryInstanceId) + primaryRecordId = try values.decode(String.self, forKey: .primaryRecordId) + _primary = try values.decodeIfPresent(LazyReference.self, forKey: .primary) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(content, forKey: .content) + try container.encode(primaryTenantId, forKey: .primaryTenantId) + try container.encode(primaryInstanceId, forKey: .primaryInstanceId) + try container.encode(primaryRecordId, forKey: .primaryRecordId) + try container.encode(_primary, forKey: .primary) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references hasMany with sortKeyFields on primary key 4`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension Related { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case content + case primaryTenantId + case primaryInstanceId + case primaryRecordId + case primary + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let related = Related.keys + + model.listPluralName = \\"Relateds\\" + model.syncPluralName = \\"Relateds\\" + + model.attributes( + .primaryKey(fields: [related.id]) + ) + + model.fields( + .field(related.id, is: .required, ofType: .string), + .field(related.content, is: .optional, ofType: .string), + .field(related.primaryTenantId, is: .required, ofType: .string), + .field(related.primaryInstanceId, is: .required, ofType: .string), + .field(related.primaryRecordId, is: .required, ofType: .string), + .belongsTo(related.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryTenantId\\", \\"primaryInstanceId\\", \\"primaryRecordId\\"]), + .field(related.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(related.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension Related: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == Related { + public var id: FieldPath { + string(\\"id\\") + } + public var content: FieldPath { + string(\\"content\\") + } + public var primaryTenantId: FieldPath { + string(\\"primaryTenantId\\") + } + public var primaryInstanceId: FieldPath { + string(\\"primaryInstanceId\\") + } + public var primaryRecordId: FieldPath { + string(\\"primaryRecordId\\") + } + public var primary: ModelPath { + Primary.Path(name: \\"primary\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references hasOne with sortKeyFields on primary key 1`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct Primary: Model { + public let tenantId: String + public let instanceId: String + public let recordId: String + public var content: String? + internal var _related: LazyReference + public var related: Related? { + get async throws { + try await _related.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(tenantId: String, + instanceId: String, + recordId: String, + content: String? = nil, + related: Related? = nil) { + self.init(tenantId: tenantId, + instanceId: instanceId, + recordId: recordId, + content: content, + related: related, + createdAt: nil, + updatedAt: nil) + } + internal init(tenantId: String, + instanceId: String, + recordId: String, + content: String? = nil, + related: Related? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.tenantId = tenantId + self.instanceId = instanceId + self.recordId = recordId + self.content = content + self._related = LazyReference(related) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setRelated(_ related: Related? = nil) { + self._related = LazyReference(related) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + tenantId = try values.decode(String.self, forKey: .tenantId) + instanceId = try values.decode(String.self, forKey: .instanceId) + recordId = try values.decode(String.self, forKey: .recordId) + content = try? values.decode(String?.self, forKey: .content) + _related = try values.decodeIfPresent(LazyReference.self, forKey: .related) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(tenantId, forKey: .tenantId) + try container.encode(instanceId, forKey: .instanceId) + try container.encode(recordId, forKey: .recordId) + try container.encode(content, forKey: .content) + try container.encode(_related, forKey: .related) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references hasOne with sortKeyFields on primary key 2`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension Primary { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case tenantId + case instanceId + case recordId + case content + case related + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let primary = Primary.keys + + model.listPluralName = \\"Primaries\\" + model.syncPluralName = \\"Primaries\\" + + model.attributes( + .index(fields: [\\"tenantId\\", \\"instanceId\\", \\"recordId\\"], name: nil), + .primaryKey(fields: [primary.tenantId, primary.instanceId, primary.recordId]) + ) + + model.fields( + .field(primary.tenantId, is: .required, ofType: .string), + .field(primary.instanceId, is: .required, ofType: .string), + .field(primary.recordId, is: .required, ofType: .string), + .field(primary.content, is: .optional, ofType: .string), + .field(primary.related, is: .optional, ofType: .model(Related.self)), + .field(primary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(primary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension Primary: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Custom + public typealias IdentifierProtocol = ModelIdentifier +} + +extension Primary.IdentifierProtocol { + public static func identifier(tenantId: String, + instanceId: String, + recordId: String) -> Self { + .make(fields:[(name: \\"tenantId\\", value: tenantId), (name: \\"instanceId\\", value: instanceId), (name: \\"recordId\\", value: recordId)]) + } +} +extension ModelPath where ModelType == Primary { + public var tenantId: FieldPath { + string(\\"tenantId\\") + } + public var instanceId: FieldPath { + string(\\"instanceId\\") + } + public var recordId: FieldPath { + string(\\"recordId\\") + } + public var content: FieldPath { + string(\\"content\\") + } + public var related: ModelPath { + Related.Path(name: \\"related\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references hasOne with sortKeyFields on primary key 3`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct Related: Model { + public let id: String + public var content: String? + public var primaryTenantId: String + public var primaryInstanceId: String + public var primaryRecordId: String + internal var _primary: LazyReference + public var primary: Primary? { + get async throws { + try await _primary.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: String = UUID().uuidString, + content: String? = nil, + primaryTenantId: String, + primaryInstanceId: String, + primaryRecordId: String, + primary: Primary? = nil) { + self.init(id: id, + content: content, + primaryTenantId: primaryTenantId, + primaryInstanceId: primaryInstanceId, + primaryRecordId: primaryRecordId, + primary: primary, + createdAt: nil, + updatedAt: nil) + } + internal init(id: String = UUID().uuidString, + content: String? = nil, + primaryTenantId: String, + primaryInstanceId: String, + primaryRecordId: String, + primary: Primary? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.content = content + self.primaryTenantId = primaryTenantId + self.primaryInstanceId = primaryInstanceId + self.primaryRecordId = primaryRecordId + self._primary = LazyReference(primary) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setPrimary(_ primary: Primary? = nil) { + self._primary = LazyReference(primary) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(String.self, forKey: .id) + content = try? values.decode(String?.self, forKey: .content) + primaryTenantId = try values.decode(String.self, forKey: .primaryTenantId) + primaryInstanceId = try values.decode(String.self, forKey: .primaryInstanceId) + primaryRecordId = try values.decode(String.self, forKey: .primaryRecordId) + _primary = try values.decodeIfPresent(LazyReference.self, forKey: .primary) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(content, forKey: .content) + try container.encode(primaryTenantId, forKey: .primaryTenantId) + try container.encode(primaryInstanceId, forKey: .primaryInstanceId) + try container.encode(primaryRecordId, forKey: .primaryRecordId) + try container.encode(_primary, forKey: .primary) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references hasOne with sortKeyFields on primary key 4`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension Related { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case content + case primaryTenantId + case primaryInstanceId + case primaryRecordId + case primary + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let related = Related.keys + + model.listPluralName = \\"Relateds\\" + model.syncPluralName = \\"Relateds\\" + + model.attributes( + .primaryKey(fields: [related.id]) + ) + + model.fields( + .field(related.id, is: .required, ofType: .string), + .field(related.content, is: .optional, ofType: .string), + .field(related.primaryTenantId, is: .required, ofType: .string), + .field(related.primaryInstanceId, is: .required, ofType: .string), + .field(related.primaryRecordId, is: .required, ofType: .string), + .belongsTo(related.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryTenantId\\", \\"primaryInstanceId\\", \\"primaryRecordId\\"]), + .field(related.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(related.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension Related: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == Related { + public var id: FieldPath { + string(\\"id\\") + } + public var content: FieldPath { + string(\\"content\\") + } + public var primaryTenantId: FieldPath { + string(\\"primaryTenantId\\") + } + public var primaryInstanceId: FieldPath { + string(\\"primaryInstanceId\\") + } + public var primaryRecordId: FieldPath { + string(\\"primaryRecordId\\") + } + public var primary: ModelPath { + Primary.Path(name: \\"primary\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasMany/belongsTo 1`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct SqlPrimary: Model { + public let id: Int + public var content: String? + public var related: List? + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: Int = UUID().uuidString, + content: String? = nil, + related: List = []) { + self.init(id: id, + content: content, + related: related, + createdAt: nil, + updatedAt: nil) + } + internal init(id: Int = UUID().uuidString, + content: String? = nil, + related: List = [], + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.content = content + self.related = related + self.createdAt = createdAt + self.updatedAt = updatedAt + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasMany/belongsTo 2`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension SqlPrimary { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case content + case related + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let sqlPrimary = SqlPrimary.keys + + model.listPluralName = \\"SqlPrimaries\\" + model.syncPluralName = \\"SqlPrimaries\\" + + model.attributes( + .index(fields: [\\"id\\"], name: nil), + .primaryKey(fields: [sqlPrimary.id]) + ) + + model.fields( + .field(sqlPrimary.id, is: .required, ofType: .int), + .field(sqlPrimary.content, is: .optional, ofType: .string), + .hasMany(sqlPrimary.related, is: .optional, ofType: SqlRelated.self, associatedWith: SqlRelated.keys.primaryId), + .field(sqlPrimary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(sqlPrimary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension SqlPrimary: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == SqlPrimary { + public var id: FieldPath { + int(\\"id\\") + } + public var content: FieldPath { + string(\\"content\\") + } + public var related: ModelPath { + SqlRelated.Path(name: \\"related\\", isCollection: true, parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasMany/belongsTo 3`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct SqlRelated: Model { + public let id: Int + public var content: String? + public var primaryId: Int + internal var _primary: LazyReference + public var primary: SqlPrimary? { + get async throws { + try await _primary.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: Int = UUID().uuidString, + content: String? = nil, + primaryId: Int, + primary: SqlPrimary? = nil) { + self.init(id: id, + content: content, + primaryId: primaryId, + primary: primary, + createdAt: nil, + updatedAt: nil) + } + internal init(id: Int = UUID().uuidString, + content: String? = nil, + primaryId: Int, + primary: SqlPrimary? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.content = content + self.primaryId = primaryId + self._primary = LazyReference(primary) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setPrimary(_ primary: SqlPrimary? = nil) { + self._primary = LazyReference(primary) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(Int.self, forKey: .id) + content = try? values.decode(String?.self, forKey: .content) + primaryId = try values.decode(Int.self, forKey: .primaryId) + _primary = try values.decodeIfPresent(LazyReference.self, forKey: .primary) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(content, forKey: .content) + try container.encode(primaryId, forKey: .primaryId) + try container.encode(_primary, forKey: .primary) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasMany/belongsTo 4`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension SqlRelated { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case content + case primaryId + case primary + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let sqlRelated = SqlRelated.keys + + model.listPluralName = \\"SqlRelateds\\" + model.syncPluralName = \\"SqlRelateds\\" + + model.attributes( + .index(fields: [\\"id\\"], name: nil), + .index(fields: [\\"primaryId\\"], name: \\"primary_id\\"), + .primaryKey(fields: [sqlRelated.id]) + ) + + model.fields( + .field(sqlRelated.id, is: .required, ofType: .int), + .field(sqlRelated.content, is: .optional, ofType: .string), + .field(sqlRelated.primaryId, is: .required, ofType: .int), + .belongsTo(sqlRelated.primary, is: .optional, ofType: SqlPrimary.self, targetNames: [\\"primaryId\\"]), + .field(sqlRelated.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(sqlRelated.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension SqlRelated: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == SqlRelated { + public var id: FieldPath { + int(\\"id\\") + } + public var content: FieldPath { + string(\\"content\\") + } + public var primaryId: FieldPath { + int(\\"primaryId\\") + } + public var primary: ModelPath { + SqlPrimary.Path(name: \\"primary\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne and hasMany 1`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct Primary: Model { + public let id: String + public var relatedMany: List? + internal var _relatedOne: LazyReference + public var relatedOne: RelatedOne? { + get async throws { + try await _relatedOne.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: String = UUID().uuidString, + relatedMany: List? = [], + relatedOne: RelatedOne? = nil) { + self.init(id: id, + relatedMany: relatedMany, + relatedOne: relatedOne, + createdAt: nil, + updatedAt: nil) + } + internal init(id: String = UUID().uuidString, + relatedMany: List? = [], + relatedOne: RelatedOne? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.relatedMany = relatedMany + self._relatedOne = LazyReference(relatedOne) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setRelatedOne(_ relatedOne: RelatedOne? = nil) { + self._relatedOne = LazyReference(relatedOne) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(String.self, forKey: .id) + relatedMany = try values.decodeIfPresent(List?.self, forKey: .relatedMany) ?? .init() + _relatedOne = try values.decodeIfPresent(LazyReference.self, forKey: .relatedOne) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(relatedMany, forKey: .relatedMany) + try container.encode(_relatedOne, forKey: .relatedOne) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne and hasMany 2`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension Primary { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case relatedMany + case relatedOne + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let primary = Primary.keys + + model.listPluralName = \\"Primaries\\" + model.syncPluralName = \\"Primaries\\" + + model.attributes( + .index(fields: [\\"id\\"], name: nil), + .primaryKey(fields: [primary.id]) + ) + + model.fields( + .field(primary.id, is: .required, ofType: .string), + .hasMany(primary.relatedMany, is: .optional, ofType: RelatedMany.self, associatedWith: RelatedMany.keys.primaryId), + .field(primary.relatedOne, is: .optional, ofType: .model(RelatedOne.self)), + .field(primary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(primary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension Primary: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == Primary { + public var id: FieldPath { + string(\\"id\\") + } + public var relatedMany: ModelPath { + RelatedMany.Path(name: \\"relatedMany\\", isCollection: true, parent: self) + } + public var relatedOne: ModelPath { + RelatedOne.Path(name: \\"relatedOne\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne and hasMany 3`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct RelatedMany: Model { + public let id: String + public var primaryId: String + internal var _primary: LazyReference + public var primary: Primary? { + get async throws { + try await _primary.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: String = UUID().uuidString, + primaryId: String, + primary: Primary? = nil) { + self.init(id: id, + primaryId: primaryId, + primary: primary, + createdAt: nil, + updatedAt: nil) + } + internal init(id: String = UUID().uuidString, + primaryId: String, + primary: Primary? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.primaryId = primaryId + self._primary = LazyReference(primary) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setPrimary(_ primary: Primary? = nil) { + self._primary = LazyReference(primary) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(String.self, forKey: .id) + primaryId = try values.decode(String.self, forKey: .primaryId) + _primary = try values.decodeIfPresent(LazyReference.self, forKey: .primary) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(primaryId, forKey: .primaryId) + try container.encode(_primary, forKey: .primary) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne and hasMany 4`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension RelatedMany { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case primaryId + case primary + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let relatedMany = RelatedMany.keys + + model.listPluralName = \\"RelatedManies\\" + model.syncPluralName = \\"RelatedManies\\" + + model.attributes( + .index(fields: [\\"id\\"], name: nil), + .primaryKey(fields: [relatedMany.id]) + ) + + model.fields( + .field(relatedMany.id, is: .required, ofType: .string), + .field(relatedMany.primaryId, is: .required, ofType: .string), + .belongsTo(relatedMany.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryId\\"]), + .field(relatedMany.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(relatedMany.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension RelatedMany: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == RelatedMany { + public var id: FieldPath { + string(\\"id\\") + } + public var primaryId: FieldPath { + string(\\"primaryId\\") + } + public var primary: ModelPath { + Primary.Path(name: \\"primary\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne and hasMany 5`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct RelatedOne: Model { + public let id: String + public var primaryId: String + internal var _primary: LazyReference + public var primary: Primary? { + get async throws { + try await _primary.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: String = UUID().uuidString, + primaryId: String, + primary: Primary? = nil) { + self.init(id: id, + primaryId: primaryId, + primary: primary, + createdAt: nil, + updatedAt: nil) + } + internal init(id: String = UUID().uuidString, + primaryId: String, + primary: Primary? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.primaryId = primaryId + self._primary = LazyReference(primary) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setPrimary(_ primary: Primary? = nil) { + self._primary = LazyReference(primary) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(String.self, forKey: .id) + primaryId = try values.decode(String.self, forKey: .primaryId) + _primary = try values.decodeIfPresent(LazyReference.self, forKey: .primary) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(primaryId, forKey: .primaryId) + try container.encode(_primary, forKey: .primary) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne and hasMany 6`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension RelatedOne { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case primaryId + case primary + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let relatedOne = RelatedOne.keys + + model.listPluralName = \\"RelatedOnes\\" + model.syncPluralName = \\"RelatedOnes\\" + + model.attributes( + .index(fields: [\\"id\\"], name: nil), + .primaryKey(fields: [relatedOne.id]) + ) + + model.fields( + .field(relatedOne.id, is: .required, ofType: .string), + .field(relatedOne.primaryId, is: .required, ofType: .string), + .belongsTo(relatedOne.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryId\\"]), + .field(relatedOne.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(relatedOne.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension RelatedOne: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == RelatedOne { + public var id: FieldPath { + string(\\"id\\") + } + public var primaryId: FieldPath { + string(\\"primaryId\\") + } + public var primary: ModelPath { + Primary.Path(name: \\"primary\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne/belongsTo 1`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct SqlPrimary: Model { + public let id: Int + public var content: String? + internal var _related: LazyReference + public var related: SqlRelated? { + get async throws { + try await _related.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: Int = UUID().uuidString, + content: String? = nil, + related: SqlRelated? = nil) { + self.init(id: id, + content: content, + related: related, + createdAt: nil, + updatedAt: nil) + } + internal init(id: Int = UUID().uuidString, + content: String? = nil, + related: SqlRelated? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.content = content + self._related = LazyReference(related) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setRelated(_ related: SqlRelated? = nil) { + self._related = LazyReference(related) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(Int.self, forKey: .id) + content = try? values.decode(String?.self, forKey: .content) + _related = try values.decodeIfPresent(LazyReference.self, forKey: .related) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(content, forKey: .content) + try container.encode(_related, forKey: .related) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne/belongsTo 2`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension SqlPrimary { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case content + case related + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let sqlPrimary = SqlPrimary.keys + + model.listPluralName = \\"SqlPrimaries\\" + model.syncPluralName = \\"SqlPrimaries\\" + + model.attributes( + .index(fields: [\\"id\\"], name: nil), + .primaryKey(fields: [sqlPrimary.id]) + ) + + model.fields( + .field(sqlPrimary.id, is: .required, ofType: .int), + .field(sqlPrimary.content, is: .optional, ofType: .string), + .field(sqlPrimary.related, is: .optional, ofType: .model(SqlRelated.self)), + .field(sqlPrimary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(sqlPrimary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension SqlPrimary: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == SqlPrimary { + public var id: FieldPath { + int(\\"id\\") + } + public var content: FieldPath { + string(\\"content\\") + } + public var related: ModelPath { + SqlRelated.Path(name: \\"related\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne/belongsTo 3`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +public struct SqlRelated: Model { + public let id: Int + public var content: String? + public var primaryId: Int + internal var _primary: LazyReference + public var primary: SqlPrimary? { + get async throws { + try await _primary.get() + } + } + public var createdAt: Temporal.DateTime? + public var updatedAt: Temporal.DateTime? + + public init(id: Int = UUID().uuidString, + content: String? = nil, + primaryId: Int, + primary: SqlPrimary? = nil) { + self.init(id: id, + content: content, + primaryId: primaryId, + primary: primary, + createdAt: nil, + updatedAt: nil) + } + internal init(id: Int = UUID().uuidString, + content: String? = nil, + primaryId: Int, + primary: SqlPrimary? = nil, + createdAt: Temporal.DateTime? = nil, + updatedAt: Temporal.DateTime? = nil) { + self.id = id + self.content = content + self.primaryId = primaryId + self._primary = LazyReference(primary) + self.createdAt = createdAt + self.updatedAt = updatedAt + } + public mutating func setPrimary(_ primary: SqlPrimary? = nil) { + self._primary = LazyReference(primary) + } + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + id = try values.decode(Int.self, forKey: .id) + content = try? values.decode(String?.self, forKey: .content) + primaryId = try values.decode(Int.self, forKey: .primaryId) + _primary = try values.decodeIfPresent(LazyReference.self, forKey: .primary) ?? LazyReference(identifiers: nil) + createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) + updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(content, forKey: .content) + try container.encode(primaryId, forKey: .primaryId) + try container.encode(_primary, forKey: .primary) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(updatedAt, forKey: .updatedAt) + } +}" +`; + +exports[`AppSyncSwiftVisitor custom references sets the association to the references field for hasOne/belongsTo 4`] = ` +"// swiftlint:disable all +import Amplify +import Foundation + +extension SqlRelated { + // MARK: - CodingKeys + public enum CodingKeys: String, ModelKey { + case id + case content + case primaryId + case primary + case createdAt + case updatedAt + } + + public static let keys = CodingKeys.self + // MARK: - ModelSchema + + public static let schema = defineSchema { model in + let sqlRelated = SqlRelated.keys + + model.listPluralName = \\"SqlRelateds\\" + model.syncPluralName = \\"SqlRelateds\\" + + model.attributes( + .index(fields: [\\"id\\"], name: nil), + .index(fields: [\\"primaryId\\"], name: \\"primary_id\\"), + .primaryKey(fields: [sqlRelated.id]) + ) + + model.fields( + .field(sqlRelated.id, is: .required, ofType: .int), + .field(sqlRelated.content, is: .optional, ofType: .string), + .field(sqlRelated.primaryId, is: .required, ofType: .int), + .belongsTo(sqlRelated.primary, is: .optional, ofType: SqlPrimary.self, targetNames: [\\"primaryId\\"]), + .field(sqlRelated.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(sqlRelated.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + ) + } + public class Path: ModelPath { } + + public static var rootPath: PropertyContainerPath? { Path() } +} + +extension SqlRelated: ModelIdentifiable { + public typealias IdentifierFormat = ModelIdentifierFormat.Default + public typealias IdentifierProtocol = DefaultModelIdentifier +} +extension ModelPath where ModelType == SqlRelated { + public var id: FieldPath { + int(\\"id\\") + } + public var content: FieldPath { + string(\\"content\\") + } + public var primaryId: FieldPath { + int(\\"primaryId\\") + } + public var primary: ModelPath { + SqlPrimary.Path(name: \\"primary\\", parent: self) + } + public var createdAt: FieldPath { + datetime(\\"createdAt\\") + } + public var updatedAt: FieldPath { + datetime(\\"updatedAt\\") + } +}" +`; diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-dart-visitor.test.ts b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-dart-visitor.test.ts index b51eefd58..2f697e489 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-dart-visitor.test.ts +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-dart-visitor.test.ts @@ -796,4 +796,184 @@ describe('AppSync Dart Visitor', () => { }) }) }); + + describe('custom references', () => { + test('sets the association to the references field for hasMany/belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: [SqlRelated!] @hasMany(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + + ['SqlPrimary', 'SqlRelated'].forEach(modelName => { + const generatedCode = getVisitor({ + schema, + selectedType: modelName, + isTimestampFieldsAdded: true, + respectPrimaryKeyAttributesOnConnectionField: true, + transformerVersion: 2, + }).generate(); + expect(generatedCode).toMatchSnapshot(); + }); + }); + + test('sets the association to the references field for hasOne/belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: SqlRelated @hasOne(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + + ['SqlPrimary', 'SqlRelated'].forEach(modelName => { + const generatedCode = getVisitor({ + schema, + selectedType: modelName, + isTimestampFieldsAdded: true, + respectPrimaryKeyAttributesOnConnectionField: true, + transformerVersion: 2, + }).generate(); + expect(generatedCode).toMatchSnapshot(); + }); + }); + + test('sets the association to the references field for hasOne and hasMany', () => { + const schema = /* GraphQL */ ` + type Primary @model { + id: ID! @primaryKey + relatedMany: [RelatedMany] @hasMany(references: ["primaryId"]) + relatedOne: RelatedOne @hasOne(references: ["primaryId"]) + } + + type RelatedMany @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: ["primaryId"]) + } + + type RelatedOne @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: ["primaryId"]) + } + `; + ['Primary', 'RelatedOne', 'RelatedMany'].forEach(modelName => { + const generatedCode = getVisitor({ + schema, + selectedType: modelName, + isTimestampFieldsAdded: true, + respectPrimaryKeyAttributesOnConnectionField: true, + transformerVersion: 2, + }).generate(); + expect(generatedCode).toMatchSnapshot(); + }); + }); + + test('double linked references', () => { + const schema = /* GraphQL */ ` + type Foo @model { + id: ID! + bar1: Bar @hasOne(references: ["bar1Id"]) + bar2: Bar @hasOne(references: ["bar2Id"]) + } + + type Bar @model { + id: ID! + bar1Id: ID + bar2Id: ID + foo1: Foo @belongsTo(references: ["bar1Id"]) + foo2: Foo @belongsTo(references: ["bar2Id"]) + } + `; + + ['Foo', 'Bar'].forEach(modelName => { + const generatedCode = getVisitor({ + schema, + selectedType: modelName, + isTimestampFieldsAdded: true, + respectPrimaryKeyAttributesOnConnectionField: true, + transformerVersion: 2, + }).generate(); + expect(generatedCode).toMatchSnapshot(); + }); + }); + + test('hasMany with sortKeyFields on primary key', () => { + const schema = /* GraphQL */ ` + type Primary @model { + tenantId: ID! @primaryKey(sortKeyFields: ["instanceId", "recordId"]) + instanceId: ID! + recordId: ID! + content: String + related: [Related!] @hasMany(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + + type Related @model { + content: String + primaryTenantId: ID! + primaryInstanceId: ID! + primaryRecordId: ID! + primary: Primary @belongsTo(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + `; + + ['Primary', 'Related'].forEach(modelName => { + const generatedCode = getVisitor({ + schema, + selectedType: modelName, + isTimestampFieldsAdded: true, + respectPrimaryKeyAttributesOnConnectionField: true, + transformerVersion: 2, + }).generate(); + expect(generatedCode).toMatchSnapshot(); + }); + }); + + test('hasOne with sortKeyFields on primary key', () => { + const schema = /* GraphQL */ ` + type Primary @model { + tenantId: ID! @primaryKey(sortKeyFields: ["instanceId", "recordId"]) + instanceId: ID! + recordId: ID! + content: String + related: Related @hasOne(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + + type Related @model { + content: String + primaryTenantId: ID! + primaryInstanceId: ID! + primaryRecordId: ID! + primary: Primary @belongsTo(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + `; + ['Primary', 'Related'].forEach(modelName => { + const generatedCode = getVisitor({ + schema, + selectedType: modelName, + isTimestampFieldsAdded: true, + respectPrimaryKeyAttributesOnConnectionField: true, + transformerVersion: 2, + }).generate(); + expect(generatedCode).toMatchSnapshot(); + }); + }); + }); }); diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-java-visitor.test.ts b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-java-visitor.test.ts index 39a9b839b..9946c53f5 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-java-visitor.test.ts +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-java-visitor.test.ts @@ -781,4 +781,160 @@ describe('AppSyncModelVisitor', () => { expect(generatedCodeIntModel).toMatchSnapshot(); }); }); + + describe('custom references', () => { + test('sets the association to the references field for hasMany/belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: [SqlRelated!] @hasMany(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'SqlPrimary', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'SqlRelated', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('sets the association to the references field for hasOne/belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: SqlRelated @hasOne(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'SqlPrimary', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'SqlRelated', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('sets the association to the references field for hasOne and hasMany', () => { + const schema = /* GraphQL */ ` + type Primary @model { + id: ID! @primaryKey + relatedMany: [RelatedMany] @hasMany(references: ["primaryId"]) + relatedOne: RelatedOne @hasOne(references: ["primaryId"]) + } + + type RelatedMany @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: ["primaryId"]) + } + + type RelatedOne @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: ["primaryId"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'Primary', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'RelatedMany', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'RelatedOne', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('double linked references', () => { + const schema = /* GraphQL */ ` + type Foo @model { + id: ID! + bar1: Bar @hasOne(references: ["bar1Id"]) + bar2: Bar @hasOne(references: ["bar2Id"]) + } + + type Bar @model { + id: ID! + bar1Id: ID + bar2Id: ID + foo1: Foo @belongsTo(references: ["bar1Id"]) + foo2: Foo @belongsTo(references: ["bar2Id"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'Foo', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Bar', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('hasMany with sortKeyFields on primary key', () => { + const schema = /* GraphQL */ ` + type Primary @model { + tenantId: ID! @primaryKey(sortKeyFields: ["instanceId", "recordId"]) + instanceId: ID! + recordId: ID! + content: String + related: [Related!] @hasMany(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + + type Related @model { + content: String + primaryTenantId: ID! + primaryInstanceId: ID! + primaryRecordId: ID! + primary: Primary @belongsTo(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + `; + + expect(getVisitorPipelinedTransformer(schema, 'Primary', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Related', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('hasOne with sortKeyFields on primary key', () => { + const schema = /* GraphQL */ ` + type Primary @model { + tenantId: ID! @primaryKey(sortKeyFields: ["instanceId", "recordId"]) + instanceId: ID! + recordId: ID! + content: String + related: Related @hasOne(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + + type Related @model { + content: String + primaryTenantId: ID! + primaryInstanceId: ID! + primaryRecordId: ID! + primary: Primary @belongsTo(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'Primary', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Related', { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + }); }); diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-model-introspection-visitor.test.ts b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-model-introspection-visitor.test.ts index 329276ecf..179f33afb 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-model-introspection-visitor.test.ts +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-model-introspection-visitor.test.ts @@ -615,6 +615,28 @@ describe('custom references', () => { expect(visitor.generate()).toMatchSnapshot(); }); + test('hasOne with sortKeyFields on primary key', () => { + const schema = /* GraphQL */ ` + type Primary @model { + tenantId: ID! @primaryKey(sortKeyFields: ["instanceId", "recordId"]) + instanceId: ID! + recordId: ID! + content: String + related: Related @hasOne(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + + type Related @model { + content: String + primaryTenantId: ID! + primaryInstanceId: ID! + primaryRecordId: ID! + primary: Primary @belongsTo(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + `; + const visitor: AppSyncModelIntrospectionVisitor = getVisitor(schema); + expect(visitor.generate()).toMatchSnapshot(); + }); + test('throws error when using fields and references on hasMany', () => { const schema = /* GraphQL */ ` type SqlPrimary @refersTo(name: "sql_primary") @model { diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-swift-visitor.test.ts b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-swift-visitor.test.ts index a59eccfbf..2ee5581ff 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-swift-visitor.test.ts +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-swift-visitor.test.ts @@ -2976,4 +2976,200 @@ describe('AppSyncSwiftVisitor', () => { expect(generatedMetaComment).toMatchSnapshot(); }); }); + + describe('custom references', () => { + test('sets the association to the references field for hasMany/belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: [SqlRelated!] @hasMany(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'SqlPrimary', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'SqlPrimary', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'SqlRelated', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'SqlRelated', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('sets the association to the references field for hasOne/belongsTo', () => { + const schema = /* GraphQL */ ` + type SqlPrimary @refersTo(name: "sql_primary") @model { + id: Int! @primaryKey + content: String + related: SqlRelated @hasOne(references: ["primaryId"]) + } + + type SqlRelated @refersTo(name: "sql_related") @model { + id: Int! @primaryKey + content: String + primaryId: Int! @refersTo(name: "primary_id") @index(name: "primary_id") + primary: SqlPrimary @belongsTo(references: ["primaryId"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'SqlPrimary', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'SqlPrimary', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'SqlRelated', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'SqlRelated', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('sets the association to the references field for hasOne and hasMany', () => { + const schema = /* GraphQL */ ` + type Primary @model { + id: ID! @primaryKey + relatedMany: [RelatedMany] @hasMany(references: ["primaryId"]) + relatedOne: RelatedOne @hasOne(references: ["primaryId"]) + } + + type RelatedMany @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: ["primaryId"]) + } + + type RelatedOne @model { + id: ID! @primaryKey + primaryId: ID! + primary: Primary @belongsTo(references: ["primaryId"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'Primary', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Primary', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'RelatedMany', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'RelatedMany', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'RelatedOne', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'RelatedOne', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('double linked references', () => { + const schema = /* GraphQL */ ` + type Foo @model { + id: ID! + bar1: Bar @hasOne(references: ["bar1Id"]) + bar2: Bar @hasOne(references: ["bar2Id"]) + } + + type Bar @model { + id: ID! + bar1Id: ID + bar2Id: ID + foo1: Foo @belongsTo(references: ["bar1Id"]) + foo2: Foo @belongsTo(references: ["bar2Id"]) + } + `; + expect(getVisitorPipelinedTransformer(schema, 'Foo', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Foo', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Bar', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Bar', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('hasMany with sortKeyFields on primary key', () => { + const schema = /* GraphQL */ ` + type Primary @model { + tenantId: ID! @primaryKey(sortKeyFields: ["instanceId", "recordId"]) + instanceId: ID! + recordId: ID! + content: String + related: [Related!] @hasMany(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + + type Related @model { + content: String + primaryTenantId: ID! + primaryInstanceId: ID! + primaryRecordId: ID! + primary: Primary @belongsTo(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + `; + + expect(getVisitorPipelinedTransformer(schema, 'Primary', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Primary', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Related', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Related', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + + test('hasOne with sortKeyFields on primary key', () => { + const schema = /* GraphQL */ ` + type Primary @model { + tenantId: ID! @primaryKey(sortKeyFields: ["instanceId", "recordId"]) + instanceId: ID! + recordId: ID! + content: String + related: Related @hasOne(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + + type Related @model { + content: String + primaryTenantId: ID! + primaryInstanceId: ID! + primaryRecordId: ID! + primary: Primary @belongsTo(references: ["primaryTenantId", "primaryInstanceId", "primaryRecordId"]) + } + `; + + expect(getVisitorPipelinedTransformer(schema, 'Primary', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Primary', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Related', CodeGenGenerateEnum.code, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + expect(getVisitorPipelinedTransformer(schema, 'Related', CodeGenGenerateEnum.metadata, { + respectPrimaryKeyAttributesOnConnectionField: true, + }).generate()).toMatchSnapshot(); + }); + }); }); diff --git a/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts b/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts index cb2cea965..3d0f626ca 100644 --- a/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts +++ b/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts @@ -1181,7 +1181,8 @@ export class AppSyncModelVisitor< connectionInfo.kind !== CodeGenConnectionType.HAS_MANY && connectionInfo.kind !== CodeGenConnectionType.HAS_ONE && connectionInfo.targetNames && - connectionInfo.targetName !== 'id' + connectionInfo.targetName !== 'id' && + !connectionInfo.isUsingReferences ) { // Need to remove the field that is targetName connectionInfo.targetNames.forEach(targetName => removeFieldFromModel(model, targetName)); From 854bfea9cb692fba558d224d039c027f0240a20b Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Mon, 22 Apr 2024 11:19:53 -0600 Subject: [PATCH 5/8] fix!: use transformer version 2 by default (#813) BREAKING CHANGE: use transformer version 2 by default --- packages/graphql-generator/API.md | 2 +- .../src/__tests__/__snapshots__/models.test.ts.snap | 9 ++++++--- packages/graphql-generator/src/models.ts | 2 +- packages/graphql-generator/src/typescript.ts | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/graphql-generator/API.md b/packages/graphql-generator/API.md index d514d95c0..2e747ea75 100644 --- a/packages/graphql-generator/API.md +++ b/packages/graphql-generator/API.md @@ -25,7 +25,7 @@ export type GenerateModelsOptions = { generateIndexRules?: boolean; emitAuthProvider?: boolean; useExperimentalPipelinedTransformer?: boolean; - transformerVersion?: boolean; + transformerVersion?: number; respectPrimaryKeyAttributesOnConnectionField?: boolean; improvePluralization?: boolean; generateModelsForLazyLoadAndCustomSelectionSet?: boolean; diff --git a/packages/graphql-generator/src/__tests__/__snapshots__/models.test.ts.snap b/packages/graphql-generator/src/__tests__/__snapshots__/models.test.ts.snap index 49b3fd925..4d1eca50b 100644 --- a/packages/graphql-generator/src/__tests__/__snapshots__/models.test.ts.snap +++ b/packages/graphql-generator/src/__tests__/__snapshots__/models.test.ts.snap @@ -2259,7 +2259,8 @@ extension Blog { public static let schema = defineSchema { model in let blog = Blog.keys - model.pluralName = \\"Blogs\\" + model.listPluralName = \\"Blogs\\" + model.syncPluralName = \\"Blogs\\" model.attributes( .primaryKey(fields: [blog.id]) @@ -2351,7 +2352,8 @@ extension Comment { public static let schema = defineSchema { model in let comment = Comment.keys - model.pluralName = \\"Comments\\" + model.listPluralName = \\"Comments\\" + model.syncPluralName = \\"Comments\\" model.attributes( .primaryKey(fields: [comment.id]) @@ -2468,7 +2470,8 @@ extension Post { public static let schema = defineSchema { model in let post = Post.keys - model.pluralName = \\"Posts\\" + model.listPluralName = \\"Posts\\" + model.syncPluralName = \\"Posts\\" model.attributes( .primaryKey(fields: [post.id]) diff --git a/packages/graphql-generator/src/models.ts b/packages/graphql-generator/src/models.ts index c563c3778..ffb00b096 100644 --- a/packages/graphql-generator/src/models.ts +++ b/packages/graphql-generator/src/models.ts @@ -19,7 +19,7 @@ export async function generateModels(options: GenerateModelsOptions): Promise Date: Thu, 25 Apr 2024 07:43:25 -0600 Subject: [PATCH 6/8] test: update snapshots (#819) --- .../appsync-dart-visitor.test.ts.snap | 135 ++++++++++++------ 1 file changed, 91 insertions(+), 44 deletions(-) diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap index b66b6b0b4..6c08b4f5c 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap @@ -11830,11 +11830,15 @@ class Foo extends amplify_core.Model { Foo.fromJson(Map json) : id = json['id'], - _bar1 = json['bar1']?['serializedData'] != null - ? Bar.fromJson(new Map.from(json['bar1']['serializedData'])) + _bar1 = json['bar1'] != null + ? json['bar1']['serializedData'] != null + ? Bar.fromJson(new Map.from(json['bar1']['serializedData'])) + : Bar.fromJson(new Map.from(json['bar1'])) : null, - _bar2 = json['bar2']?['serializedData'] != null - ? Bar.fromJson(new Map.from(json['bar2']['serializedData'])) + _bar2 = json['bar2'] != null + ? json['bar2']['serializedData'] != null + ? Bar.fromJson(new Map.from(json['bar2']['serializedData'])) + : Bar.fromJson(new Map.from(json['bar2'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -12101,11 +12105,15 @@ class Bar extends amplify_core.Model { : id = json['id'], _bar1Id = json['bar1Id'], _bar2Id = json['bar2Id'], - _foo1 = json['foo1']?['serializedData'] != null - ? Foo.fromJson(new Map.from(json['foo1']['serializedData'])) + _foo1 = json['foo1'] != null + ? json['foo1']['serializedData'] != null + ? Foo.fromJson(new Map.from(json['foo1']['serializedData'])) + : Foo.fromJson(new Map.from(json['foo1'])) : null, - _foo2 = json['foo2']?['serializedData'] != null - ? Foo.fromJson(new Map.from(json['foo2']['serializedData'])) + _foo2 = json['foo2'] != null + ? json['foo2']['serializedData'] != null + ? Foo.fromJson(new Map.from(json['foo2']['serializedData'])) + : Foo.fromJson(new Map.from(json['foo2'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -12429,12 +12437,19 @@ class Primary extends amplify_core.Model { _instanceId = json['instanceId'], _recordId = json['recordId'], _content = json['content'], - _related = json['related'] is List - ? (json['related'] as List) - .where((e) => e?['serializedData'] != null) - .map((e) => Related.fromJson(new Map.from(e['serializedData']))) - .toList() - : null, + _related = json['related'] is Map + ? (json['related']['items'] is List + ? (json['related']['items'] as List) + .where((e) => e != null) + .map((e) => Related.fromJson(new Map.from(e))) + .toList() + : null) + : (json['related'] is List + ? (json['related'] as List) + .where((e) => e?['serializedData'] != null) + .map((e) => Related.fromJson(new Map.from(e?['serializedData']))) + .toList() + : null), _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -12774,8 +12789,10 @@ class Related extends amplify_core.Model { _primaryTenantId = json['primaryTenantId'], _primaryInstanceId = json['primaryInstanceId'], _primaryRecordId = json['primaryRecordId'], - _primary = json['primary']?['serializedData'] != null - ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + _primary = json['primary'] != null + ? json['primary']['serializedData'] != null + ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + : Primary.fromJson(new Map.from(json['primary'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -13103,8 +13120,10 @@ class Primary extends amplify_core.Model { _instanceId = json['instanceId'], _recordId = json['recordId'], _content = json['content'], - _related = json['related']?['serializedData'] != null - ? Related.fromJson(new Map.from(json['related']['serializedData'])) + _related = json['related'] != null + ? json['related']['serializedData'] != null + ? Related.fromJson(new Map.from(json['related']['serializedData'])) + : Related.fromJson(new Map.from(json['related'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -13445,8 +13464,10 @@ class Related extends amplify_core.Model { _primaryTenantId = json['primaryTenantId'], _primaryInstanceId = json['primaryInstanceId'], _primaryRecordId = json['primaryRecordId'], - _primary = json['primary']?['serializedData'] != null - ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + _primary = json['primary'] != null + ? json['primary']['serializedData'] != null + ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + : Primary.fromJson(new Map.from(json['primary'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -13711,12 +13732,19 @@ class SqlPrimary extends amplify_core.Model { SqlPrimary.fromJson(Map json) : id = (json['id'] as num?)?.toInt(), _content = json['content'], - _related = json['related'] is List - ? (json['related'] as List) - .where((e) => e?['serializedData'] != null) - .map((e) => SqlRelated.fromJson(new Map.from(e['serializedData']))) - .toList() - : null, + _related = json['related'] is Map + ? (json['related']['items'] is List + ? (json['related']['items'] as List) + .where((e) => e != null) + .map((e) => SqlRelated.fromJson(new Map.from(e))) + .toList() + : null) + : (json['related'] is List + ? (json['related'] as List) + .where((e) => e?['serializedData'] != null) + .map((e) => SqlRelated.fromJson(new Map.from(e?['serializedData']))) + .toList() + : null), _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -13981,8 +14009,10 @@ class SqlRelated extends amplify_core.Model { : id = (json['id'] as num?)?.toInt(), _content = json['content'], _primaryId = (json['primaryId'] as num?)?.toInt(), - _primary = json['primary']?['serializedData'] != null - ? SqlPrimary.fromJson(new Map.from(json['primary']['serializedData'])) + _primary = json['primary'] != null + ? json['primary']['serializedData'] != null + ? SqlPrimary.fromJson(new Map.from(json['primary']['serializedData'])) + : SqlPrimary.fromJson(new Map.from(json['primary'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -14234,14 +14264,23 @@ class Primary extends amplify_core.Model { Primary.fromJson(Map json) : id = json['id'], - _relatedMany = json['relatedMany'] is List - ? (json['relatedMany'] as List) - .where((e) => e?['serializedData'] != null) - .map((e) => RelatedMany.fromJson(new Map.from(e['serializedData']))) - .toList() - : null, - _relatedOne = json['relatedOne']?['serializedData'] != null - ? RelatedOne.fromJson(new Map.from(json['relatedOne']['serializedData'])) + _relatedMany = json['relatedMany'] is Map + ? (json['relatedMany']['items'] is List + ? (json['relatedMany']['items'] as List) + .where((e) => e != null) + .map((e) => RelatedMany.fromJson(new Map.from(e))) + .toList() + : null) + : (json['relatedMany'] is List + ? (json['relatedMany'] as List) + .where((e) => e?['serializedData'] != null) + .map((e) => RelatedMany.fromJson(new Map.from(e?['serializedData']))) + .toList() + : null), + _relatedOne = json['relatedOne'] != null + ? json['relatedOne']['serializedData'] != null + ? RelatedOne.fromJson(new Map.from(json['relatedOne']['serializedData'])) + : RelatedOne.fromJson(new Map.from(json['relatedOne'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -14498,8 +14537,10 @@ class RelatedOne extends amplify_core.Model { RelatedOne.fromJson(Map json) : id = json['id'], _primaryId = json['primaryId'], - _primary = json['primary']?['serializedData'] != null - ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + _primary = json['primary'] != null + ? json['primary']['serializedData'] != null + ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + : Primary.fromJson(new Map.from(json['primary'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -14753,8 +14794,10 @@ class RelatedMany extends amplify_core.Model { RelatedMany.fromJson(Map json) : id = json['id'], _primaryId = json['primaryId'], - _primary = json['primary']?['serializedData'] != null - ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + _primary = json['primary'] != null + ? json['primary']['serializedData'] != null + ? Primary.fromJson(new Map.from(json['primary']['serializedData'])) + : Primary.fromJson(new Map.from(json['primary'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -14998,8 +15041,10 @@ class SqlPrimary extends amplify_core.Model { SqlPrimary.fromJson(Map json) : id = (json['id'] as num?)?.toInt(), _content = json['content'], - _related = json['related']?['serializedData'] != null - ? SqlRelated.fromJson(new Map.from(json['related']['serializedData'])) + _related = json['related'] != null + ? json['related']['serializedData'] != null + ? SqlRelated.fromJson(new Map.from(json['related']['serializedData'])) + : SqlRelated.fromJson(new Map.from(json['related'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; @@ -15265,8 +15310,10 @@ class SqlRelated extends amplify_core.Model { : id = (json['id'] as num?)?.toInt(), _content = json['content'], _primaryId = (json['primaryId'] as num?)?.toInt(), - _primary = json['primary']?['serializedData'] != null - ? SqlPrimary.fromJson(new Map.from(json['primary']['serializedData'])) + _primary = json['primary'] != null + ? json['primary']['serializedData'] != null + ? SqlPrimary.fromJson(new Map.from(json['primary']['serializedData'])) + : SqlPrimary.fromJson(new Map.from(json['primary'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; From e1b2035a6325cb608ed00b6a2779a458842db628 Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Thu, 25 Apr 2024 11:07:20 -0600 Subject: [PATCH 7/8] build: fix schema generation (#821) --- .../schemas/introspection/1/ModelIntrospectionSchema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename packages/appsync-modelgen-plugin/{src => }/schemas/introspection/1/ModelIntrospectionSchema.json (99%) diff --git a/packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json b/packages/appsync-modelgen-plugin/schemas/introspection/1/ModelIntrospectionSchema.json similarity index 99% rename from packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json rename to packages/appsync-modelgen-plugin/schemas/introspection/1/ModelIntrospectionSchema.json index 6b37c37bc..d92926be2 100644 --- a/packages/appsync-modelgen-plugin/src/schemas/introspection/1/ModelIntrospectionSchema.json +++ b/packages/appsync-modelgen-plugin/schemas/introspection/1/ModelIntrospectionSchema.json @@ -275,7 +275,8 @@ }, "required": [ "associatedWith", - "connectionType" + "connectionType", + "targetNames" ] }, "AssociationBelongsTo": { From e7320a9933b6c7fe11d3cb602b0d8d2a39ed177a Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Thu, 25 Apr 2024 13:00:12 -0600 Subject: [PATCH 8/8] fix: return reference behavior to main for all but introspection (#824) --- .../appsync-dart-visitor.test.ts.snap | 228 +++++++++++----- .../appsync-java-visitor.test.ts.snap | 250 ++++++++++++++---- .../appsync-swift-visitor.test.ts.snap | 124 ++++++--- .../src/utils/process-belongs-to.ts | 7 +- .../src/utils/process-connections-v2.ts | 14 +- .../src/utils/process-has-many.ts | 7 +- .../src/utils/process-has-one.ts | 9 +- .../src/visitors/appsync-visitor.ts | 6 +- 8 files changed, 472 insertions(+), 173 deletions(-) diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap index 6c08b4f5c..cead98d9c 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-dart-visitor.test.ts.snap @@ -11742,6 +11742,8 @@ class Foo extends amplify_core.Model { final Bar? _bar2; final amplify_core.TemporalDateTime? _createdAt; final amplify_core.TemporalDateTime? _updatedAt; + final String? _fooBar1Id; + final String? _fooBar2Id; @override getInstanceType() => classType; @@ -11772,13 +11774,23 @@ class Foo extends amplify_core.Model { return _updatedAt; } - const Foo._internal({required this.id, bar1, bar2, createdAt, updatedAt}): _bar1 = bar1, _bar2 = bar2, _createdAt = createdAt, _updatedAt = updatedAt; + String? get fooBar1Id { + return _fooBar1Id; + } + + String? get fooBar2Id { + return _fooBar2Id; + } - factory Foo({String? id, Bar? bar1, Bar? bar2}) { + const Foo._internal({required this.id, bar1, bar2, createdAt, updatedAt, fooBar1Id, fooBar2Id}): _bar1 = bar1, _bar2 = bar2, _createdAt = createdAt, _updatedAt = updatedAt, _fooBar1Id = fooBar1Id, _fooBar2Id = fooBar2Id; + + factory Foo({String? id, Bar? bar1, Bar? bar2, String? fooBar1Id, String? fooBar2Id}) { return Foo._internal( id: id == null ? amplify_core.UUID.getUUID() : id, bar1: bar1, - bar2: bar2); + bar2: bar2, + fooBar1Id: fooBar1Id, + fooBar2Id: fooBar2Id); } bool equals(Object other) { @@ -11791,7 +11803,9 @@ class Foo extends amplify_core.Model { return other is Foo && id == other.id && _bar1 == other._bar1 && - _bar2 == other._bar2; + _bar2 == other._bar2 && + _fooBar1Id == other._fooBar1Id && + _fooBar2Id == other._fooBar2Id; } @override @@ -11804,27 +11818,35 @@ class Foo extends amplify_core.Model { buffer.write(\\"Foo {\\"); buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); - buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"fooBar1Id=\\" + \\"$_fooBar1Id\\" + \\", \\"); + buffer.write(\\"fooBar2Id=\\" + \\"$_fooBar2Id\\"); buffer.write(\\"}\\"); return buffer.toString(); } - Foo copyWith({Bar? bar1, Bar? bar2}) { + Foo copyWith({Bar? bar1, Bar? bar2, String? fooBar1Id, String? fooBar2Id}) { return Foo._internal( id: id, bar1: bar1 ?? this.bar1, - bar2: bar2 ?? this.bar2); + bar2: bar2 ?? this.bar2, + fooBar1Id: fooBar1Id ?? this.fooBar1Id, + fooBar2Id: fooBar2Id ?? this.fooBar2Id); } Foo copyWithModelFieldValues({ ModelFieldValue? bar1, - ModelFieldValue? bar2 + ModelFieldValue? bar2, + ModelFieldValue? fooBar1Id, + ModelFieldValue? fooBar2Id }) { return Foo._internal( id: id, bar1: bar1 == null ? this.bar1 : bar1.value, - bar2: bar2 == null ? this.bar2 : bar2.value + bar2: bar2 == null ? this.bar2 : bar2.value, + fooBar1Id: fooBar1Id == null ? this.fooBar1Id : fooBar1Id.value, + fooBar2Id: fooBar2Id == null ? this.fooBar2Id : fooBar2Id.value ); } @@ -11841,10 +11863,12 @@ class Foo extends amplify_core.Model { : Bar.fromJson(new Map.from(json['bar2'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, - _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null, + _fooBar1Id = json['fooBar1Id'], + _fooBar2Id = json['fooBar2Id']; Map toJson() => { - 'id': id, 'bar1': _bar1?.toJson(), 'bar2': _bar2?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + 'id': id, 'bar1': _bar1?.toJson(), 'bar2': _bar2?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format(), 'fooBar1Id': _fooBar1Id, 'fooBar2Id': _fooBar2Id }; Map toMap() => { @@ -11852,7 +11876,9 @@ class Foo extends amplify_core.Model { 'bar1': _bar1, 'bar2': _bar2, 'createdAt': _createdAt, - 'updatedAt': _updatedAt + 'updatedAt': _updatedAt, + 'fooBar1Id': _fooBar1Id, + 'fooBar2Id': _fooBar2Id }; static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); @@ -11863,6 +11889,8 @@ class Foo extends amplify_core.Model { static final BAR2 = amplify_core.QueryField( fieldName: \\"bar2\\", fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Bar')); + static final FOOBAR1ID = amplify_core.QueryField(fieldName: \\"fooBar1Id\\"); + static final FOOBAR2ID = amplify_core.QueryField(fieldName: \\"fooBar2Id\\"); static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { modelSchemaDefinition.name = \\"Foo\\"; modelSchemaDefinition.pluralName = \\"Foos\\"; @@ -11873,14 +11901,14 @@ class Foo extends amplify_core.Model { key: Foo.BAR1, isRequired: false, ofModelName: 'Bar', - associatedKey: Bar.BAR1ID + associatedKey: Bar.FOO1 )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasOne( key: Foo.BAR2, isRequired: false, ofModelName: 'Bar', - associatedKey: Bar.BAR2ID + associatedKey: Bar.FOO1 )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( @@ -11896,6 +11924,18 @@ class Foo extends amplify_core.Model { isReadOnly: true, ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Foo.FOOBAR1ID, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Foo.FOOBAR2ID, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); }); } @@ -12163,14 +12203,14 @@ class Bar extends amplify_core.Model { modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( key: Bar.FOO1, isRequired: false, - targetNames: ['bar1Id'], + targetNames: ['barFoo1Id'], ofModelName: 'Foo' )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( key: Bar.FOO2, isRequired: false, - targetNames: ['bar2Id'], + targetNames: ['barFoo2Id'], ofModelName: 'Foo' )); @@ -12511,7 +12551,7 @@ class Primary extends amplify_core.Model { key: Primary.RELATED, isRequired: true, ofModelName: 'Related', - associatedKey: Related.PRIMARYTENANTID + associatedKey: Related.PRIMARY )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( @@ -12854,7 +12894,7 @@ class Related extends amplify_core.Model { modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( key: Related.PRIMARY, isRequired: false, - targetNames: ['primaryTenantId', 'primaryInstanceId', 'primaryRecordId'], + targetNames: ['primaryRelatedTenantId', 'primaryRelatedInstanceId', 'primaryRelatedRecordId'], ofModelName: 'Primary' )); @@ -12968,6 +13008,7 @@ class Primary extends amplify_core.Model { final Related? _related; final amplify_core.TemporalDateTime? _createdAt; final amplify_core.TemporalDateTime? _updatedAt; + final String? _primaryRelatedId; @override getInstanceType() => classType; @@ -13048,15 +13089,20 @@ class Primary extends amplify_core.Model { return _updatedAt; } - const Primary._internal({required tenantId, required instanceId, required recordId, content, related, createdAt, updatedAt}): _tenantId = tenantId, _instanceId = instanceId, _recordId = recordId, _content = content, _related = related, _createdAt = createdAt, _updatedAt = updatedAt; + String? get primaryRelatedId { + return _primaryRelatedId; + } + + const Primary._internal({required tenantId, required instanceId, required recordId, content, related, createdAt, updatedAt, primaryRelatedId}): _tenantId = tenantId, _instanceId = instanceId, _recordId = recordId, _content = content, _related = related, _createdAt = createdAt, _updatedAt = updatedAt, _primaryRelatedId = primaryRelatedId; - factory Primary({required String tenantId, required String instanceId, required String recordId, String? content, Related? related}) { + factory Primary({required String tenantId, required String instanceId, required String recordId, String? content, Related? related, String? primaryRelatedId}) { return Primary._internal( tenantId: tenantId, instanceId: instanceId, recordId: recordId, content: content, - related: related); + related: related, + primaryRelatedId: primaryRelatedId); } bool equals(Object other) { @@ -13071,7 +13117,8 @@ class Primary extends amplify_core.Model { _instanceId == other._instanceId && _recordId == other._recordId && _content == other._content && - _related == other._related; + _related == other._related && + _primaryRelatedId == other._primaryRelatedId; } @override @@ -13087,31 +13134,35 @@ class Primary extends amplify_core.Model { buffer.write(\\"recordId=\\" + \\"$_recordId\\" + \\", \\"); buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); - buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"primaryRelatedId=\\" + \\"$_primaryRelatedId\\"); buffer.write(\\"}\\"); return buffer.toString(); } - Primary copyWith({String? content, Related? related}) { + Primary copyWith({String? content, Related? related, String? primaryRelatedId}) { return Primary._internal( tenantId: tenantId, instanceId: instanceId, recordId: recordId, content: content ?? this.content, - related: related ?? this.related); + related: related ?? this.related, + primaryRelatedId: primaryRelatedId ?? this.primaryRelatedId); } Primary copyWithModelFieldValues({ ModelFieldValue? content, - ModelFieldValue? related + ModelFieldValue? related, + ModelFieldValue? primaryRelatedId }) { return Primary._internal( tenantId: tenantId, instanceId: instanceId, recordId: recordId, content: content == null ? this.content : content.value, - related: related == null ? this.related : related.value + related: related == null ? this.related : related.value, + primaryRelatedId: primaryRelatedId == null ? this.primaryRelatedId : primaryRelatedId.value ); } @@ -13126,10 +13177,11 @@ class Primary extends amplify_core.Model { : Related.fromJson(new Map.from(json['related'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, - _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null, + _primaryRelatedId = json['primaryRelatedId']; Map toJson() => { - 'tenantId': _tenantId, 'instanceId': _instanceId, 'recordId': _recordId, 'content': _content, 'related': _related?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + 'tenantId': _tenantId, 'instanceId': _instanceId, 'recordId': _recordId, 'content': _content, 'related': _related?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format(), 'primaryRelatedId': _primaryRelatedId }; Map toMap() => { @@ -13139,7 +13191,8 @@ class Primary extends amplify_core.Model { 'content': _content, 'related': _related, 'createdAt': _createdAt, - 'updatedAt': _updatedAt + 'updatedAt': _updatedAt, + 'primaryRelatedId': _primaryRelatedId }; static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); @@ -13150,6 +13203,7 @@ class Primary extends amplify_core.Model { static final RELATED = amplify_core.QueryField( fieldName: \\"related\\", fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'Related')); + static final PRIMARYRELATEDID = amplify_core.QueryField(fieldName: \\"primaryRelatedId\\"); static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { modelSchemaDefinition.name = \\"Primary\\"; modelSchemaDefinition.pluralName = \\"Primaries\\"; @@ -13186,7 +13240,7 @@ class Primary extends amplify_core.Model { key: Primary.RELATED, isRequired: false, ofModelName: 'Related', - associatedKey: Related.PRIMARYTENANTID + associatedKey: Related.PRIMARY )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( @@ -13202,6 +13256,12 @@ class Primary extends amplify_core.Model { isReadOnly: true, ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.PRIMARYRELATEDID, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); }); } @@ -13529,7 +13589,7 @@ class Related extends amplify_core.Model { modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( key: Related.PRIMARY, isRequired: false, - targetNames: ['primaryTenantId', 'primaryInstanceId', 'primaryRecordId'], + targetNames: ['relatedPrimaryTenantId', 'relatedPrimaryInstanceId', 'relatedPrimaryRecordId'], ofModelName: 'Primary' )); @@ -13786,7 +13846,7 @@ class SqlPrimary extends amplify_core.Model { key: SqlPrimary.RELATED, isRequired: true, ofModelName: 'SqlRelated', - associatedKey: SqlRelated.PRIMARYID + associatedKey: SqlRelated.PRIMARY )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( @@ -14063,7 +14123,7 @@ class SqlRelated extends amplify_core.Model { modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( key: SqlRelated.PRIMARY, isRequired: false, - targetNames: ['primaryId'], + targetNames: ['sqlPrimaryRelatedId'], ofModelName: 'SqlPrimary' )); @@ -14176,6 +14236,7 @@ class Primary extends amplify_core.Model { final RelatedOne? _relatedOne; final amplify_core.TemporalDateTime? _createdAt; final amplify_core.TemporalDateTime? _updatedAt; + final String? _primaryRelatedOneId; @override getInstanceType() => classType; @@ -14206,13 +14267,18 @@ class Primary extends amplify_core.Model { return _updatedAt; } - const Primary._internal({required this.id, relatedMany, relatedOne, createdAt, updatedAt}): _relatedMany = relatedMany, _relatedOne = relatedOne, _createdAt = createdAt, _updatedAt = updatedAt; + String? get primaryRelatedOneId { + return _primaryRelatedOneId; + } + + const Primary._internal({required this.id, relatedMany, relatedOne, createdAt, updatedAt, primaryRelatedOneId}): _relatedMany = relatedMany, _relatedOne = relatedOne, _createdAt = createdAt, _updatedAt = updatedAt, _primaryRelatedOneId = primaryRelatedOneId; - factory Primary({String? id, List? relatedMany, RelatedOne? relatedOne}) { + factory Primary({String? id, List? relatedMany, RelatedOne? relatedOne, String? primaryRelatedOneId}) { return Primary._internal( id: id == null ? amplify_core.UUID.getUUID() : id, relatedMany: relatedMany != null ? List.unmodifiable(relatedMany) : relatedMany, - relatedOne: relatedOne); + relatedOne: relatedOne, + primaryRelatedOneId: primaryRelatedOneId); } bool equals(Object other) { @@ -14225,7 +14291,8 @@ class Primary extends amplify_core.Model { return other is Primary && id == other.id && DeepCollectionEquality().equals(_relatedMany, other._relatedMany) && - _relatedOne == other._relatedOne; + _relatedOne == other._relatedOne && + _primaryRelatedOneId == other._primaryRelatedOneId; } @override @@ -14238,27 +14305,31 @@ class Primary extends amplify_core.Model { buffer.write(\\"Primary {\\"); buffer.write(\\"id=\\" + \\"$id\\" + \\", \\"); buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); - buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"primaryRelatedOneId=\\" + \\"$_primaryRelatedOneId\\"); buffer.write(\\"}\\"); return buffer.toString(); } - Primary copyWith({List? relatedMany, RelatedOne? relatedOne}) { + Primary copyWith({List? relatedMany, RelatedOne? relatedOne, String? primaryRelatedOneId}) { return Primary._internal( id: id, relatedMany: relatedMany ?? this.relatedMany, - relatedOne: relatedOne ?? this.relatedOne); + relatedOne: relatedOne ?? this.relatedOne, + primaryRelatedOneId: primaryRelatedOneId ?? this.primaryRelatedOneId); } Primary copyWithModelFieldValues({ ModelFieldValue?>? relatedMany, - ModelFieldValue? relatedOne + ModelFieldValue? relatedOne, + ModelFieldValue? primaryRelatedOneId }) { return Primary._internal( id: id, relatedMany: relatedMany == null ? this.relatedMany : relatedMany.value, - relatedOne: relatedOne == null ? this.relatedOne : relatedOne.value + relatedOne: relatedOne == null ? this.relatedOne : relatedOne.value, + primaryRelatedOneId: primaryRelatedOneId == null ? this.primaryRelatedOneId : primaryRelatedOneId.value ); } @@ -14283,10 +14354,11 @@ class Primary extends amplify_core.Model { : RelatedOne.fromJson(new Map.from(json['relatedOne'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, - _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null, + _primaryRelatedOneId = json['primaryRelatedOneId']; Map toJson() => { - 'id': id, 'relatedMany': _relatedMany?.map((RelatedMany? e) => e?.toJson()).toList(), 'relatedOne': _relatedOne?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + 'id': id, 'relatedMany': _relatedMany?.map((RelatedMany? e) => e?.toJson()).toList(), 'relatedOne': _relatedOne?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format(), 'primaryRelatedOneId': _primaryRelatedOneId }; Map toMap() => { @@ -14294,7 +14366,8 @@ class Primary extends amplify_core.Model { 'relatedMany': _relatedMany, 'relatedOne': _relatedOne, 'createdAt': _createdAt, - 'updatedAt': _updatedAt + 'updatedAt': _updatedAt, + 'primaryRelatedOneId': _primaryRelatedOneId }; static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); @@ -14305,6 +14378,7 @@ class Primary extends amplify_core.Model { static final RELATEDONE = amplify_core.QueryField( fieldName: \\"relatedOne\\", fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'RelatedOne')); + static final PRIMARYRELATEDONEID = amplify_core.QueryField(fieldName: \\"primaryRelatedOneId\\"); static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { modelSchemaDefinition.name = \\"Primary\\"; modelSchemaDefinition.pluralName = \\"Primaries\\"; @@ -14319,14 +14393,14 @@ class Primary extends amplify_core.Model { key: Primary.RELATEDMANY, isRequired: false, ofModelName: 'RelatedMany', - associatedKey: RelatedMany.PRIMARYID + associatedKey: RelatedMany.PRIMARY )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.hasOne( key: Primary.RELATEDONE, isRequired: false, ofModelName: 'RelatedOne', - associatedKey: RelatedOne.PRIMARYID + associatedKey: RelatedOne.PRIMARY )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( @@ -14342,6 +14416,12 @@ class Primary extends amplify_core.Model { isReadOnly: true, ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: Primary.PRIMARYRELATEDONEID, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.string) + )); }); } @@ -14582,7 +14662,7 @@ class RelatedOne extends amplify_core.Model { modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( key: RelatedOne.PRIMARY, isRequired: false, - targetNames: ['primaryId'], + targetNames: ['relatedOnePrimaryId'], ofModelName: 'Primary' )); @@ -14839,7 +14919,7 @@ class RelatedMany extends amplify_core.Model { modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( key: RelatedMany.PRIMARY, isRequired: false, - targetNames: ['primaryId'], + targetNames: ['primaryRelatedManyId'], ofModelName: 'Primary' )); @@ -14951,6 +15031,7 @@ class SqlPrimary extends amplify_core.Model { final SqlRelated? _related; final amplify_core.TemporalDateTime? _createdAt; final amplify_core.TemporalDateTime? _updatedAt; + final int? _sqlPrimaryRelatedId; @override getInstanceType() => classType; @@ -14981,13 +15062,18 @@ class SqlPrimary extends amplify_core.Model { return _updatedAt; } - const SqlPrimary._internal({required this.id, content, related, createdAt, updatedAt}): _content = content, _related = related, _createdAt = createdAt, _updatedAt = updatedAt; + int? get sqlPrimaryRelatedId { + return _sqlPrimaryRelatedId; + } - factory SqlPrimary({int? id, String? content, SqlRelated? related}) { + const SqlPrimary._internal({required this.id, content, related, createdAt, updatedAt, sqlPrimaryRelatedId}): _content = content, _related = related, _createdAt = createdAt, _updatedAt = updatedAt, _sqlPrimaryRelatedId = sqlPrimaryRelatedId; + + factory SqlPrimary({int? id, String? content, SqlRelated? related, int? sqlPrimaryRelatedId}) { return SqlPrimary._internal( id: id == null ? amplify_core.UUID.getUUID() : id, content: content, - related: related); + related: related, + sqlPrimaryRelatedId: sqlPrimaryRelatedId); } bool equals(Object other) { @@ -15000,7 +15086,8 @@ class SqlPrimary extends amplify_core.Model { return other is SqlPrimary && id == other.id && _content == other._content && - _related == other._related; + _related == other._related && + _sqlPrimaryRelatedId == other._sqlPrimaryRelatedId; } @override @@ -15014,27 +15101,31 @@ class SqlPrimary extends amplify_core.Model { buffer.write(\\"id=\\" + (id != null ? id!.toString() : \\"null\\") + \\", \\"); buffer.write(\\"content=\\" + \\"$_content\\" + \\", \\"); buffer.write(\\"createdAt=\\" + (_createdAt != null ? _createdAt!.format() : \\"null\\") + \\", \\"); - buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\")); + buffer.write(\\"updatedAt=\\" + (_updatedAt != null ? _updatedAt!.format() : \\"null\\") + \\", \\"); + buffer.write(\\"sqlPrimaryRelatedId=\\" + (_sqlPrimaryRelatedId != null ? _sqlPrimaryRelatedId!.toString() : \\"null\\")); buffer.write(\\"}\\"); return buffer.toString(); } - SqlPrimary copyWith({String? content, SqlRelated? related}) { + SqlPrimary copyWith({String? content, SqlRelated? related, int? sqlPrimaryRelatedId}) { return SqlPrimary._internal( id: id, content: content ?? this.content, - related: related ?? this.related); + related: related ?? this.related, + sqlPrimaryRelatedId: sqlPrimaryRelatedId ?? this.sqlPrimaryRelatedId); } SqlPrimary copyWithModelFieldValues({ ModelFieldValue? content, - ModelFieldValue? related + ModelFieldValue? related, + ModelFieldValue? sqlPrimaryRelatedId }) { return SqlPrimary._internal( id: id, content: content == null ? this.content : content.value, - related: related == null ? this.related : related.value + related: related == null ? this.related : related.value, + sqlPrimaryRelatedId: sqlPrimaryRelatedId == null ? this.sqlPrimaryRelatedId : sqlPrimaryRelatedId.value ); } @@ -15047,10 +15138,11 @@ class SqlPrimary extends amplify_core.Model { : SqlRelated.fromJson(new Map.from(json['related'])) : null, _createdAt = json['createdAt'] != null ? amplify_core.TemporalDateTime.fromString(json['createdAt']) : null, - _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null; + _updatedAt = json['updatedAt'] != null ? amplify_core.TemporalDateTime.fromString(json['updatedAt']) : null, + _sqlPrimaryRelatedId = (json['sqlPrimaryRelatedId'] as num?)?.toInt(); Map toJson() => { - 'id': id, 'content': _content, 'related': _related?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format() + 'id': id, 'content': _content, 'related': _related?.toJson(), 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format(), 'sqlPrimaryRelatedId': _sqlPrimaryRelatedId }; Map toMap() => { @@ -15058,7 +15150,8 @@ class SqlPrimary extends amplify_core.Model { 'content': _content, 'related': _related, 'createdAt': _createdAt, - 'updatedAt': _updatedAt + 'updatedAt': _updatedAt, + 'sqlPrimaryRelatedId': _sqlPrimaryRelatedId }; static final amplify_core.QueryModelIdentifier MODEL_IDENTIFIER = amplify_core.QueryModelIdentifier(); @@ -15067,6 +15160,7 @@ class SqlPrimary extends amplify_core.Model { static final RELATED = amplify_core.QueryField( fieldName: \\"related\\", fieldType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.model, ofModelName: 'SqlRelated')); + static final SQLPRIMARYRELATEDID = amplify_core.QueryField(fieldName: \\"sqlPrimaryRelatedId\\"); static var schema = amplify_core.Model.defineSchema(define: (amplify_core.ModelSchemaDefinition modelSchemaDefinition) { modelSchemaDefinition.name = \\"SqlPrimary\\"; modelSchemaDefinition.pluralName = \\"SqlPrimaries\\"; @@ -15087,7 +15181,7 @@ class SqlPrimary extends amplify_core.Model { key: SqlPrimary.RELATED, isRequired: false, ofModelName: 'SqlRelated', - associatedKey: SqlRelated.PRIMARYID + associatedKey: SqlRelated.PRIMARY )); modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.nonQueryField( @@ -15103,6 +15197,12 @@ class SqlPrimary extends amplify_core.Model { isReadOnly: true, ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.dateTime) )); + + modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.field( + key: SqlPrimary.SQLPRIMARYRELATEDID, + isRequired: false, + ofType: amplify_core.ModelFieldType(amplify_core.ModelFieldTypeEnum.int) + )); }); } @@ -15364,7 +15464,7 @@ class SqlRelated extends amplify_core.Model { modelSchemaDefinition.addField(amplify_core.ModelFieldDefinition.belongsTo( key: SqlRelated.PRIMARY, isRequired: false, - targetNames: ['primaryId'], + targetNames: ['sqlRelatedPrimaryId'], ofModelName: 'SqlPrimary' )); diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-java-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-java-visitor.test.ts.snap index d82be5ff2..5548dfa39 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-java-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-java-visitor.test.ts.snap @@ -7871,11 +7871,15 @@ import static com.amplifyframework.core.model.query.predicate.QueryField.field; @ModelConfig(pluralName = \\"Foos\\", type = Model.Type.USER, version = 1) public final class Foo implements Model { public static final QueryField ID = field(\\"Foo\\", \\"id\\"); + public static final QueryField FOO_BAR1_ID = field(\\"Foo\\", \\"fooBar1Id\\"); + public static final QueryField FOO_BAR2_ID = field(\\"Foo\\", \\"fooBar2Id\\"); private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; - private final @ModelField(targetType=\\"Bar\\") @HasOne(associatedWith = \\"bar1Id\\", type = Bar.class) Bar bar1 = null; - private final @ModelField(targetType=\\"Bar\\") @HasOne(associatedWith = \\"bar2Id\\", type = Bar.class) Bar bar2 = null; + private final @ModelField(targetType=\\"Bar\\") @HasOne(associatedWith = \\"foo1\\", type = Bar.class) Bar bar1 = null; + private final @ModelField(targetType=\\"Bar\\") @HasOne(associatedWith = \\"foo1\\", type = Bar.class) Bar bar2 = null; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + private final @ModelField(targetType=\\"ID\\") String fooBar1Id; + private final @ModelField(targetType=\\"ID\\") String fooBar2Id; /** @deprecated This API is internal to Amplify and should not be used. */ @Deprecated public String resolveIdentifier() { @@ -7902,8 +7906,18 @@ public final class Foo implements Model { return updatedAt; } - private Foo(String id) { + public String getFooBar1Id() { + return fooBar1Id; + } + + public String getFooBar2Id() { + return fooBar2Id; + } + + private Foo(String id, String fooBar1Id, String fooBar2Id) { this.id = id; + this.fooBar1Id = fooBar1Id; + this.fooBar2Id = fooBar2Id; } @Override @@ -7916,7 +7930,9 @@ public final class Foo implements Model { Foo foo = (Foo) obj; return ObjectsCompat.equals(getId(), foo.getId()) && ObjectsCompat.equals(getCreatedAt(), foo.getCreatedAt()) && - ObjectsCompat.equals(getUpdatedAt(), foo.getUpdatedAt()); + ObjectsCompat.equals(getUpdatedAt(), foo.getUpdatedAt()) && + ObjectsCompat.equals(getFooBar1Id(), foo.getFooBar1Id()) && + ObjectsCompat.equals(getFooBar2Id(), foo.getFooBar2Id()); } } @@ -7926,6 +7942,8 @@ public final class Foo implements Model { .append(getId()) .append(getCreatedAt()) .append(getUpdatedAt()) + .append(getFooBar1Id()) + .append(getFooBar2Id()) .toString() .hashCode(); } @@ -7936,7 +7954,9 @@ public final class Foo implements Model { .append(\\"Foo {\\") .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") - .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt()) + \\", \\") + .append(\\"fooBar1Id=\\" + String.valueOf(getFooBar1Id()) + \\", \\") + .append(\\"fooBar2Id=\\" + String.valueOf(getFooBar2Id())) .append(\\"}\\") .toString(); } @@ -7955,27 +7975,37 @@ public final class Foo implements Model { */ public static Foo justId(String id) { return new Foo( - id + id, + null, + null ); } public CopyOfBuilder copyOfBuilder() { - return new CopyOfBuilder(id); + return new CopyOfBuilder(id, + fooBar1Id, + fooBar2Id); } public interface BuildStep { Foo build(); BuildStep id(String id); + BuildStep fooBar1Id(String fooBar1Id); + BuildStep fooBar2Id(String fooBar2Id); } public static class Builder implements BuildStep { private String id; + private String fooBar1Id; + private String fooBar2Id; public Builder() { } - private Builder(String id) { + private Builder(String id, String fooBar1Id, String fooBar2Id) { this.id = id; + this.fooBar1Id = fooBar1Id; + this.fooBar2Id = fooBar2Id; } @Override @@ -7983,7 +8013,21 @@ public final class Foo implements Model { String id = this.id != null ? this.id : UUID.randomUUID().toString(); return new Foo( - id); + id, + fooBar1Id, + fooBar2Id); + } + + @Override + public BuildStep fooBar1Id(String fooBar1Id) { + this.fooBar1Id = fooBar1Id; + return this; + } + + @Override + public BuildStep fooBar2Id(String fooBar2Id) { + this.fooBar2Id = fooBar2Id; + return this; } /** @@ -7998,10 +8042,20 @@ public final class Foo implements Model { public final class CopyOfBuilder extends Builder { - private CopyOfBuilder(String id) { - super(id); + private CopyOfBuilder(String id, String fooBar1Id, String fooBar2Id) { + super(id, fooBar1Id, fooBar2Id); } + + @Override + public CopyOfBuilder fooBar1Id(String fooBar1Id) { + return (CopyOfBuilder) super.fooBar1Id(fooBar1Id); + } + + @Override + public CopyOfBuilder fooBar2Id(String fooBar2Id) { + return (CopyOfBuilder) super.fooBar2Id(fooBar2Id); + } } @@ -8044,13 +8098,13 @@ public final class Bar implements Model { public static final QueryField ID = field(\\"Bar\\", \\"id\\"); public static final QueryField BAR1_ID = field(\\"Bar\\", \\"bar1Id\\"); public static final QueryField BAR2_ID = field(\\"Bar\\", \\"bar2Id\\"); - public static final QueryField FOO1 = field(\\"Bar\\", \\"bar1Id\\"); - public static final QueryField FOO2 = field(\\"Bar\\", \\"bar2Id\\"); + public static final QueryField FOO1 = field(\\"Bar\\", \\"barFoo1Id\\"); + public static final QueryField FOO2 = field(\\"Bar\\", \\"barFoo2Id\\"); private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; private final @ModelField(targetType=\\"ID\\") String bar1Id; private final @ModelField(targetType=\\"ID\\") String bar2Id; - private final @ModelField(targetType=\\"Foo\\") @BelongsTo(targetName = \\"bar1Id\\", targetNames = {\\"bar1Id\\"}, type = Foo.class) Foo foo1; - private final @ModelField(targetType=\\"Foo\\") @BelongsTo(targetName = \\"bar2Id\\", targetNames = {\\"bar2Id\\"}, type = Foo.class) Foo foo2; + private final @ModelField(targetType=\\"Foo\\") @BelongsTo(targetName = \\"barFoo1Id\\", targetNames = {\\"barFoo1Id\\"}, type = Foo.class) Foo foo1; + private final @ModelField(targetType=\\"Foo\\") @BelongsTo(targetName = \\"barFoo2Id\\", targetNames = {\\"barFoo2Id\\"}, type = Foo.class) Foo foo2; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; /** @deprecated This API is internal to Amplify and should not be used. */ @@ -8319,7 +8373,7 @@ public final class Primary implements Model { private final @ModelField(targetType=\\"ID\\", isRequired = true) String instanceId; private final @ModelField(targetType=\\"ID\\", isRequired = true) String recordId; private final @ModelField(targetType=\\"String\\") String content; - private final @ModelField(targetType=\\"Related\\") @HasMany(associatedWith = \\"primaryTenantId\\", type = Related.class) List related = null; + private final @ModelField(targetType=\\"Related\\") @HasMany(associatedWith = \\"primary\\", type = Related.class) List related = null; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; private PrimaryIdentifier primaryIdentifier; @@ -8568,13 +8622,13 @@ public final class Related implements Model { public static final QueryField PRIMARY_TENANT_ID = field(\\"Related\\", \\"primaryTenantId\\"); public static final QueryField PRIMARY_INSTANCE_ID = field(\\"Related\\", \\"primaryInstanceId\\"); public static final QueryField PRIMARY_RECORD_ID = field(\\"Related\\", \\"primaryRecordId\\"); - public static final QueryField PRIMARY = field(\\"Related\\", \\"primaryTenantId\\"); + public static final QueryField PRIMARY = field(\\"Related\\", \\"primaryRelatedTenantId\\"); private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; private final @ModelField(targetType=\\"String\\") String content; private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryTenantId; private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryInstanceId; private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryRecordId; - private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryTenantId\\", targetNames = {\\"primaryTenantId\\", \\"primaryInstanceId\\", \\"primaryRecordId\\"}, type = Primary.class) Primary primary; + private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryRelatedTenantId\\", targetNames = {\\"primaryRelatedTenantId\\", \\"primaryRelatedInstanceId\\", \\"primaryRelatedRecordId\\"}, type = Primary.class) Primary primary; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; /** @deprecated This API is internal to Amplify and should not be used. */ @@ -8881,13 +8935,15 @@ public final class Primary implements Model { public static final QueryField INSTANCE_ID = field(\\"Primary\\", \\"instanceId\\"); public static final QueryField RECORD_ID = field(\\"Primary\\", \\"recordId\\"); public static final QueryField CONTENT = field(\\"Primary\\", \\"content\\"); + public static final QueryField PRIMARY_RELATED_ID = field(\\"Primary\\", \\"primaryRelatedId\\"); private final @ModelField(targetType=\\"ID\\", isRequired = true) String tenantId; private final @ModelField(targetType=\\"ID\\", isRequired = true) String instanceId; private final @ModelField(targetType=\\"ID\\", isRequired = true) String recordId; private final @ModelField(targetType=\\"String\\") String content; - private final @ModelField(targetType=\\"Related\\") @HasOne(associatedWith = \\"primaryTenantId\\", type = Related.class) Related related = null; + private final @ModelField(targetType=\\"Related\\") @HasOne(associatedWith = \\"primary\\", type = Related.class) Related related = null; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + private final @ModelField(targetType=\\"ID\\") String primaryRelatedId; private PrimaryIdentifier primaryIdentifier; /** @deprecated This API is internal to Amplify and should not be used. */ @Deprecated @@ -8926,11 +8982,16 @@ public final class Primary implements Model { return updatedAt; } - private Primary(String tenantId, String instanceId, String recordId, String content) { + public String getPrimaryRelatedId() { + return primaryRelatedId; + } + + private Primary(String tenantId, String instanceId, String recordId, String content, String primaryRelatedId) { this.tenantId = tenantId; this.instanceId = instanceId; this.recordId = recordId; this.content = content; + this.primaryRelatedId = primaryRelatedId; } @Override @@ -8946,7 +9007,8 @@ public final class Primary implements Model { ObjectsCompat.equals(getRecordId(), primary.getRecordId()) && ObjectsCompat.equals(getContent(), primary.getContent()) && ObjectsCompat.equals(getCreatedAt(), primary.getCreatedAt()) && - ObjectsCompat.equals(getUpdatedAt(), primary.getUpdatedAt()); + ObjectsCompat.equals(getUpdatedAt(), primary.getUpdatedAt()) && + ObjectsCompat.equals(getPrimaryRelatedId(), primary.getPrimaryRelatedId()); } } @@ -8959,6 +9021,7 @@ public final class Primary implements Model { .append(getContent()) .append(getCreatedAt()) .append(getUpdatedAt()) + .append(getPrimaryRelatedId()) .toString() .hashCode(); } @@ -8972,7 +9035,8 @@ public final class Primary implements Model { .append(\\"recordId=\\" + String.valueOf(getRecordId()) + \\", \\") .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") - .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt()) + \\", \\") + .append(\\"primaryRelatedId=\\" + String.valueOf(getPrimaryRelatedId())) .append(\\"}\\") .toString(); } @@ -8985,7 +9049,8 @@ public final class Primary implements Model { return new CopyOfBuilder(tenantId, instanceId, recordId, - content); + content, + primaryRelatedId); } public interface TenantIdStep { InstanceIdStep tenantId(String tenantId); @@ -9005,6 +9070,7 @@ public final class Primary implements Model { public interface BuildStep { Primary build(); BuildStep content(String content); + BuildStep primaryRelatedId(String primaryRelatedId); } @@ -9013,15 +9079,17 @@ public final class Primary implements Model { private String instanceId; private String recordId; private String content; + private String primaryRelatedId; public Builder() { } - private Builder(String tenantId, String instanceId, String recordId, String content) { + private Builder(String tenantId, String instanceId, String recordId, String content, String primaryRelatedId) { this.tenantId = tenantId; this.instanceId = instanceId; this.recordId = recordId; this.content = content; + this.primaryRelatedId = primaryRelatedId; } @Override @@ -9031,7 +9099,8 @@ public final class Primary implements Model { tenantId, instanceId, recordId, - content); + content, + primaryRelatedId); } @Override @@ -9060,12 +9129,18 @@ public final class Primary implements Model { this.content = content; return this; } + + @Override + public BuildStep primaryRelatedId(String primaryRelatedId) { + this.primaryRelatedId = primaryRelatedId; + return this; + } } public final class CopyOfBuilder extends Builder { - private CopyOfBuilder(String tenantId, String instanceId, String recordId, String content) { - super(tenantId, instanceId, recordId, content); + private CopyOfBuilder(String tenantId, String instanceId, String recordId, String content, String primaryRelatedId) { + super(tenantId, instanceId, recordId, content, primaryRelatedId); Objects.requireNonNull(tenantId); Objects.requireNonNull(instanceId); Objects.requireNonNull(recordId); @@ -9090,6 +9165,11 @@ public final class Primary implements Model { public CopyOfBuilder content(String content) { return (CopyOfBuilder) super.content(content); } + + @Override + public CopyOfBuilder primaryRelatedId(String primaryRelatedId) { + return (CopyOfBuilder) super.primaryRelatedId(primaryRelatedId); + } } @@ -9134,13 +9214,13 @@ public final class Related implements Model { public static final QueryField PRIMARY_TENANT_ID = field(\\"Related\\", \\"primaryTenantId\\"); public static final QueryField PRIMARY_INSTANCE_ID = field(\\"Related\\", \\"primaryInstanceId\\"); public static final QueryField PRIMARY_RECORD_ID = field(\\"Related\\", \\"primaryRecordId\\"); - public static final QueryField PRIMARY = field(\\"Related\\", \\"primaryTenantId\\"); + public static final QueryField PRIMARY = field(\\"Related\\", \\"relatedPrimaryTenantId\\"); private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; private final @ModelField(targetType=\\"String\\") String content; private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryTenantId; private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryInstanceId; private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryRecordId; - private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryTenantId\\", targetNames = {\\"primaryTenantId\\", \\"primaryInstanceId\\", \\"primaryRecordId\\"}, type = Primary.class) Primary primary; + private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"relatedPrimaryTenantId\\", targetNames = {\\"relatedPrimaryTenantId\\", \\"relatedPrimaryInstanceId\\", \\"relatedPrimaryRecordId\\"}, type = Primary.class) Primary primary; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; /** @deprecated This API is internal to Amplify and should not be used. */ @@ -9447,7 +9527,7 @@ public final class SqlPrimary implements Model { public static final QueryField CONTENT = field(\\"SqlPrimary\\", \\"content\\"); private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer id; private final @ModelField(targetType=\\"String\\") String content; - private final @ModelField(targetType=\\"SqlRelated\\") @HasMany(associatedWith = \\"primaryId\\", type = SqlRelated.class) List related = null; + private final @ModelField(targetType=\\"SqlRelated\\") @HasMany(associatedWith = \\"primary\\", type = SqlRelated.class) List related = null; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; /** @deprecated This API is internal to Amplify and should not be used. */ @@ -9641,11 +9721,11 @@ public final class SqlRelated implements Model { public static final QueryField ID = field(\\"SqlRelated\\", \\"id\\"); public static final QueryField CONTENT = field(\\"SqlRelated\\", \\"content\\"); public static final QueryField PRIMARY_ID = field(\\"SqlRelated\\", \\"primaryId\\"); - public static final QueryField PRIMARY = field(\\"SqlRelated\\", \\"primaryId\\"); + public static final QueryField PRIMARY = field(\\"SqlRelated\\", \\"sqlPrimaryRelatedId\\"); private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer id; private final @ModelField(targetType=\\"String\\") String content; private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer primaryId; - private final @ModelField(targetType=\\"SqlPrimary\\") @BelongsTo(targetName = \\"primaryId\\", targetNames = {\\"primaryId\\"}, type = SqlPrimary.class) SqlPrimary primary; + private final @ModelField(targetType=\\"SqlPrimary\\") @BelongsTo(targetName = \\"sqlPrimaryRelatedId\\", targetNames = {\\"sqlPrimaryRelatedId\\"}, type = SqlPrimary.class) SqlPrimary primary; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; /** @deprecated This API is internal to Amplify and should not be used. */ @@ -9888,11 +9968,13 @@ import static com.amplifyframework.core.model.query.predicate.QueryField.field; @Index(name = \\"undefined\\", fields = {\\"id\\"}) public final class Primary implements Model { public static final QueryField ID = field(\\"Primary\\", \\"id\\"); + public static final QueryField PRIMARY_RELATED_ONE_ID = field(\\"Primary\\", \\"primaryRelatedOneId\\"); private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; - private final @ModelField(targetType=\\"RelatedMany\\") @HasMany(associatedWith = \\"primaryId\\", type = RelatedMany.class) List relatedMany = null; - private final @ModelField(targetType=\\"RelatedOne\\") @HasOne(associatedWith = \\"primaryId\\", type = RelatedOne.class) RelatedOne relatedOne = null; + private final @ModelField(targetType=\\"RelatedMany\\") @HasMany(associatedWith = \\"primary\\", type = RelatedMany.class) List relatedMany = null; + private final @ModelField(targetType=\\"RelatedOne\\") @HasOne(associatedWith = \\"primary\\", type = RelatedOne.class) RelatedOne relatedOne = null; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + private final @ModelField(targetType=\\"ID\\") String primaryRelatedOneId; /** @deprecated This API is internal to Amplify and should not be used. */ @Deprecated public String resolveIdentifier() { @@ -9919,8 +10001,13 @@ public final class Primary implements Model { return updatedAt; } - private Primary(String id) { + public String getPrimaryRelatedOneId() { + return primaryRelatedOneId; + } + + private Primary(String id, String primaryRelatedOneId) { this.id = id; + this.primaryRelatedOneId = primaryRelatedOneId; } @Override @@ -9933,7 +10020,8 @@ public final class Primary implements Model { Primary primary = (Primary) obj; return ObjectsCompat.equals(getId(), primary.getId()) && ObjectsCompat.equals(getCreatedAt(), primary.getCreatedAt()) && - ObjectsCompat.equals(getUpdatedAt(), primary.getUpdatedAt()); + ObjectsCompat.equals(getUpdatedAt(), primary.getUpdatedAt()) && + ObjectsCompat.equals(getPrimaryRelatedOneId(), primary.getPrimaryRelatedOneId()); } } @@ -9943,6 +10031,7 @@ public final class Primary implements Model { .append(getId()) .append(getCreatedAt()) .append(getUpdatedAt()) + .append(getPrimaryRelatedOneId()) .toString() .hashCode(); } @@ -9953,7 +10042,8 @@ public final class Primary implements Model { .append(\\"Primary {\\") .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") - .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt()) + \\", \\") + .append(\\"primaryRelatedOneId=\\" + String.valueOf(getPrimaryRelatedOneId())) .append(\\"}\\") .toString(); } @@ -9972,27 +10062,32 @@ public final class Primary implements Model { */ public static Primary justId(String id) { return new Primary( - id + id, + null ); } public CopyOfBuilder copyOfBuilder() { - return new CopyOfBuilder(id); + return new CopyOfBuilder(id, + primaryRelatedOneId); } public interface BuildStep { Primary build(); BuildStep id(String id); + BuildStep primaryRelatedOneId(String primaryRelatedOneId); } public static class Builder implements BuildStep { private String id; + private String primaryRelatedOneId; public Builder() { } - private Builder(String id) { + private Builder(String id, String primaryRelatedOneId) { this.id = id; + this.primaryRelatedOneId = primaryRelatedOneId; } @Override @@ -10000,7 +10095,14 @@ public final class Primary implements Model { String id = this.id != null ? this.id : UUID.randomUUID().toString(); return new Primary( - id); + id, + primaryRelatedOneId); + } + + @Override + public BuildStep primaryRelatedOneId(String primaryRelatedOneId) { + this.primaryRelatedOneId = primaryRelatedOneId; + return this; } /** @@ -10015,10 +10117,15 @@ public final class Primary implements Model { public final class CopyOfBuilder extends Builder { - private CopyOfBuilder(String id) { - super(id); + private CopyOfBuilder(String id, String primaryRelatedOneId) { + super(id, primaryRelatedOneId); } + + @Override + public CopyOfBuilder primaryRelatedOneId(String primaryRelatedOneId) { + return (CopyOfBuilder) super.primaryRelatedOneId(primaryRelatedOneId); + } } @@ -10061,10 +10168,10 @@ import static com.amplifyframework.core.model.query.predicate.QueryField.field; public final class RelatedMany implements Model { public static final QueryField ID = field(\\"RelatedMany\\", \\"id\\"); public static final QueryField PRIMARY_ID = field(\\"RelatedMany\\", \\"primaryId\\"); - public static final QueryField PRIMARY = field(\\"RelatedMany\\", \\"primaryId\\"); + public static final QueryField PRIMARY = field(\\"RelatedMany\\", \\"primaryRelatedManyId\\"); private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryId; - private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryId\\", targetNames = {\\"primaryId\\"}, type = Primary.class) Primary primary; + private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryRelatedManyId\\", targetNames = {\\"primaryRelatedManyId\\"}, type = Primary.class) Primary primary; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; /** @deprecated This API is internal to Amplify and should not be used. */ @@ -10282,10 +10389,10 @@ import static com.amplifyframework.core.model.query.predicate.QueryField.field; public final class RelatedOne implements Model { public static final QueryField ID = field(\\"RelatedOne\\", \\"id\\"); public static final QueryField PRIMARY_ID = field(\\"RelatedOne\\", \\"primaryId\\"); - public static final QueryField PRIMARY = field(\\"RelatedOne\\", \\"primaryId\\"); + public static final QueryField PRIMARY = field(\\"RelatedOne\\", \\"relatedOnePrimaryId\\"); private final @ModelField(targetType=\\"ID\\", isRequired = true) String id; private final @ModelField(targetType=\\"ID\\", isRequired = true) String primaryId; - private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"primaryId\\", targetNames = {\\"primaryId\\"}, type = Primary.class) Primary primary; + private final @ModelField(targetType=\\"Primary\\") @BelongsTo(targetName = \\"relatedOnePrimaryId\\", targetNames = {\\"relatedOnePrimaryId\\"}, type = Primary.class) Primary primary; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; /** @deprecated This API is internal to Amplify and should not be used. */ @@ -10503,11 +10610,13 @@ import static com.amplifyframework.core.model.query.predicate.QueryField.field; public final class SqlPrimary implements Model { public static final QueryField ID = field(\\"SqlPrimary\\", \\"id\\"); public static final QueryField CONTENT = field(\\"SqlPrimary\\", \\"content\\"); + public static final QueryField SQL_PRIMARY_RELATED_ID = field(\\"SqlPrimary\\", \\"sqlPrimaryRelatedId\\"); private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer id; private final @ModelField(targetType=\\"String\\") String content; - private final @ModelField(targetType=\\"SqlRelated\\") @HasOne(associatedWith = \\"primaryId\\", type = SqlRelated.class) SqlRelated related = null; + private final @ModelField(targetType=\\"SqlRelated\\") @HasOne(associatedWith = \\"primary\\", type = SqlRelated.class) SqlRelated related = null; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; + private final @ModelField(targetType=\\"Int\\") Integer sqlPrimaryRelatedId; /** @deprecated This API is internal to Amplify and should not be used. */ @Deprecated public Integer resolveIdentifier() { @@ -10534,9 +10643,14 @@ public final class SqlPrimary implements Model { return updatedAt; } - private SqlPrimary(Integer id, String content) { + public Integer getSqlPrimaryRelatedId() { + return sqlPrimaryRelatedId; + } + + private SqlPrimary(Integer id, String content, Integer sqlPrimaryRelatedId) { this.id = id; this.content = content; + this.sqlPrimaryRelatedId = sqlPrimaryRelatedId; } @Override @@ -10550,7 +10664,8 @@ public final class SqlPrimary implements Model { return ObjectsCompat.equals(getId(), sqlPrimary.getId()) && ObjectsCompat.equals(getContent(), sqlPrimary.getContent()) && ObjectsCompat.equals(getCreatedAt(), sqlPrimary.getCreatedAt()) && - ObjectsCompat.equals(getUpdatedAt(), sqlPrimary.getUpdatedAt()); + ObjectsCompat.equals(getUpdatedAt(), sqlPrimary.getUpdatedAt()) && + ObjectsCompat.equals(getSqlPrimaryRelatedId(), sqlPrimary.getSqlPrimaryRelatedId()); } } @@ -10561,6 +10676,7 @@ public final class SqlPrimary implements Model { .append(getContent()) .append(getCreatedAt()) .append(getUpdatedAt()) + .append(getSqlPrimaryRelatedId()) .toString() .hashCode(); } @@ -10572,7 +10688,8 @@ public final class SqlPrimary implements Model { .append(\\"id=\\" + String.valueOf(getId()) + \\", \\") .append(\\"content=\\" + String.valueOf(getContent()) + \\", \\") .append(\\"createdAt=\\" + String.valueOf(getCreatedAt()) + \\", \\") - .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt())) + .append(\\"updatedAt=\\" + String.valueOf(getUpdatedAt()) + \\", \\") + .append(\\"sqlPrimaryRelatedId=\\" + String.valueOf(getSqlPrimaryRelatedId())) .append(\\"}\\") .toString(); } @@ -10592,31 +10709,36 @@ public final class SqlPrimary implements Model { public static SqlPrimary justId(String id) { return new SqlPrimary( id, + null, null ); } public CopyOfBuilder copyOfBuilder() { return new CopyOfBuilder(id, - content); + content, + sqlPrimaryRelatedId); } public interface BuildStep { SqlPrimary build(); BuildStep id(String id); BuildStep content(String content); + BuildStep sqlPrimaryRelatedId(Integer sqlPrimaryRelatedId); } public static class Builder implements BuildStep { private Integer id; private String content; + private Integer sqlPrimaryRelatedId; public Builder() { } - private Builder(Integer id, String content) { + private Builder(Integer id, String content, Integer sqlPrimaryRelatedId) { this.id = id; this.content = content; + this.sqlPrimaryRelatedId = sqlPrimaryRelatedId; } @Override @@ -10625,7 +10747,8 @@ public final class SqlPrimary implements Model { return new SqlPrimary( id, - content); + content, + sqlPrimaryRelatedId); } @Override @@ -10634,6 +10757,12 @@ public final class SqlPrimary implements Model { return this; } + @Override + public BuildStep sqlPrimaryRelatedId(Integer sqlPrimaryRelatedId) { + this.sqlPrimaryRelatedId = sqlPrimaryRelatedId; + return this; + } + /** * @param id id * @return Current Builder instance, for fluent method chaining @@ -10646,8 +10775,8 @@ public final class SqlPrimary implements Model { public final class CopyOfBuilder extends Builder { - private CopyOfBuilder(Integer id, String content) { - super(id, content); + private CopyOfBuilder(Integer id, String content, Integer sqlPrimaryRelatedId) { + super(id, content, sqlPrimaryRelatedId); } @@ -10655,6 +10784,11 @@ public final class SqlPrimary implements Model { public CopyOfBuilder content(String content) { return (CopyOfBuilder) super.content(content); } + + @Override + public CopyOfBuilder sqlPrimaryRelatedId(Integer sqlPrimaryRelatedId) { + return (CopyOfBuilder) super.sqlPrimaryRelatedId(sqlPrimaryRelatedId); + } } @@ -10699,11 +10833,11 @@ public final class SqlRelated implements Model { public static final QueryField ID = field(\\"SqlRelated\\", \\"id\\"); public static final QueryField CONTENT = field(\\"SqlRelated\\", \\"content\\"); public static final QueryField PRIMARY_ID = field(\\"SqlRelated\\", \\"primaryId\\"); - public static final QueryField PRIMARY = field(\\"SqlRelated\\", \\"primaryId\\"); + public static final QueryField PRIMARY = field(\\"SqlRelated\\", \\"sqlRelatedPrimaryId\\"); private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer id; private final @ModelField(targetType=\\"String\\") String content; private final @ModelField(targetType=\\"Int\\", isRequired = true) Integer primaryId; - private final @ModelField(targetType=\\"SqlPrimary\\") @BelongsTo(targetName = \\"primaryId\\", targetNames = {\\"primaryId\\"}, type = SqlPrimary.class) SqlPrimary primary; + private final @ModelField(targetType=\\"SqlPrimary\\") @BelongsTo(targetName = \\"sqlRelatedPrimaryId\\", targetNames = {\\"sqlRelatedPrimaryId\\"}, type = SqlPrimary.class) SqlPrimary primary; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime createdAt; private @ModelField(targetType=\\"AWSDateTime\\", isReadOnly = true) Temporal.DateTime updatedAt; /** @deprecated This API is internal to Amplify and should not be used. */ diff --git a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-swift-visitor.test.ts.snap b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-swift-visitor.test.ts.snap index dfc173c83..6850c06e7 100644 --- a/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-swift-visitor.test.ts.snap +++ b/packages/appsync-modelgen-plugin/src/__tests__/visitors/__snapshots__/appsync-swift-visitor.test.ts.snap @@ -1312,26 +1312,36 @@ public struct Foo: Model { } public var createdAt: Temporal.DateTime? public var updatedAt: Temporal.DateTime? + public var fooBar1Id: String? + public var fooBar2Id: String? public init(id: String = UUID().uuidString, bar1: Bar? = nil, - bar2: Bar? = nil) { + bar2: Bar? = nil, + fooBar1Id: String? = nil, + fooBar2Id: String? = nil) { self.init(id: id, bar1: bar1, bar2: bar2, createdAt: nil, - updatedAt: nil) + updatedAt: nil, + fooBar1Id: fooBar1Id, + fooBar2Id: fooBar2Id) } internal init(id: String = UUID().uuidString, bar1: Bar? = nil, bar2: Bar? = nil, createdAt: Temporal.DateTime? = nil, - updatedAt: Temporal.DateTime? = nil) { + updatedAt: Temporal.DateTime? = nil, + fooBar1Id: String? = nil, + fooBar2Id: String? = nil) { self.id = id self._bar1 = LazyReference(bar1) self._bar2 = LazyReference(bar2) self.createdAt = createdAt self.updatedAt = updatedAt + self.fooBar1Id = fooBar1Id + self.fooBar2Id = fooBar2Id } public mutating func setBar1(_ bar1: Bar? = nil) { self._bar1 = LazyReference(bar1) @@ -1346,6 +1356,8 @@ public struct Foo: Model { _bar2 = try values.decodeIfPresent(LazyReference.self, forKey: .bar2) ?? LazyReference(identifiers: nil) createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + fooBar1Id = try? values.decode(String?.self, forKey: .fooBar1Id) + fooBar2Id = try? values.decode(String?.self, forKey: .fooBar2Id) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) @@ -1354,6 +1366,8 @@ public struct Foo: Model { try container.encode(_bar2, forKey: .bar2) try container.encode(createdAt, forKey: .createdAt) try container.encode(updatedAt, forKey: .updatedAt) + try container.encode(fooBar1Id, forKey: .fooBar1Id) + try container.encode(fooBar2Id, forKey: .fooBar2Id) } }" `; @@ -1371,6 +1385,8 @@ extension Foo { case bar2 case createdAt case updatedAt + case fooBar1Id + case fooBar2Id } public static let keys = CodingKeys.self @@ -1388,10 +1404,12 @@ extension Foo { model.fields( .field(foo.id, is: .required, ofType: .string), - .field(foo.bar1, is: .optional, ofType: .model(Bar.self)), - .field(foo.bar2, is: .optional, ofType: .model(Bar.self)), + .hasOne(foo.bar1, is: .optional, ofType: Bar.self, associatedWith: Bar.keys.foo1, targetNames: [\\"fooBar1Id\\"]), + .hasOne(foo.bar2, is: .optional, ofType: Bar.self, associatedWith: Bar.keys.foo1, targetNames: [\\"fooBar2Id\\"]), .field(foo.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), - .field(foo.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + .field(foo.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(foo.fooBar1Id, is: .optional, ofType: .string), + .field(foo.fooBar2Id, is: .optional, ofType: .string) ) } public class Path: ModelPath { } @@ -1419,6 +1437,12 @@ extension ModelPath where ModelType == Foo { public var updatedAt: FieldPath { datetime(\\"updatedAt\\") } + public var fooBar1Id: FieldPath { + string(\\"fooBar1Id\\") + } + public var fooBar2Id: FieldPath { + string(\\"fooBar2Id\\") + } }" `; @@ -1537,8 +1561,8 @@ extension Bar { .field(bar.id, is: .required, ofType: .string), .field(bar.bar1Id, is: .optional, ofType: .string), .field(bar.bar2Id, is: .optional, ofType: .string), - .belongsTo(bar.foo1, is: .optional, ofType: Foo.self, targetNames: [\\"bar1Id\\"]), - .belongsTo(bar.foo2, is: .optional, ofType: Foo.self, targetNames: [\\"bar2Id\\"]), + .belongsTo(bar.foo1, is: .optional, ofType: Foo.self, targetNames: [\\"barFoo1Id\\"]), + .belongsTo(bar.foo2, is: .optional, ofType: Foo.self, targetNames: [\\"barFoo2Id\\"]), .field(bar.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(bar.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) @@ -1658,7 +1682,7 @@ extension Primary { .field(primary.instanceId, is: .required, ofType: .string), .field(primary.recordId, is: .required, ofType: .string), .field(primary.content, is: .optional, ofType: .string), - .hasMany(primary.related, is: .optional, ofType: Related.self, associatedWith: Related.keys.primaryTenantId), + .hasMany(primary.related, is: .optional, ofType: Related.self, associatedWith: Related.keys.primary), .field(primary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(primary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) @@ -1822,7 +1846,7 @@ extension Related { .field(related.primaryTenantId, is: .required, ofType: .string), .field(related.primaryInstanceId, is: .required, ofType: .string), .field(related.primaryRecordId, is: .required, ofType: .string), - .belongsTo(related.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryTenantId\\", \\"primaryInstanceId\\", \\"primaryRecordId\\"]), + .belongsTo(related.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryRelatedTenantId\\", \\"primaryRelatedInstanceId\\", \\"primaryRelatedRecordId\\"]), .field(related.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(related.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) @@ -1882,19 +1906,22 @@ public struct Primary: Model { } public var createdAt: Temporal.DateTime? public var updatedAt: Temporal.DateTime? + public var primaryRelatedId: String? public init(tenantId: String, instanceId: String, recordId: String, content: String? = nil, - related: Related? = nil) { + related: Related? = nil, + primaryRelatedId: String? = nil) { self.init(tenantId: tenantId, instanceId: instanceId, recordId: recordId, content: content, related: related, createdAt: nil, - updatedAt: nil) + updatedAt: nil, + primaryRelatedId: primaryRelatedId) } internal init(tenantId: String, instanceId: String, @@ -1902,7 +1929,8 @@ public struct Primary: Model { content: String? = nil, related: Related? = nil, createdAt: Temporal.DateTime? = nil, - updatedAt: Temporal.DateTime? = nil) { + updatedAt: Temporal.DateTime? = nil, + primaryRelatedId: String? = nil) { self.tenantId = tenantId self.instanceId = instanceId self.recordId = recordId @@ -1910,6 +1938,7 @@ public struct Primary: Model { self._related = LazyReference(related) self.createdAt = createdAt self.updatedAt = updatedAt + self.primaryRelatedId = primaryRelatedId } public mutating func setRelated(_ related: Related? = nil) { self._related = LazyReference(related) @@ -1923,6 +1952,7 @@ public struct Primary: Model { _related = try values.decodeIfPresent(LazyReference.self, forKey: .related) ?? LazyReference(identifiers: nil) createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + primaryRelatedId = try? values.decode(String?.self, forKey: .primaryRelatedId) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) @@ -1933,6 +1963,7 @@ public struct Primary: Model { try container.encode(_related, forKey: .related) try container.encode(createdAt, forKey: .createdAt) try container.encode(updatedAt, forKey: .updatedAt) + try container.encode(primaryRelatedId, forKey: .primaryRelatedId) } }" `; @@ -1952,6 +1983,7 @@ extension Primary { case related case createdAt case updatedAt + case primaryRelatedId } public static let keys = CodingKeys.self @@ -1973,9 +2005,10 @@ extension Primary { .field(primary.instanceId, is: .required, ofType: .string), .field(primary.recordId, is: .required, ofType: .string), .field(primary.content, is: .optional, ofType: .string), - .field(primary.related, is: .optional, ofType: .model(Related.self)), + .hasOne(primary.related, is: .optional, ofType: Related.self, associatedWith: Related.keys.primary, targetNames: [\\"primaryRelatedId\\"]), .field(primary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), - .field(primary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + .field(primary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(primary.primaryRelatedId, is: .optional, ofType: .string) ) } public class Path: ModelPath { } @@ -2017,6 +2050,9 @@ extension ModelPath where ModelType == Primary { public var updatedAt: FieldPath { datetime(\\"updatedAt\\") } + public var primaryRelatedId: FieldPath { + string(\\"primaryRelatedId\\") + } }" `; @@ -2137,7 +2173,7 @@ extension Related { .field(related.primaryTenantId, is: .required, ofType: .string), .field(related.primaryInstanceId, is: .required, ofType: .string), .field(related.primaryRecordId, is: .required, ofType: .string), - .belongsTo(related.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryTenantId\\", \\"primaryInstanceId\\", \\"primaryRecordId\\"]), + .belongsTo(related.primary, is: .optional, ofType: Primary.self, targetNames: [\\"relatedPrimaryTenantId\\", \\"relatedPrimaryInstanceId\\", \\"relatedPrimaryRecordId\\"]), .field(related.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(related.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) @@ -2246,7 +2282,7 @@ extension SqlPrimary { model.fields( .field(sqlPrimary.id, is: .required, ofType: .int), .field(sqlPrimary.content, is: .optional, ofType: .string), - .hasMany(sqlPrimary.related, is: .optional, ofType: SqlRelated.self, associatedWith: SqlRelated.keys.primaryId), + .hasMany(sqlPrimary.related, is: .optional, ofType: SqlRelated.self, associatedWith: SqlRelated.keys.primary), .field(sqlPrimary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(sqlPrimary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) @@ -2380,7 +2416,7 @@ extension SqlRelated { .field(sqlRelated.id, is: .required, ofType: .int), .field(sqlRelated.content, is: .optional, ofType: .string), .field(sqlRelated.primaryId, is: .required, ofType: .int), - .belongsTo(sqlRelated.primary, is: .optional, ofType: SqlPrimary.self, targetNames: [\\"primaryId\\"]), + .belongsTo(sqlRelated.primary, is: .optional, ofType: SqlPrimary.self, targetNames: [\\"sqlPrimaryRelatedId\\"]), .field(sqlRelated.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(sqlRelated.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) @@ -2432,26 +2468,31 @@ public struct Primary: Model { } public var createdAt: Temporal.DateTime? public var updatedAt: Temporal.DateTime? + public var primaryRelatedOneId: String? public init(id: String = UUID().uuidString, relatedMany: List? = [], - relatedOne: RelatedOne? = nil) { + relatedOne: RelatedOne? = nil, + primaryRelatedOneId: String? = nil) { self.init(id: id, relatedMany: relatedMany, relatedOne: relatedOne, createdAt: nil, - updatedAt: nil) + updatedAt: nil, + primaryRelatedOneId: primaryRelatedOneId) } internal init(id: String = UUID().uuidString, relatedMany: List? = [], relatedOne: RelatedOne? = nil, createdAt: Temporal.DateTime? = nil, - updatedAt: Temporal.DateTime? = nil) { + updatedAt: Temporal.DateTime? = nil, + primaryRelatedOneId: String? = nil) { self.id = id self.relatedMany = relatedMany self._relatedOne = LazyReference(relatedOne) self.createdAt = createdAt self.updatedAt = updatedAt + self.primaryRelatedOneId = primaryRelatedOneId } public mutating func setRelatedOne(_ relatedOne: RelatedOne? = nil) { self._relatedOne = LazyReference(relatedOne) @@ -2463,6 +2504,7 @@ public struct Primary: Model { _relatedOne = try values.decodeIfPresent(LazyReference.self, forKey: .relatedOne) ?? LazyReference(identifiers: nil) createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + primaryRelatedOneId = try? values.decode(String?.self, forKey: .primaryRelatedOneId) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) @@ -2471,6 +2513,7 @@ public struct Primary: Model { try container.encode(_relatedOne, forKey: .relatedOne) try container.encode(createdAt, forKey: .createdAt) try container.encode(updatedAt, forKey: .updatedAt) + try container.encode(primaryRelatedOneId, forKey: .primaryRelatedOneId) } }" `; @@ -2488,6 +2531,7 @@ extension Primary { case relatedOne case createdAt case updatedAt + case primaryRelatedOneId } public static let keys = CodingKeys.self @@ -2506,10 +2550,11 @@ extension Primary { model.fields( .field(primary.id, is: .required, ofType: .string), - .hasMany(primary.relatedMany, is: .optional, ofType: RelatedMany.self, associatedWith: RelatedMany.keys.primaryId), - .field(primary.relatedOne, is: .optional, ofType: .model(RelatedOne.self)), + .hasMany(primary.relatedMany, is: .optional, ofType: RelatedMany.self, associatedWith: RelatedMany.keys.primary), + .hasOne(primary.relatedOne, is: .optional, ofType: RelatedOne.self, associatedWith: RelatedOne.keys.primary, targetNames: [\\"primaryRelatedOneId\\"]), .field(primary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), - .field(primary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + .field(primary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(primary.primaryRelatedOneId, is: .optional, ofType: .string) ) } public class Path: ModelPath { } @@ -2537,6 +2582,9 @@ extension ModelPath where ModelType == Primary { public var updatedAt: FieldPath { datetime(\\"updatedAt\\") } + public var primaryRelatedOneId: FieldPath { + string(\\"primaryRelatedOneId\\") + } }" `; @@ -2631,7 +2679,7 @@ extension RelatedMany { model.fields( .field(relatedMany.id, is: .required, ofType: .string), .field(relatedMany.primaryId, is: .required, ofType: .string), - .belongsTo(relatedMany.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryId\\"]), + .belongsTo(relatedMany.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryRelatedManyId\\"]), .field(relatedMany.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(relatedMany.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) @@ -2755,7 +2803,7 @@ extension RelatedOne { model.fields( .field(relatedOne.id, is: .required, ofType: .string), .field(relatedOne.primaryId, is: .required, ofType: .string), - .belongsTo(relatedOne.primary, is: .optional, ofType: Primary.self, targetNames: [\\"primaryId\\"]), + .belongsTo(relatedOne.primary, is: .optional, ofType: Primary.self, targetNames: [\\"relatedOnePrimaryId\\"]), .field(relatedOne.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(relatedOne.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) @@ -2804,26 +2852,31 @@ public struct SqlPrimary: Model { } public var createdAt: Temporal.DateTime? public var updatedAt: Temporal.DateTime? + public var sqlPrimaryRelatedId: Int? public init(id: Int = UUID().uuidString, content: String? = nil, - related: SqlRelated? = nil) { + related: SqlRelated? = nil, + sqlPrimaryRelatedId: Int? = nil) { self.init(id: id, content: content, related: related, createdAt: nil, - updatedAt: nil) + updatedAt: nil, + sqlPrimaryRelatedId: sqlPrimaryRelatedId) } internal init(id: Int = UUID().uuidString, content: String? = nil, related: SqlRelated? = nil, createdAt: Temporal.DateTime? = nil, - updatedAt: Temporal.DateTime? = nil) { + updatedAt: Temporal.DateTime? = nil, + sqlPrimaryRelatedId: Int? = nil) { self.id = id self.content = content self._related = LazyReference(related) self.createdAt = createdAt self.updatedAt = updatedAt + self.sqlPrimaryRelatedId = sqlPrimaryRelatedId } public mutating func setRelated(_ related: SqlRelated? = nil) { self._related = LazyReference(related) @@ -2835,6 +2888,7 @@ public struct SqlPrimary: Model { _related = try values.decodeIfPresent(LazyReference.self, forKey: .related) ?? LazyReference(identifiers: nil) createdAt = try? values.decode(Temporal.DateTime?.self, forKey: .createdAt) updatedAt = try? values.decode(Temporal.DateTime?.self, forKey: .updatedAt) + sqlPrimaryRelatedId = try? values.decode(Int?.self, forKey: .sqlPrimaryRelatedId) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) @@ -2843,6 +2897,7 @@ public struct SqlPrimary: Model { try container.encode(_related, forKey: .related) try container.encode(createdAt, forKey: .createdAt) try container.encode(updatedAt, forKey: .updatedAt) + try container.encode(sqlPrimaryRelatedId, forKey: .sqlPrimaryRelatedId) } }" `; @@ -2860,6 +2915,7 @@ extension SqlPrimary { case related case createdAt case updatedAt + case sqlPrimaryRelatedId } public static let keys = CodingKeys.self @@ -2879,9 +2935,10 @@ extension SqlPrimary { model.fields( .field(sqlPrimary.id, is: .required, ofType: .int), .field(sqlPrimary.content, is: .optional, ofType: .string), - .field(sqlPrimary.related, is: .optional, ofType: .model(SqlRelated.self)), + .hasOne(sqlPrimary.related, is: .optional, ofType: SqlRelated.self, associatedWith: SqlRelated.keys.primary, targetNames: [\\"sqlPrimaryRelatedId\\"]), .field(sqlPrimary.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), - .field(sqlPrimary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) + .field(sqlPrimary.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime), + .field(sqlPrimary.sqlPrimaryRelatedId, is: .optional, ofType: .int) ) } public class Path: ModelPath { } @@ -2909,6 +2966,9 @@ extension ModelPath where ModelType == SqlPrimary { public var updatedAt: FieldPath { datetime(\\"updatedAt\\") } + public var sqlPrimaryRelatedId: FieldPath { + int(\\"sqlPrimaryRelatedId\\") + } }" `; @@ -3013,7 +3073,7 @@ extension SqlRelated { .field(sqlRelated.id, is: .required, ofType: .int), .field(sqlRelated.content, is: .optional, ofType: .string), .field(sqlRelated.primaryId, is: .required, ofType: .int), - .belongsTo(sqlRelated.primary, is: .optional, ofType: SqlPrimary.self, targetNames: [\\"primaryId\\"]), + .belongsTo(sqlRelated.primary, is: .optional, ofType: SqlPrimary.self, targetNames: [\\"sqlRelatedPrimaryId\\"]), .field(sqlRelated.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime), .field(sqlRelated.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime) ) diff --git a/packages/appsync-modelgen-plugin/src/utils/process-belongs-to.ts b/packages/appsync-modelgen-plugin/src/utils/process-belongs-to.ts index 76cf7623a..7a1377399 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-belongs-to.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-belongs-to.ts @@ -15,6 +15,7 @@ export function processBelongsToConnection( modelMap: CodeGenModelMap, connectionDirective: CodeGenDirective, isCustomPKEnabled: boolean = false, + respectReferences: boolean = false, // remove when enabled references for all targets ): CodeGenFieldConnection | undefined { if (field.isList) { throw new Error( @@ -28,7 +29,7 @@ export function processBelongsToConnection( `A 'belongsTo' field should match to a corresponding 'hasMany' or 'hasOne' field` ); } - const otherSideField = isCustomPKEnabled ? otherSideConnectedFields[0] : getConnectedFieldV2(field, model, otherSide, connectionDirective.name); + const otherSideField = isCustomPKEnabled ? otherSideConnectedFields[0] : getConnectedFieldV2(field, model, otherSide, connectionDirective.name, false, respectReferences); const connectionFields = connectionDirective.arguments.fields || []; const references = connectionDirective.arguments.references || []; @@ -41,9 +42,9 @@ export function processBelongsToConnection( // but if the field are connected using fields argument in connection directive // we are reusing the field and it should be preserved in selection set const otherSideHasMany = otherSideField.isList; - const isUsingReferences = references.length > 0; + const isUsingReferences = respectReferences && references.length > 0; // New metada type introduced by custom PK v2 support - let targetNames: string[] = [ ...connectionFields, ...references ]; + let targetNames = isUsingReferences ? [ ...connectionFields, ...references ] : [ ...connectionFields ]; if (targetNames.length === 0) { if (otherSideHasMany) { targetNames = isCustomPKEnabled diff --git a/packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts b/packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts index 851f541e3..054955af2 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts @@ -13,7 +13,8 @@ export function getConnectedFieldV2( model: CodeGenModel, connectedModel: CodeGenModel, directiveName: string, - shouldUseModelNameFieldInHasManyAndBelongsTo: boolean = false + shouldUseModelNameFieldInHasManyAndBelongsTo: boolean = false, + respectReferences: boolean = false, ): CodeGenField { const connectionInfo = getDirective(field)(directiveName); if (!connectionInfo) { @@ -23,7 +24,7 @@ export function getConnectedFieldV2( const references = connectionInfo.arguments.references; if (connectionInfo.name === 'belongsTo') { let connectedFieldsBelongsTo = getBelongsToConnectedFields(model, connectedModel); - if (references) { + if (respectReferences && references) { const connectedField = connectedFieldsBelongsTo.find((field) => { return field.directives.some((dir) => { return (dir.name === 'hasOne' || dir.name === 'hasMany') @@ -49,7 +50,7 @@ export function getConnectedFieldV2( } if (references || connectionFields || directiveName === 'hasOne') { let connectionDirective; - if (references) { + if (respectReferences && references) { if (connectionInfo) { connectionDirective = flattenFieldDirectives(connectedModel).find((dir) => { return dir.arguments.references @@ -161,17 +162,18 @@ export function processConnectionsV2( shouldUseModelNameFieldInHasManyAndBelongsTo: boolean = false, isCustomPKEnabled: boolean = false, shouldUseFieldsInAssociatedWithInHasOne: boolean = false, + respectReferences: boolean = false, // remove when enabled references for all targets ): CodeGenFieldConnection | undefined { const connectionDirective = field.directives.find(d => d.name === 'hasOne' || d.name === 'hasMany' || d.name === 'belongsTo'); if (connectionDirective) { switch (connectionDirective.name) { case 'hasOne': - return processHasOneConnection(field, model, modelMap, connectionDirective, isCustomPKEnabled, shouldUseFieldsInAssociatedWithInHasOne); + return processHasOneConnection(field, model, modelMap, connectionDirective, isCustomPKEnabled, shouldUseFieldsInAssociatedWithInHasOne, respectReferences); case 'belongsTo': - return processBelongsToConnection(field, model, modelMap, connectionDirective, isCustomPKEnabled); + return processBelongsToConnection(field, model, modelMap, connectionDirective, isCustomPKEnabled, respectReferences); case 'hasMany': - return processHasManyConnection(field, model, modelMap, connectionDirective, shouldUseModelNameFieldInHasManyAndBelongsTo, isCustomPKEnabled); + return processHasManyConnection(field, model, modelMap, connectionDirective, shouldUseModelNameFieldInHasManyAndBelongsTo, isCustomPKEnabled, respectReferences); default: break; } diff --git a/packages/appsync-modelgen-plugin/src/utils/process-has-many.ts b/packages/appsync-modelgen-plugin/src/utils/process-has-many.ts index 2d0c6427c..3f0f41bb6 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-has-many.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-has-many.ts @@ -19,6 +19,7 @@ export function processHasManyConnection( connectionDirective: CodeGenDirective, shouldUseModelNameFieldInHasManyAndBelongsTo: boolean, isCustomPKEnabled: boolean = false, + respectReferences: boolean = false, // remove when enabled references for all targets ): CodeGenFieldConnection | undefined { if (!field.isList) { throw new Error("A field with hasMany must be a list type"); @@ -31,9 +32,9 @@ export function processHasManyConnection( throw new Error(fieldsAndReferencesErrorMessage); } - if (references.length > 0) { + if (respectReferences && references.length > 0) { // ensure there is a matching belongsTo field with references - getConnectedFieldV2(field, model, otherSide, connectionDirective.name, shouldUseModelNameFieldInHasManyAndBelongsTo) + getConnectedFieldV2(field, model, otherSide, connectionDirective.name, shouldUseModelNameFieldInHasManyAndBelongsTo, respectReferences) const associatedWithFields = references.map((reference: string) => otherSide.fields.find((field) => reference === field.name)) return { kind: CodeGenConnectionType.HAS_MANY, @@ -46,7 +47,7 @@ export function processHasManyConnection( const otherSideFields = isCustomPKEnabled ? getConnectedFieldsForHasMany(field, model, otherSide, shouldUseModelNameFieldInHasManyAndBelongsTo) - : [getConnectedFieldV2(field, model, otherSide, connectionDirective.name, shouldUseModelNameFieldInHasManyAndBelongsTo)]; + : [getConnectedFieldV2(field, model, otherSide, connectionDirective.name, shouldUseModelNameFieldInHasManyAndBelongsTo, respectReferences)]; const otherSideField = otherSideFields[0]; // if a type is connected using name, then graphql-connection-transformer adds a field to diff --git a/packages/appsync-modelgen-plugin/src/utils/process-has-one.ts b/packages/appsync-modelgen-plugin/src/utils/process-has-one.ts index 23f57a768..8de63914c 100644 --- a/packages/appsync-modelgen-plugin/src/utils/process-has-one.ts +++ b/packages/appsync-modelgen-plugin/src/utils/process-has-one.ts @@ -14,7 +14,8 @@ export function processHasOneConnection( modelMap: CodeGenModelMap, connectionDirective: CodeGenDirective, isCustomPKEnabled: boolean = false, - shouldUseFieldsInAssociatedWithInHasOne:boolean = false + shouldUseFieldsInAssociatedWithInHasOne:boolean = false, + respectReferences: boolean = false, // remove when enabled references for all targets ): CodeGenFieldConnection | undefined { const otherSide = modelMap[field.type]; // Find other side belongsTo field when in bi direction connection @@ -31,9 +32,9 @@ export function processHasOneConnection( } let associatedWithFields; - if (references.length > 0) { + if (respectReferences && references.length > 0) { // ensure there is a matching belongsTo field with references - getConnectedFieldV2(field, model, otherSide, connectionDirective.name); + getConnectedFieldV2(field, model, otherSide, connectionDirective.name, false, respectReferences); associatedWithFields = references.map((reference: string) => otherSide.fields.find((field) => reference === field.name)) return { kind: CodeGenConnectionType.HAS_ONE, @@ -45,7 +46,7 @@ export function processHasOneConnection( } else if (isCustomPKEnabled) { associatedWithFields = getConnectedFieldsForHasOne(otherSideBelongsToField, otherSide, shouldUseFieldsInAssociatedWithInHasOne); } else { - const otherSideField = getConnectedFieldV2(field, model, otherSide, connectionDirective.name); + const otherSideField = getConnectedFieldV2(field, model, otherSide, connectionDirective.name, false, respectReferences); associatedWithFields = [otherSideField]; } diff --git a/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts b/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts index 3d0f626ca..e8a611384 100644 --- a/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts +++ b/packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts @@ -1087,7 +1087,8 @@ export class AppSyncModelVisitor< this.modelMap, shouldUseModelNameFieldInHasManyAndBelongsTo, isCustomPKEnabled, - shouldUseFieldsInAssociatedWithInHasOne + shouldUseFieldsInAssociatedWithInHasOne, + this.config.target === 'introspection', ); if (connectionInfo) { if (connectionInfo.kind === CodeGenConnectionType.HAS_MANY) { @@ -1181,8 +1182,7 @@ export class AppSyncModelVisitor< connectionInfo.kind !== CodeGenConnectionType.HAS_MANY && connectionInfo.kind !== CodeGenConnectionType.HAS_ONE && connectionInfo.targetNames && - connectionInfo.targetName !== 'id' && - !connectionInfo.isUsingReferences + connectionInfo.targetName !== 'id' ) { // Need to remove the field that is targetName connectionInfo.targetNames.forEach(targetName => removeFieldFromModel(model, targetName));