aws-amplify / amplify-category-api

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of GraphQL and REST based backends for your amplify project.
https://docs.amplify.aws/
Apache License 2.0
89 stars 79 forks source link

Type RDSModelSchema is not assignable to type GenericModelSchema #2934

Open chrisl777 opened 1 month ago

chrisl777 commented 1 month ago

Environment information

System:
  OS: macOS 14.5
  CPU: (14) arm64 Apple M3 Max
  Memory: 220.56 MB / 36.00 GB
  Shell: /bin/zsh
Binaries:
  Node: 18.18.0 - ~/.asdf/installs/nodejs/18.18.0/bin/node
  Yarn: 1.22.22 - ~/.asdf/installs/nodejs/18.18.0/bin/yarn
  npm: 9.8.1 - ~/.asdf/plugins/nodejs/shims/npm
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/auth-construct: 1.3.1
  @aws-amplify/backend: 1.3.2
  @aws-amplify/backend-auth: 1.2.0
  @aws-amplify/backend-cli: 1.2.9
  @aws-amplify/backend-data: 1.1.4
  @aws-amplify/backend-deployer: 1.1.4
  @aws-amplify/backend-function: 1.5.0
  @aws-amplify/backend-output-schemas: 1.2.0
  @aws-amplify/backend-output-storage: 1.1.2
  @aws-amplify/backend-secret: 1.1.3
  @aws-amplify/backend-storage: 1.2.1
  @aws-amplify/cli-core: 1.1.3
  @aws-amplify/client-config: 1.4.0
  @aws-amplify/deployed-backend-client: 1.4.1
  @aws-amplify/form-generator: 1.0.3
  @aws-amplify/model-generator: 1.0.8
  @aws-amplify/platform-core: 1.1.0
  @aws-amplify/plugin-types: 1.3.0
  @aws-amplify/sandbox: 1.2.2
  @aws-amplify/schema-generator: 1.2.4
  aws-amplify: 6.6.2
  aws-cdk: 2.161.1
  aws-cdk-lib: 2.161.1
  typescript: 5.3.3
AWS environment variables:
  AWS_STS_REGIONAL_ENDPOINTS = regional
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
No CDK environment variables

Describe the bug

I'm following the directions on connecting to existing data sources:

https://docs.amplify.aws/react-native/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/

In my case, I'm connecting to a Postgres database (third-party, not RDS).

import { type ClientSchema, a, defineData  } from '@aws-amplify/backend';
import { schema as generatedSqlSchema } from './schema.sql';
import { venuesLambda } from '../functions/venue-api-function/resource';

const sqlSchema = generatedSqlSchema.setAuthorization((models) => [
  models.locations
    .authorization(allow => [
      allow.guest().to(["read"])
    ]),
])

const schema = a.schema({
  Venue: a.model({
    externalId: a.id(), 
    venuePayInfo: a.hasOne("VenuePayInfo", "venueId"),

    // Redacted 
    // ...
  })
  .authorization(allow => [
    allow.group('Admin')
  ]),

  VenuePayInfo: a.model({

    // Venue relationship: 
    venueId: a.id(),
    venue: a.belongsTo("Venue", "venueId"),

    // Redacted 
    // ...
  })
  .authorization(allow => [
    allow.group('Admin')
  ]),
})
.authorization(allow => [
  allow.resource(venuesLambda).to(["query"]),
])

const combinedSchema = a.combine([schema, sqlSchema]);

export type Schema = ClientSchema<typeof combinedSchema>;

export const data = defineData({
  schema: combinedSchema,
});

I see the following error when I deploy the sandbox:

Type 'RDSModelSchema<{ types: { active_storage_attachments: ModelType<SetTypeSubArg<{ fields: { id: ModelField<number, "required", undefined>; name: ModelField<string, "required", undefined>; record_type: ModelField<...>; record_id: ModelField<...>; blob_id: ModelField<...>; created_at: ModelField<...>; }; identifier: Mod...' is not assignable to type 'GenericModelSchema<any>'.
  Type 'RDSModelSchema<{ types: { active_storage_attachments: ModelType<SetTypeSubArg<{ fields: { id: ModelField<number, "required", undefined>; name: ModelField<string, "required", undefined>; record_type: ModelField<...>; record_id: ModelField<...>; blob_id: ModelField<...>; created_at: ModelField<...>; }; identifier: Mod...' is not assignable to type 'BaseSchema<any, false>'.
    Types of property 'context' are incompatible.
      Type '{ schemas: import("/Users/me/Documents/Projects/MyCompany/MyCompanyApp/node_modules/@aws-amplify/data-schema/dist/esm/ModelSchema").GenericModelSchema<any>[]; } | undefined' is not assignable to type '{ schemas: import("/Users/me/Documents/Projects/MyCompany/MyCompanyApp/node_modules/@aws-amplify/backend/node_modules/@aws-amplify/data-schema/dist/esm/ModelSchema").GenericModelSchema<any>[]; } | undefined'.
        Type '{ schemas: import("/Users/me/Documents/Projects/MyCompany/MyCompanyApp/node_modules/@aws-amplify/data-schema/dist/esm/ModelSchema").GenericModelSchema<any>[]; }' is not assignable to type '{ schemas: import("/Users/me/Documents/Projects/MyCompany/MyCompanyApp/node_modules/@aws-amplify/backend/node_modules/@aws-amplify/data-schema/dist/esm/ModelSchema").GenericModelSchema<any>[]; }'.
          Types of property 'schemas' are incompatible.
            Type 'import("/Users/me/Documents/Projects/MyCompany/MyCompanyApp/node_modules/@aws-amplify/data-schema/dist/esm/ModelSchema").GenericModelSchema<any>[]' is not assignable to type 'import("/Users/me/Documents/Projects/MyCompany/MyCompanyApp/node_modules/@aws-amplify/backend/node_modules/@aws-amplify/data-schema/dist/esm/ModelSchema").GenericModelSchema<any>[]'.
              Type 'import("/Users/me/Documents/Projects/MyCompany/MyCompanyApp/node_modules/@aws-amplify/data-schema/dist/esm/ModelSchema").GenericModelSchema<any>' is not assignable to type 'import("/Users/me/Documents/Projects/MyCompany/MyCompanyApp/node_modules/@aws-amplify/backend/node_modules/@aws-amplify/data-schema/dist/esm/ModelSchema").GenericModelSchema<any>'.
                Property '[brandSymbol]' is missing in type 'GenericModelSchema<any>' but required in type 'Brand<"DDBSchema" | "RDSSchema">'.

