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

Generated client in 0.9.x can still contain "string is not assignable to type undefined" errors #1001

Closed
fooware opened this issue Feb 23, 2024 · 19 comments
Assignees

Comments

@fooware
Copy link
Contributor

fooware commented Feb 23, 2024

There have been problems with incompatible Zod and Prisma versions in previous Electric-SQL versions, requiring the developer to use specific versions of Prisma and Zod, which is somewhat complicated, see PR #700.

That PR got rejected due to #727 adding a workaround using casts in the generated client, which fixed our initial problems.

However, as late as Electric 0.9.3 we still have this problem with our generated client with a more "advanced" DB structure, and due to internal changes in the way Electric generates the client, we can no longer override the Zod version using PNPM in a good way, so we are stuck at version 0.8.1 for now.

Test case

The main branch of the test repo below contains a mostly stock create-electric-app using ElectricSQL 0.9.3 and it can not generate a correct client.

Error

image

Test Repo

https://github.com/fooware/electric-testcase-01

Commit with the DB-structure

fooware/electric-testcase-01@10e5ff7

@kevin-dp
Copy link
Contributor

Hi @fooware, i found that these type errors got introduced by our upgrade to Prisma v5 for generating the Prisma client as v5 seems to introduce some breaking changes in the generated types. I could reproduce your type errors on a fresh create-electric-app with your schema. Also tested it with a modified Electric client that uses Prisma v4 and the type errors were gone. That confirms the problem i described. We will need to revert to using Prisma v4. Will keep you posted here when that is done. Thanks for reporting this issue.

@kevin-dp
Copy link
Contributor

Created a PR for reverting to Prisma v4: #1016

@fooware
Copy link
Contributor Author

fooware commented Feb 28, 2024

Sounds great @kevin-dp, looking forward to testing the new release when it is out.

@atanaskanchev
Copy link

Could this be related to this long lived Zod bug? colinhacks/zod#2184

@msfstef
Copy link
Contributor

msfstef commented Mar 27, 2024

@fooware this issue should be resolved now in 0.9.6 - can you confirm?
If other problems related to the generator come up it's better if they are added as separate issues.

@jljorgenson18
Copy link

@msfstef I am still seeing errors in 0.9.6 and had to add @ts-expect-error comments throughout the generated code

@msfstef
Copy link
Contributor

msfstef commented Mar 27, 2024

@jljorgenson18 is it still the string is not assignable to type undefined error or something else like 'Relation' is declared but its value is never read.?

@jljorgenson18
Copy link

I am receiving two types of errors.

The first one is the string error

Type 'ZodObject<{ where: ZodLazy<ZodType<DataSourceSectionsWhereUniqueInput, ZodTypeDef, DataSourceSectionsWhereUniqueInput>>; create: ZodUnion<[ZodLazy<ZodType<DataSourceSectionsCreateWithoutDataSourceDataPointsInput, ZodTypeDef, DataSourceSectionsCreateWithoutDataSourceDataPointsInput>>, ZodLazy<ZodType<DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput, ZodTypeDef, DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput>>]>; }, "strict", ZodTypeAny, { create: (DataSourceSectionsCreateWithoutDataSourceDataPointsInput | DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput) & (DataSourceSectionsCreateWithoutDataSourceDataPointsInput | DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput | undefined); where: DataSourceSectionsWhereUniqueInput; }, { create: (DataSourceSectionsCreateWithoutDataSourceDataPointsInput | DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput) & (DataSourceSectionsCreateWithoutDataSourceDataPointsInput | DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput | undefined); where: DataSourceSectionsWhereUniqueInput; }>' is not assignable to type 'ZodType<DataSourceSectionsCreateOrConnectWithoutDataSourceDataPointsInput, ZodTypeDef, DataSourceSectionsCreateOrConnectWithoutDataSourceDataPointsInput>'.
  The types of '_type.create' are incompatible between these types.
    Type '(DataSourceSectionsCreateWithoutDataSourceDataPointsInput | DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput) & (DataSourceSectionsCreateWithoutDataSourceDataPointsInput | DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput | undefined)' is not assignable to type '(Without<DataSourceSectionsCreateWithoutDataSourceDataPointsInput, DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput> & DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput) | (Without<DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput, DataSourceSectionsCreateWithoutDataSourceDataPointsInput> & DataSourceSectionsCreateWithoutDataSourceDataPointsInput)'.
      Type 'DataSourceSectionsCreateWithoutDataSourceDataPointsInput & DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput' is not assignable to type '(Without<DataSourceSectionsCreateWithoutDataSourceDataPointsInput, DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput> & DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput) | (Without<DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput, DataSourceSectionsCreateWithoutDataSourceDataPointsInput> & DataSourceSectionsCreateWithoutDataSourceDataPointsInput)'.
        Type 'DataSourceSectionsCreateWithoutDataSourceDataPointsInput & DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput' is not assignable to type 'Without<DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput, DataSourceSectionsCreateWithoutDataSourceDataPointsInput> & DataSourceSectionsCreateWithoutDataSourceDataPointsInput'.
          Type 'DataSourceSectionsCreateWithoutDataSourceDataPointsInput & DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput' is not assignable to type 'Without<DataSourceSectionsUncheckedCreateWithoutDataSourceDataPointsInput, DataSourceSectionsCreateWithoutDataSourceDataPointsInput>'.
            Types of property 'dataSourceId' are incompatible.
              Type 'string' is not assignable to type 'undefined'.

