drizzle-team / drizzle-graphql

Automatically generate GraphQL schema or customizable schema config fields from Drizzle ORM schema
https://www.npmjs.com/package/drizzle-graphql
Apache License 2.0
49 stars 5 forks source link

impossible to define array of objects (aka jsonb) + no support for custom fields #22

Open creotip opened 1 month ago

creotip commented 1 month ago

Seems like there is no easy way to define a field as array of objects. one way is to define with jsonb:

interface PreviousOwner {
  name: string
}

export const owners = pgTable('owners', {
  id: serial('id').primaryKey(),
  previousOwners: jsonb('previous_owners')
    .$type<PreviousOwner[]>()
    .notNull()
    .default([]),
})

Checking Apollo sandbox Introspection Schema. drizzle-graphql generates the following SDL schema:

input OwnersInsertInput {
  id: Int

  """JSON"""
  previousOwners: String
}

So, the mutation will accept String only:

mutation InsertIntoOwnersSingle {
  insertIntoOwnersSingle(
    values: { 
        previousOwners: "[{\"name\": \"jon doe3\"}]"
      }
  ) {
    id
    previousOwners
  }
}

Checking in drizzle studio. the record has been created:

Screenshot 2024-09-16 at 12 42 33

Now, lets execute the query:

query Owners {
  owners {
    id
    previousOwners
  }
}

And here is the error:

{
  "errors": [
    {
      "message": "String cannot represent value: [\"{\\\"name\\\":\\\"jon doe3\\\"}\"]",
      "locations": [
        {
          "line": 4,
          "column": 5
        }
      ],
      "path": [
        "owners",
        0,
        "previousOwners"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "stacktrace": [
          "GraphQLError: String cannot represent value: [\"{\\\"name\\\":\\\"jon doe3\\\"}\"]",
          "    at GraphQLScalarType.serialize (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/type/scalars.js:202:11)",
          "    at completeLeafValue (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:749:39)",
          "    at completeValue (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:630:12)",
          "    at completeValue (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:595:23)",
          "    at executeField (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:500:19)",
          "    at executeFields (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:414:22)",
          "    at completeObjectValue (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:925:10)",
          "    at completeValue (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:646:12)",
          "    at completeValue (/Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:595:23)",
          "    at /Users/myuser/Desktop/projects/my-turborepo/node_modules/.pnpm/graphql@16.9.0/node_modules/graphql/execution/execute.js:707:25"
        ]
      }
    }
  ],
  "data": null
}

Tried to fix it with custom field:

const customJsonB = customType<{
  data: PreviousOwner[]
}>({
  dataType: () => 'jsonb',
  fromDriver: (val) => JSON.parse(val as string),
  toDriver: (val: PreviousOwner[]) => JSON.stringify(val),
})

But there is no support for custom field:

throw new Error(`Drizzle-GraphQL Error: Type ${column.dataType} is not implemented!`);

https://github.com/drizzle-team/drizzle-graphql/blob/c558249fadcc7bd1af8ec17faf292d8cf2d365c5/src/util/type-converter/index.ts#L121

chemalopezp commented 2 weeks ago

I'm also stuck with no support for custom fields. In my case I'm trying to simply define some postgres like types, such as:

export const tstzrange = customType<TsTzRange>({
  dataType() {
    return "tstzrange";
  },
  toDriver(value: TsTzRange["data"]): string {
    return `[${value.from},${value.to})`;
  },
  fromDriver(value: string): TsTzRange["data"] {
    const [from, to] = value.slice(1, -1).split(",");
    return {
      from,
      to,
    };
  },
});

but I get

/node_modules/src/util/type-converter/index.ts:121
                        throw new Error(`Drizzle-GraphQL Error: Type ${column.dataType} is not implemented!`);
                              ^

Error: Drizzle-GraphQL Error: Type custom is not implemented!

Is it something I'm doing wrong or simply there's still not a support for this use case? Any idea how to move forward?

ruslan-primesec commented 2 weeks ago

@chemalopezp I forked the repo and added support for array of objects and partial support for custom fields. Will push PR soon.

chemalopezp commented 2 weeks ago

@ruslan-primesec that's amazing! Thank you so much, let me know if I can be of any help 🎉 Looking forward to test it ;)

chemalopezp commented 4 days ago

@ruslan-primesec I hope everything is going well! Is there any way I could help with the custom fields PR? Or do you already have a timeline? Thank you so much!