Reproduction steps

Follow the directions for importing your database schema (using npx ampx generate schema-from-database).

Deploy the sandbox with npx ampx sandbox.

ykethan commented 1 month ago

Hey👋, thanks for raising this! I'm going to transfer this over to our API repository for better assistance 🙂

AnilMaktala commented 1 month ago

Hey @chrisl777, Thanks for raising this. To better understand the issue, would you be able to share the generated schema?

chrisl777 commented 1 month ago

@AnilMaktala I can't share the entire generated schema publicly, but here's an excerpt of some models that I thought may be interesting.

Oddly, the identifier in some cases is not "id". Also, some of the table ids are integers (stored as BigInt in Postgres).

/* eslint-disable */
/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. */
import { a } from "@aws-amplify/data-schema";
import { configure } from "@aws-amplify/data-schema/internals";
import { secret } from "@aws-amplify/backend";

export const schema = configure({
    database: {
        identifier: "...",
        engine: "postgresql",
        connectionUri: secret("SQL_CONNECTION_STRING"),
        sslCert: secret("CUSTOM_SSL_CERT")
    }
}).schema({
    ....
    "ar_internal_metadata": a.model({
        key: a.string().required(),
        value: a.string(),
        created_at: a.datetime().required(),
        updated_at: a.datetime().required()
    }).identifier([
        "key"
    ]),
    ...
    "cities": a.model({
        id: a.integer().required(),
        city_name: a.string(),
        state_id: a.integer().required()
    }).identifier([
        "id"
    ]),
    ...
    "notifications": a.model({
        id: a.integer().required(),
        sender_user_id: a.integer().required(),
        receiver_user_id: a.integer().required(),
        notification_category: a.string().required(),
        notification_message: a.string(),
        additional_data: a.json(),
        read_status: a.string().required(),
        created_at: a.datetime().required(),
        updated_at: a.datetime().required()
    }).identifier([
        "id"
    ]),
    ...
    "schema_migrations": a.model({
        version: a.string().required()
    }).identifier([
        "version"
    ]),
    ...
    "states": a.model({
        id: a.integer().required(),
        state_name: a.string(),
        state_code: a.string()
    }).identifier([
        "id"
    ]),
    ...
    "venues": a.model({
        id: a.integer().required(),
        ...,
        created_at: a.datetime().required(),
        updated_at: a.datetime().required(),
        metadata: a.json().required(),
        ...
    }).identifier([
        "id"
    ]),
});
AnilMaktala commented 1 month ago

Hey @chrisl777, Thanks for your reply. Based on the error, the issue seems related to the Brand model. Do you have a Brand model, and if so, could you share it with us?

chrisl777 commented 1 month ago

@AnilMaktala As far as Brand, if you mean database type, we're connecting to a Postgres database (it's a third party database host, not RDS).

We followed these directions quite closely to generate the schema (Postgres): https://docs.amplify.aws/react-native/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/

AnilMaktala commented 1 month ago

Hey @chrisl777, thanks for providing additional details. Can you please remove and re-install the node modules. run below command to remove the node modules and package-lock.json file. rm -rf node_modules package-lock.json

sundersc commented 3 weeks ago

Oddly, the identifier in some cases is not "id". Also, some of the table ids are integers (stored as BigInt in Postgres).

Hey @chrisl777 - It looks like in some cases, the primary key isn't correctly detected during the schema generation step and it ends up assigning the default id field as primary key which could be breaking the type definition. Could you share the CREATE TABLE script and the corresponding model definition (a.model({...})) from the generated schema file for one of the tables for which the inferred primary key is incorrect.

chrisl777 commented 2 weeks ago

@sundersc @AnilMaktala I ended up commenting out the "ar_internal_metadata" and "schema_migrations" tables in the generated schema, as I don't really need those for operation of the app.

In the case of "ar_internal_metadata," that table is apparently automatically created by Rails to check the current environment before running migrations (the current backend was created using Ruby on Rails): https://vinioyama.com/blog/ruby-on-rails-what-is-ar_internal_metadata-metada-table/

For the "schema_migrations" table, it similarly is automatically created by Rails to manage databse migrations: https://planetscale.com/docs/tutorials/automatic-rails-migrations

Going forward, I don't need to access these tables via AppSync, so it's not as much of an issue. But I could see other people tripping over this problem.