The second one has something to do with context

Conversion of type '{ fields: Map<string, "UUID" | "TEXT" | "JSONB" | "INT4" | "TIMESTAMP" | "BOOL">; relations: Relation[]; modelSchema: any; createSchema: z.ZodType<Prisma.DataSourceSectionsCreateArgs, z.ZodTypeDef, Prisma.DataSourceSectionsCreateArgs>; createManySchema: z.ZodType<Prisma.DataSourceSectionsCreateManyArgs, z.ZodTypeDef, Prisma.DataSourceSectionsCreateManyArgs>; findUniqueSchema: z.ZodType<Prisma.DataSourceSectionsFindUniqueArgs, z.ZodTypeDef, Prisma.DataSourceSectionsFindUniqueArgs>; findSchema: z.ZodType<Prisma.DataSourceSectionsFindFirstArgs, z.ZodTypeDef, Prisma.DataSourceSectionsFindFirstArgs>; updateSchema: z.ZodType<Prisma.DataSourceSectionsUpdateArgs, z.ZodTypeDef, Prisma.DataSourceSectionsUpdateArgs>; updateManySchema: z.ZodType<Prisma.DataSourceSectionsUpdateManyArgs, z.ZodTypeDef, Prisma.DataSourceSectionsUpdateManyArgs>; upsertSchema: z.ZodType<Prisma.DataSourceSectionsUpsertArgs, z.ZodTypeDef, Prisma.DataSourceSectionsUpsertArgs>; deleteSchema: z.ZodType<Prisma.DataSourceSectionsDeleteArgs, z.ZodTypeDef, Prisma.DataSourceSectionsDeleteArgs>; deleteManySchema: z.ZodType<Prisma.DataSourceSectionsDeleteManyArgs, z.ZodTypeDef, Prisma.DataSourceSectionsDeleteManyArgs>; }' to type 'TableSchema<DataSourceSectionsCreateInput, (Without<DataSourceSectionsCreateInput, DataSourceSectionsUncheckedCreateInput> & DataSourceSectionsUncheckedCreateInput) | (Without<DataSourceSectionsUncheckedCreateInput, DataSourceSectionsCreateInput> & DataSourceSectionsCreateInput), (Without<DataSourceSectionsUpdateInput, DataSourceSectionsUncheckedUpdateInput> & DataSourceSectionsUncheckedUpdateInput) | (Without<DataSourceSectionsUncheckedUpdateInput, DataSourceSectionsUpdateInput> & DataSourceSectionsUpdateInput), DataSourceSectionsSelect | null | undefined, DataSourceSectionsWhereInput | undefined, DataSourceSectionsWhereUniqueInput, Omit<DataSourceSectionsInclude, "_count">, Enumerable<DataSourceSectionsOrderByWithRelationInput> | undefined, DataSourceSectionsScalarFieldEnum, DataSourceSectionsGetPayload>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  The types of 'createSchema.refine(...).refine(...).optional().optional().nullable().nullable().array().nonempty(...).promise().promise().or(...).or(...).and(...).and(...).default(...).default(...).brand(...).brand(...).catch(...)._def.catchValue' are incompatible between these types.
    Type '(ctx: { error: ZodError<any>; input: unknown; }) => any' is not comparable to type '(ctx: { error: ZodError<any>; }) => any'.
      Types of parameters 'ctx' and 'ctx' are incompatible.
        Type '{ error: ZodError<any>; }' is not comparable to type '{ error: ZodError<any>; input: unknown; }'.ts(2352)

