Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

chore: release changes needed to support Gen2 CLI #826

Merged
merged 22 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f51b5d3
feat: enable codegen to run in browser (#789)
dpilch Mar 27, 2024
ba4a712
chore: add explainer for model introspection schema relationships (#806)
palpatim Apr 9, 2024
849e842
Merge branch 'feature/gen2-release' into main-to-gen2
dpilch Apr 10, 2024
453baf7
Merge pull request #808 from aws-amplify/main-to-gen2
dpilch Apr 10, 2024
e948a3c
build(deps): bump tar from 6.2.0 to 6.2.1
dependabot[bot] Apr 11, 2024
a6efa72
feat: set correct association with references (#793)
dpilch Apr 11, 2024
a9e6cbd
Merge pull request #810 from aws-amplify/dependabot/npm_and_yarn/tar-…
dpilch Apr 11, 2024
9f55941
fix: use standalone ajv validation for model introspection schema (#807)
AaronZyLee Apr 12, 2024
61e0f8f
Merge branch 'main' into merge-main-gen2
AaronZyLee Apr 17, 2024
02a581f
fix: missing targetNames in hasOne reference
AaronZyLee Apr 17, 2024
dd31e18
Merge pull request #812 from aws-amplify/merge-main-gen2
AaronZyLee Apr 17, 2024
de394dd
fix: do not remove belongsTo target names when using references (#814)
dpilch Apr 19, 2024
854bfea
fix!: use transformer version 2 by default (#813)
dpilch Apr 22, 2024
f83eba1
feat: dart api model .fromJson() refactor (#593)
Equartey Apr 23, 2024
8ffacc3
Merge pull request #817 from aws-amplify/main
dpilch Apr 23, 2024
f217f56
style(amplify-codegen): adds a todo comment (#820)
Equartey Apr 24, 2024
20c7b92
test: update snapshots (#819)
dpilch Apr 25, 2024
e1b2035
build: fix schema generation (#821)
dpilch Apr 25, 2024
e7320a9
fix: return reference behavior to main for all but introspection (#824)
dpilch Apr 25, 2024
62012b5
Merge pull request #825 from aws-amplify/feature/gen2-release
dpilch Apr 25, 2024
aef1f63
style(amplify-codegen): added lint ignore to support Amplify Flutter …
Equartey Apr 25, 2024
22f1425
test: update dart snapshots (#828)
dpilch Apr 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .codebuild/e2e_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,25 +145,25 @@ batch:
depend-on:
- publish_to_local_registry
- identifier: >-
l_build_app_ts_push_codegen_admin_modelgen_uninitialized_project_codegen_js_uninitialized_project_modelgen_android
l_build_app_ts_graphql_generator_app_push_codegen_admin_modelgen_uninitialized_project_codegen_js
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: >-
src/__tests__/build-app-ts.test.ts|src/__tests__/push-codegen-admin-modelgen.test.ts|src/__tests__/uninitialized-project-codegen-js.test.ts|src/__tests__/uninitialized-project-modelgen-android.test.ts
src/__tests__/build-app-ts.test.ts|src/__tests__/graphql-generator-app.test.ts|src/__tests__/push-codegen-admin-modelgen.test.ts|src/__tests__/uninitialized-project-codegen-js.test.ts
CLI_REGION: ap-southeast-1
DISABLE_ESLINT_PLUGIN: true
depend-on:
- publish_to_local_registry
- identifier: >-
l_uninitialized_project_modelgen_flutter_uninitialized_project_modelgen_ios_uninitialized_project_modelgen_js
l_uninitialized_project_modelgen_android_uninitialized_project_modelgen_flutter_uninitialized_project_modelgen_ios_uninitialize
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: >-
src/__tests__/uninitialized-project-modelgen-flutter.test.ts|src/__tests__/uninitialized-project-modelgen-ios.test.ts|src/__tests__/uninitialized-project-modelgen-js.test.ts
src/__tests__/uninitialized-project-modelgen-android.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
Expand Down Expand Up @@ -252,30 +252,30 @@ batch:
- publish_to_local_registry
- build_windows
- identifier: >-
w_build_app_ts_push_codegen_admin_modelgen_uninitialized_project_codegen_js_uninitialized_project_modelgen_android
w_build_app_ts_graphql_generator_app_push_codegen_admin_modelgen_uninitialized_project_codegen_js
buildspec: .codebuild/run_e2e_tests_windows.yml
env:
compute-type: BUILD_GENERAL1_LARGE
image: $WINDOWS_IMAGE_2019
type: WINDOWS_SERVER_2019_CONTAINER
variables:
TEST_SUITE: >-
src/__tests__/build-app-ts.test.ts|src/__tests__/push-codegen-admin-modelgen.test.ts|src/__tests__/uninitialized-project-codegen-js.test.ts|src/__tests__/uninitialized-project-modelgen-android.test.ts
src/__tests__/build-app-ts.test.ts|src/__tests__/graphql-generator-app.test.ts|src/__tests__/push-codegen-admin-modelgen.test.ts|src/__tests__/uninitialized-project-codegen-js.test.ts
CLI_REGION: us-east-1
DISABLE_ESLINT_PLUGIN: true
depend-on:
- publish_to_local_registry
- build_windows
- identifier: >-
w_uninitialized_project_modelgen_flutter_uninitialized_project_modelgen_ios_uninitialized_project_modelgen_js
w_uninitialized_project_modelgen_android_uninitialized_project_modelgen_flutter_uninitialized_project_modelgen_ios_uninitialize
buildspec: .codebuild/run_e2e_tests_windows.yml
env:
compute-type: BUILD_GENERAL1_LARGE
image: $WINDOWS_IMAGE_2019
type: WINDOWS_SERVER_2019_CONTAINER
variables:
TEST_SUITE: >-
src/__tests__/uninitialized-project-modelgen-flutter.test.ts|src/__tests__/uninitialized-project-modelgen-ios.test.ts|src/__tests__/uninitialized-project-modelgen-js.test.ts
src/__tests__/uninitialized-project-modelgen-android.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
Expand Down
5 changes: 4 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ module.exports = {
'/packages/*/CHANGELOG.md',

// Ignore lint in e2e test apps
'test-apps'
'test-apps',

// Ignore lint for standalone JSON validation function
'/packages/appsync-modelgen-plugin/src/validate-cjs.js'
]
};
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"eslint.packageManager": "yarn",
"eslint.quiet": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"jest.enableInlineErrorMessages": true,
"jest.showCoverageOnLoad": true,
Expand Down
262 changes: 262 additions & 0 deletions README-relationships.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
# Modeling relationships in the introspection schema

## Background

The Model Introspection Schema (MIS) is an intermediate representation of the GraphQL model that includes Amplify annotations. It is different
from the standard [GraphQL introspection schema](https://graphql.org/learn/introspection/) in that it includes relationship information, not
just type information.

> **NOTE:** The MIS is an internal implementation detail of the Amplify API plugin. It should not be used in a customer application.

## Sample

Given a schema like

```graphql
type Primary @model @auth(rules: [{ allow: public, operations: [read] }, { allow: owner }]) {
id: ID! @primaryKey
relatedMany: [RelatedMany] @hasMany(references: "primaryId")
relatedOne: RelatedOne @hasOne(references: "primaryId")
}

type RelatedMany @model @auth(rules: [{ allow: public, operations: [read] }, { allow: owner }]) {
id: ID! @primaryKey
primaryId: ID!
primary: Primary @belongsTo(references: "primaryId")
}

type RelatedOne @model @auth(rules: [{ allow: public, operations: [read] }, { allow: owner }]) {
id: ID! @primaryKey
primaryId: ID!
primary: Primary @belongsTo(references: "primaryId")
}
```

the MIS (abridged to show relationship information only) looks like:

```json
{
"version": 1,
"models": {
"Primary": {
"name": "Primary",
"fields": {
"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"],
}
}
}
},
"RelatedMany": {
"name": "RelatedMany",
"fields": {
"primary": {
"name": "primary",
"isArray": false,
"type": {
"model": "Primary"
},
"isRequired": false,
"attributes": [],
"association": {
"connectionType": "BELONGS_TO",
"targetNames": ["primaryId"]
}
},
"primaryId": {
"name": "primaryId",
"isArray": false,
"type": "ID",
"isRequired": false,
"attributes": []
}
}
},
"RelatedOne": {
"name": "RelatedOne",
"fields": {
"primary": {
"name": "primary",
"isArray": false,
"type": {
"model": "Primary"
},
"isRequired": false,
"attributes": [],
"association": {
"connectionType": "BELONGS_TO",
"targetNames": ["primaryId"]
}
},
"primaryId": {
"name": "primaryId",
"isArray": false,
"type": "ID",
"isRequired": false,
"attributes": []
}
}
}
}
}
```

## Glossary

* **Associated type** - In a field decorated with a `@hasMany`, `@hasOne`, or `@belongsTo` directive, the model “pointed to” by the directive. In the sample schema:
* `Related` is the **associated type** for the `@hasMany` directive on `Primary.related`
* `Primary` is the **associated type** for the `@belongsTo` directive on `Related.primary`
* **Association field** - See **Connection field**
* **Connection field** - In any model type, the field that is decorated with a `@hasMany`, `@hasOne`, or `@belongsTo` directive. In the sample schema:
* `Primary.related` is the **connection field** in the `Primary` model, for the relationship `Primary -> Related` defined by the `@hasMany` on `Primary.related` and the `@belongsTo` on `Related.primary`
* `Related.primary` is the **connection field** in the `Related` model, for the relationship `Primary -> Related` defined by the `@hasMany` on `Primary.related` and the `@belongsTo` on `Related.primary`
* **Source type** - In a field decorated with a `@hasMany`, `@hasOne`, or `@belongsTo` directive, the model containing the directive. In the sample schema:
* `Primary` is the **source type** for the `@hasMany` directive on `Primary.related`
* `Related` is the **source type** for the `@belongsTo` directive on `Related.primary`

## Structure

Relationships are modeled in an `association` structure in the MIS. The `association` attribute must belong to a `@model` field, not a field of non-model type, enum, input, or custom query/mutation.

Here are the relevant types to define the association structure. Note that this is a simplified rendition of the JSON/JavaScript version of the MIS. Other platforms may represent the MIS differently. The full definition is in [source code](./appsync-modelgen-plugin/src/utils/process-connections.ts);

```ts
enum CodeGenConnectionType {
HAS_ONE = 'HAS_ONE',
BELONGS_TO = 'BELONGS_TO',
HAS_MANY = 'HAS_MANY',
}

type CodeGenConnectionTypeBase = {
kind: CodeGenConnectionType;
connectedModel: CodeGenModel;
// ^-- Type not shown
};

type CodeGenFieldConnectionBelongsTo = CodeGenConnectionTypeBase & {
kind: CodeGenConnectionType.BELONGS_TO;
targetNames: string[];
}

type CodeGenFieldConnectionHasOne = CodeGenConnectionTypeBase & {
kind: CodeGenConnectionType.HAS_ONE;
associatedWith: CodeGenField[];
// ^-- Type not shown -- rendered in MIS as a string array
targetNames: string[];
}

export type CodeGenFieldConnectionHasMany = CodeGenConnectionTypeBase & {
kind: CodeGenConnectionType.HAS_MANY;
associatedWith: CodeGenField[];
// ^-- Type not shown -- rendered in MIS as a string array
}
```

Considering a snippet of the above sample:

```json
"models": {
"Primary": {
"name": "Primary",
"fields": {
"relatedMany": {
"name": "relatedMany",
"isArray": true,
"type": {
"model": "RelatedMany"
},
"isRequired": false,
"attributes": [],
"isArrayNullable": true,
"association": {
"connectionType": "HAS_MANY",
"associatedWith": ["primaryId"]
}
},
...
"RelatedMany": {
"name": "RelatedMany",
"fields": {
"primary": {
"name": "primary",
"isArray": false,
"type": {
"model": "Primary"
},
"isRequired": false,
"attributes": [],
"association": {
"connectionType": "BELONGS_TO",
"targetNames": ["primaryId"]
}
},
"primaryId": {
"name": "primaryId",
"isArray": false,
"type": "ID",
"isRequired": false,
"attributes": []
}
```

- `models.Primary` - A type definition. The **source type** for any `association`s defined in this model.
- `models.Primary.fields.relatedMany` - The **association field**/**connection field**
- `models.Primary.fields.relatedMany.type` - The **associated type** for this relationship. This must be a `@model`.
- `models.Primary.fields.relatedMany.association` - The structure containing the data needed to navigate the relationship with the associated type
- `models.Primary.fields.relatedMany.association.connectionType` - The kind of relationship (has one, has many, belongs to) this **source type** has with the associated type
- `models.Primary.fields.relatedMany.association.associatedWith` - A list of fields on the **associated type** that hold the primary key of the **source** record. This is an array so we can support composite primary keys.
- `models.RelatedMany` - A type definition. The **source type** for any `association`s defined in this model.
- `models.RelatedMany.fields.primary.association.targetNames` - A list of fields on the **source type** (that is, the current type) that hold the primary key of the **associated** record. This is an array so we can support composite primary keys.
- `models.RelatedMany.fields.primaryId` - The field pointed to by `targetNames` above, containing the primary key of the **associated** record for the `RelatedOne.primary` relationship.


## Navigating relationships

We will describe the steps to resolve the record in pseudo-sql

### From source record to associated record

* If the source model has an `associatedWith` but no `targetNames`:
```
SELECT *
FROM <associated type>
WHERE <associatedWith fields> = <source type>.primaryKey
```
* If the source model has an `associatedWith` AND `targetNames`:
```
SELECT *
FROM <associated type>
WHERE <associatedWith fields> = <source type>.<targetNames fields>
```
* If the source model has a `targetNames` but no `associatedWith`:
```
SELECT *
FROM <associated type>
WHERE <source type>.<targetNames fields> = <associated type>.primaryKey
```



Original file line number Diff line number Diff line change
@@ -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 });
});
});
Original file line number Diff line number Diff line change
@@ -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*
Loading
Loading