@fooware
Copy link
Contributor Author

fooware commented Mar 28, 2024

@fooware this issue should be resolved now in 0.9.6 - can you confirm? If other problems related to the generator come up it's better if they are added as separate issues.

Thanks for the update @msfstef . I'm heading out for easter vacation at this very moment, but I will try to update the test case repo and check during next week.

@msfstef
Copy link
Contributor

msfstef commented Apr 1, 2024

@jljorgenson18 could you post your tsconfig compiler options here?

Make sure you have strict mode enabled and you do not have strictNullChecks set to false. The schema validation library Electric uses, Zod, will have unexpected behaviour if using non-strict compilation options (see this readme).

@jljorgenson18
Copy link

jljorgenson18 commented Apr 1, 2024

@msfstef Everything is set to strict, otherwise the undefined error would not be possible I don't think.

{
  "compilerOptions": {
    "target": "esnext",
    "moduleResolution": "node",
    "module": "ESNext",
    "allowJs": true,
    "strict": true,
    "noErrorTruncation": true,
    "esModuleInterop": true,
    "noImplicitAny": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strictNullChecks": true,
    "jsx": "react",
    "lib": ["DOM", "ES7", "ES2019", "DOM.Iterable", "WebWorker"],
    "baseUrl": ".",
    "paths": {
      "src/*": ["./src/*"],
      "test/*": ["./test/*"]
    },
    "typeRoots": ["../node_modules/@types", "./typings"]
  },
  "include": [],
  "exclude": []
}

@msfstef
Copy link
Contributor

msfstef commented Apr 2, 2024

@jljorgenson18 I see, thank you, could you share your migration as well so I can try and reproduce this particular error?

@jljorgenson18
Copy link

@msfstef Sure thing

export default [
  {
    "statements": [
      "CREATE TABLE \"dataSources\" (\n  \"id\" TEXT NOT NULL,\n  \"ownerId\" TEXT NOT NULL,\n  \"accessCredentialId\" TEXT,\n  \"name\" TEXT NOT NULL,\n  \"syncType\" TEXT NOT NULL,\n  \"connectorId\" TEXT NOT NULL,\n  \"sortWeight\" TEXT,\n  \"config\" TEXT_JSON NOT NULL,\n  \"clientData\" TEXT_JSON,\n  \"createdAt\" TEXT(3) NOT NULL,\n  \"updatedAt\" TEXT(3) NOT NULL,\n  CONSTRAINT \"dataSources_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n",
      "CREATE TABLE \"dataSourceSections\" (\n  \"id\" TEXT NOT NULL,\n  \"dataSourceId\" TEXT NOT NULL,\n  \"name\" TEXT NOT NULL,\n  \"label\" TEXT NOT NULL,\n  \"fields\" TEXT_JSON NOT NULL,\n  \"refreshInterval\" INTEGER,\n  \"lastSyncTime\" TEXT(3),\n  \"lastSyncMeta\" TEXT_JSON,\n  \"initialized\" INTEGER NOT NULL,\n  \"createdAt\" TEXT(3) NOT NULL,\n  \"updatedAt\" TEXT(3) NOT NULL,\n  CONSTRAINT \"dataSourceSections_dataSourceId_fkey\" FOREIGN KEY (\"dataSourceId\") REFERENCES \"dataSources\" (\"id\") ON DELETE CASCADE ON UPDATE CASCADE,\n  CONSTRAINT \"dataSourceSections_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n",
      "CREATE TABLE \"dataSourceDataPoints\" (\n  \"id\" TEXT NOT NULL,\n  \"pointId\" TEXT NOT NULL,\n  \"dataSourceSectionId\" TEXT NOT NULL,\n  \"point\" TEXT_JSON NOT NULL,\n  CONSTRAINT \"dataSourceDataPoints_dataSourceSectionId_fkey\" FOREIGN KEY (\"dataSourceSectionId\") REFERENCES \"dataSourceSections\" (\"id\") ON DELETE CASCADE ON UPDATE CASCADE,\n  CONSTRAINT \"dataSourceDataPoints_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n",
      "INSERT OR IGNORE INTO _electric_trigger_settings(tablename,flag) VALUES ('main.dataSources', 1);",
      "DROP TRIGGER IF EXISTS update_ensure_main_dataSources_primarykey;",
      "CREATE TRIGGER update_ensure_main_dataSources_primarykey\n  BEFORE UPDATE ON \"main\".\"dataSources\"\nBEGIN\n  SELECT\n    CASE\n      WHEN old.\"id\" != new.\"id\" THEN\n      \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n    END;\nEND;",
      "DROP TRIGGER IF EXISTS insert_main_dataSources_into_oplog;",
      "CREATE TRIGGER insert_main_dataSources_into_oplog\n   AFTER INSERT ON \"main\".\"dataSources\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSources')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSources', 'INSERT', json_object('id', new.\"id\"), json_object('accessCredentialId', new.\"accessCredentialId\", 'clientData', new.\"clientData\", 'config', new.\"config\", 'connectorId', new.\"connectorId\", 'createdAt', new.\"createdAt\", 'id', new.\"id\", 'name', new.\"name\", 'ownerId', new.\"ownerId\", 'sortWeight', new.\"sortWeight\", 'syncType', new.\"syncType\", 'updatedAt', new.\"updatedAt\"), NULL, NULL);\nEND;",
      "DROP TRIGGER IF EXISTS update_main_dataSources_into_oplog;",
      "CREATE TRIGGER update_main_dataSources_into_oplog\n   AFTER UPDATE ON \"main\".\"dataSources\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSources')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSources', 'UPDATE', json_object('id', new.\"id\"), json_object('accessCredentialId', new.\"accessCredentialId\", 'clientData', new.\"clientData\", 'config', new.\"config\", 'connectorId', new.\"connectorId\", 'createdAt', new.\"createdAt\", 'id', new.\"id\", 'name', new.\"name\", 'ownerId', new.\"ownerId\", 'sortWeight', new.\"sortWeight\", 'syncType', new.\"syncType\", 'updatedAt', new.\"updatedAt\"), json_object('accessCredentialId', old.\"accessCredentialId\", 'clientData', old.\"clientData\", 'config', old.\"config\", 'connectorId', old.\"connectorId\", 'createdAt', old.\"createdAt\", 'id', old.\"id\", 'name', old.\"name\", 'ownerId', old.\"ownerId\", 'sortWeight', old.\"sortWeight\", 'syncType', old.\"syncType\", 'updatedAt', old.\"updatedAt\"), NULL);\nEND;",
      "DROP TRIGGER IF EXISTS delete_main_dataSources_into_oplog;",
      "CREATE TRIGGER delete_main_dataSources_into_oplog\n   AFTER DELETE ON \"main\".\"dataSources\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSources')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSources', 'DELETE', json_object('id', old.\"id\"), NULL, json_object('accessCredentialId', old.\"accessCredentialId\", 'clientData', old.\"clientData\", 'config', old.\"config\", 'connectorId', old.\"connectorId\", 'createdAt', old.\"createdAt\", 'id', old.\"id\", 'name', old.\"name\", 'ownerId', old.\"ownerId\", 'sortWeight', old.\"sortWeight\", 'syncType', old.\"syncType\", 'updatedAt', old.\"updatedAt\"), NULL);\nEND;",
      "INSERT OR IGNORE INTO _electric_trigger_settings(tablename,flag) VALUES ('main.dataSourceSections', 1);",
      "DROP TRIGGER IF EXISTS update_ensure_main_dataSourceSections_primarykey;",
      "CREATE TRIGGER update_ensure_main_dataSourceSections_primarykey\n  BEFORE UPDATE ON \"main\".\"dataSourceSections\"\nBEGIN\n  SELECT\n    CASE\n      WHEN old.\"id\" != new.\"id\" THEN\n      \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n    END;\nEND;",
      "DROP TRIGGER IF EXISTS insert_main_dataSourceSections_into_oplog;",
      "CREATE TRIGGER insert_main_dataSourceSections_into_oplog\n   AFTER INSERT ON \"main\".\"dataSourceSections\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSourceSections')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSourceSections', 'INSERT', json_object('id', new.\"id\"), json_object('createdAt', new.\"createdAt\", 'dataSourceId', new.\"dataSourceId\", 'fields', new.\"fields\", 'id', new.\"id\", 'initialized', new.\"initialized\", 'label', new.\"label\", 'lastSyncMeta', new.\"lastSyncMeta\", 'lastSyncTime', new.\"lastSyncTime\", 'name', new.\"name\", 'refreshInterval', new.\"refreshInterval\", 'updatedAt', new.\"updatedAt\"), NULL, NULL);\nEND;",
      "DROP TRIGGER IF EXISTS update_main_dataSourceSections_into_oplog;",
      "CREATE TRIGGER update_main_dataSourceSections_into_oplog\n   AFTER UPDATE ON \"main\".\"dataSourceSections\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSourceSections')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSourceSections', 'UPDATE', json_object('id', new.\"id\"), json_object('createdAt', new.\"createdAt\", 'dataSourceId', new.\"dataSourceId\", 'fields', new.\"fields\", 'id', new.\"id\", 'initialized', new.\"initialized\", 'label', new.\"label\", 'lastSyncMeta', new.\"lastSyncMeta\", 'lastSyncTime', new.\"lastSyncTime\", 'name', new.\"name\", 'refreshInterval', new.\"refreshInterval\", 'updatedAt', new.\"updatedAt\"), json_object('createdAt', old.\"createdAt\", 'dataSourceId', old.\"dataSourceId\", 'fields', old.\"fields\", 'id', old.\"id\", 'initialized', old.\"initialized\", 'label', old.\"label\", 'lastSyncMeta', old.\"lastSyncMeta\", 'lastSyncTime', old.\"lastSyncTime\", 'name', old.\"name\", 'refreshInterval', old.\"refreshInterval\", 'updatedAt', old.\"updatedAt\"), NULL);\nEND;",
      "DROP TRIGGER IF EXISTS delete_main_dataSourceSections_into_oplog;",
      "CREATE TRIGGER delete_main_dataSourceSections_into_oplog\n   AFTER DELETE ON \"main\".\"dataSourceSections\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSourceSections')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSourceSections', 'DELETE', json_object('id', old.\"id\"), NULL, json_object('createdAt', old.\"createdAt\", 'dataSourceId', old.\"dataSourceId\", 'fields', old.\"fields\", 'id', old.\"id\", 'initialized', old.\"initialized\", 'label', old.\"label\", 'lastSyncMeta', old.\"lastSyncMeta\", 'lastSyncTime', old.\"lastSyncTime\", 'name', old.\"name\", 'refreshInterval', old.\"refreshInterval\", 'updatedAt', old.\"updatedAt\"), NULL);\nEND;",
      "DROP TRIGGER IF EXISTS compensation_insert_main_dataSourceSections_dataSourceId_into_oplog;",
      "CREATE TRIGGER compensation_insert_main_dataSourceSections_dataSourceId_into_oplog\n  AFTER INSERT ON \"main\".\"dataSourceSections\"\n  WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSources') AND\n       1 == (SELECT value from _electric_meta WHERE key == 'compensations')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  SELECT 'main', 'dataSources', 'COMPENSATION', json_object('id', \"id\"), json_object('id', \"id\"), NULL, NULL\n  FROM \"main\".\"dataSources\" WHERE \"id\" = new.\"dataSourceId\";\nEND;",
      "DROP TRIGGER IF EXISTS compensation_update_main_dataSourceSections_dataSourceId_into_oplog;",
      "CREATE TRIGGER compensation_update_main_dataSourceSections_dataSourceId_into_oplog\n   AFTER UPDATE ON \"main\".\"dataSourceSections\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSources') AND\n        1 == (SELECT value from _electric_meta WHERE key == 'compensations')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  SELECT 'main', 'dataSources', 'COMPENSATION', json_object('id', \"id\"), json_object('id', \"id\"), NULL, NULL\n  FROM \"main\".\"dataSources\" WHERE \"id\" = new.\"dataSourceId\";\nEND;",
      "INSERT OR IGNORE INTO _electric_trigger_settings(tablename,flag) VALUES ('main.dataSourceDataPoints', 1);",
      "DROP TRIGGER IF EXISTS update_ensure_main_dataSourceDataPoints_primarykey;",
      "CREATE TRIGGER update_ensure_main_dataSourceDataPoints_primarykey\n  BEFORE UPDATE ON \"main\".\"dataSourceDataPoints\"\nBEGIN\n  SELECT\n    CASE\n      WHEN old.\"id\" != new.\"id\" THEN\n      \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n    END;\nEND;",
      "DROP TRIGGER IF EXISTS insert_main_dataSourceDataPoints_into_oplog;",
      "CREATE TRIGGER insert_main_dataSourceDataPoints_into_oplog\n   AFTER INSERT ON \"main\".\"dataSourceDataPoints\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSourceDataPoints')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSourceDataPoints', 'INSERT', json_object('id', new.\"id\"), json_object('dataSourceSectionId', new.\"dataSourceSectionId\", 'id', new.\"id\", 'point', new.\"point\", 'pointId', new.\"pointId\"), NULL, NULL);\nEND;",
      "DROP TRIGGER IF EXISTS update_main_dataSourceDataPoints_into_oplog;",
      "CREATE TRIGGER update_main_dataSourceDataPoints_into_oplog\n   AFTER UPDATE ON \"main\".\"dataSourceDataPoints\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSourceDataPoints')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSourceDataPoints', 'UPDATE', json_object('id', new.\"id\"), json_object('dataSourceSectionId', new.\"dataSourceSectionId\", 'id', new.\"id\", 'point', new.\"point\", 'pointId', new.\"pointId\"), json_object('dataSourceSectionId', old.\"dataSourceSectionId\", 'id', old.\"id\", 'point', old.\"point\", 'pointId', old.\"pointId\"), NULL);\nEND;",
      "DROP TRIGGER IF EXISTS delete_main_dataSourceDataPoints_into_oplog;",
      "CREATE TRIGGER delete_main_dataSourceDataPoints_into_oplog\n   AFTER DELETE ON \"main\".\"dataSourceDataPoints\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSourceDataPoints')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  VALUES ('main', 'dataSourceDataPoints', 'DELETE', json_object('id', old.\"id\"), NULL, json_object('dataSourceSectionId', old.\"dataSourceSectionId\", 'id', old.\"id\", 'point', old.\"point\", 'pointId', old.\"pointId\"), NULL);\nEND;",
      "DROP TRIGGER IF EXISTS compensation_insert_main_dataSourceDataPoints_dataSourceSectionId_into_oplog;",
      "CREATE TRIGGER compensation_insert_main_dataSourceDataPoints_dataSourceSectionId_into_oplog\n  AFTER INSERT ON \"main\".\"dataSourceDataPoints\"\n  WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSourceSections') AND\n       1 == (SELECT value from _electric_meta WHERE key == 'compensations')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  SELECT 'main', 'dataSourceSections', 'COMPENSATION', json_object('id', \"id\"), json_object('id', \"id\"), NULL, NULL\n  FROM \"main\".\"dataSourceSections\" WHERE \"id\" = new.\"dataSourceSectionId\";\nEND;",
      "DROP TRIGGER IF EXISTS compensation_update_main_dataSourceDataPoints_dataSourceSectionId_into_oplog;",
      "CREATE TRIGGER compensation_update_main_dataSourceDataPoints_dataSourceSectionId_into_oplog\n   AFTER UPDATE ON \"main\".\"dataSourceDataPoints\"\n   WHEN 1 == (SELECT flag from _electric_trigger_settings WHERE tablename == 'main.dataSourceSections') AND\n        1 == (SELECT value from _electric_meta WHERE key == 'compensations')\nBEGIN\n  INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n  SELECT 'main', 'dataSourceSections', 'COMPENSATION', json_object('id', \"id\"), json_object('id', \"id\"), NULL, NULL\n  FROM \"main\".\"dataSourceSections\" WHERE \"id\" = new.\"dataSourceSectionId\";\nEND;"
    ],
    "version": "20240127171312"
  }
]

@msfstef
Copy link
Contributor

msfstef commented Apr 2, 2024

@jljorgenson18 thank you! I think it'll be easier if you share the postgres schema migration from which the sqlite migrations are generated if it's possible

msfstef added a commit that referenced this issue Apr 3, 2024
…ests (#1117)

Relevant issues: #1001
#925
#1114

Only one thing is fixed in this PR, the `Relation` is no longer imported
if the data model has no relations in order to avoid `unused imports` TS
errors.

Main changes are moving all of the generator tests into their own test
directory rather than inside the source code, for consistency with the
TS client, ease of use, and improved reusability of test utilities.

I've also added a sort of integration test for the CLI generation step,
which is crucial to getting a working, compileable TS client as it
modifies some of the Prisma generated typings. This test generates the
client given a Prisma schema and performs all appropriate modifications
to it, and then attempts to compile it with TS and specified compiler
options.

Also found that with TS version >=5.4 we have [stricter conditional type
checking](https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/#notable-behavioral-changes)
which breaks clients generated with Prisma versions earlier than 4.16.0
(see issue #1114),
however 4.16.0 introduces breaking changes with the "extensions"
feature, so I've added a hacky workaround for it:

https://github.com/electric-sql/electric/pull/1117/files#diff-fb0a50df4fc86f09b81a210162984d7822276fe19c8ae6496cf5ffe7d09f5adb

We can add more tests that would test various compiler options, making
it easier to avoid regressions when users report them with more
complicated schemas and TS compiler options.

Finally, I've added a Caution banner in our Usage section in the docs
about requiring TS `strict` mode, since Zod has that as a requirement as
well and its the reason why we see some inconsistencies in bug reports.
@fooware
Copy link
Contributor Author

fooware commented Apr 4, 2024

@fooware this issue should be resolved now in 0.9.6 - can you confirm? If other problems related to the generator come up it's better if they are added as separate issues.

@msfstef: I took some time to verify today. It took some time since 0.9.3 (or perhaps 0.9.4, not sure what was resolved) was no longer compatible with the new Docker Compose release that went live like 10 days ago, something about extends and depends_on on being allowed at the same time any longer.

Anyhow, after rolling back my Docker version, upgrading to Electric 0.9.6 and doing a client:generate I can verify that the string is not assignable to type undefined errors are gone. 👍

That said, there sure is a lot of warnings now. In prismaClient.d.ts I had to set all these flags at the top of the file to quiet it down:

/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable @typescript-eslint/no-explicit-any */

In index.ts it was enough with:

/* eslint-disable @typescript-eslint/no-explicit-any */

@fooware
Copy link
Contributor Author

fooware commented Apr 4, 2024

@msfstef: Please let me know if you need anything else, or if I'm supposed to be the one to close the issue.

@msfstef
Copy link
Contributor

msfstef commented Apr 4, 2024

@fooware glad the string issue was resolved! There's one more PR that should solve a few more TS issues (#1117).

Regarding the linting, it'll be hard to make the client respect all lint rule setups so the main thing is for it to be compileable by TS - I'd suggest excluding the generated client directory from linting (@kevin-dp what do you think?)

That being said, at least for the index.ts where we have more control we can try and respect more strict lint rules like no-explicit-any.

If your issue has been resolved then feel free to close it :)

@fooware fooware closed this as completed Apr 4, 2024
Copy link
Contributor

kevin-dp commented Apr 8, 2024

@msfstef, indeed, we don't have much (if any) control over the generated prismaClient.d.ts. We have more control over the generated index.ts client so that would be more feasible. These issues should be solved when we introduce our own (Prisma-independent) client generator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants