Issue(mongoDB): Types missing in generated GraphQL schema. IDs and relation scalar fields not supported.
mikerudge opened this issue · 7 comments
When using the type
for embedded documents, it seems as though the schema that is generated doesnt include the type.
Here is a quick example. If we use this as the schema.
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
generator appsync {
provider = "prisma-appsync"
}
generator client {
provider = "prisma-client-js"
}
type Address {
street String
city String
zip String
}
type Photo {
height Int
width Int
url String
}
/// @gql(subscriptions: null, mutations: null)
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
photo Photo?
address Address?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Then this is the output
type User {
id: String!
email: AWSEmail!
name: String
photo: Photo
address: Address <--- type of Address is here but not defined anywhere?
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
type BatchPayload {
count: Int
}
enum OrderByArg {
ASC
DESC
}
input UserFilter {
some: UserWhereInput
every: UserWhereInput
none: UserWhereInput
}
input UserWhereInput {
OR: [UserWhereInput]
NOT: [UserWhereInput]
AND: [UserWhereInput]
id: StringFilter
email: AWSEmailFilter
name: StringFilter
photo: StringFilter
address: StringFilter <-- address is a string here, but it should be an object
createdAt: AWSDateTimeFilter
updatedAt: AWSDateTimeFilter
}
input UserWhereUniqueInput {
id: String
email: AWSEmail
}
input UserExtendedWhereUniqueInput {
OR: [UserWhereInput]
NOT: [UserWhereInput]
AND: [UserWhereInput]
id: String
email: AWSEmail
name: StringFilter
photo: StringFilter
address: StringFilter
createdAt: AWSDateTimeFilter
updatedAt: AWSDateTimeFilter
}
input UserOrderByInput {
id: OrderByArg
email: OrderByArg
name: OrderByArg
photo: OrderByArg
address: OrderByArg
createdAt: OrderByArg
updatedAt: OrderByArg
}
input UserCreateInput {
id: String!
email: AWSEmail!
name: String
photo: Photo
address: Address <--- address type here
createdAt: AWSDateTime
updatedAt: AWSDateTime
}
input UserCreateManyInput {
id: String!
email: AWSEmail!
name: String
photo: Photo
address: Address <--- address type here
createdAt: AWSDateTime
updatedAt: AWSDateTime
}
input UserUpdateInput {
id: String
email: AWSEmail
name: String
photo: Photo
address: Address <--- address type here
createdAt: AWSDateTime
updatedAt: AWSDateTime
}
input UserUpdateUniqueInput {
data: UserUpdateInput!
where: UserWhereUniqueInput!
}
input UserUpdateManyInput {
where: UserWhereInput!
data: UserUpdateInput!
}
input UserUpsertInput {
create: UserCreateInput!
update: UserUpdateInput!
}
input UserUpsertUniqueInput {
where: UserWhereUniqueInput!
create: UserCreateInput!
update: UserUpdateInput!
}
input UserConnectOrCreateInput {
where: UserWhereUniqueInput!
create: UserCreateInput!
}
input UserDeleteUniqueInput {
where: UserWhereUniqueInput!
}
input UserDeleteManyInput {
where: UserWhereInput!
}
input IntOperation {
set: Int
increment: Int
decrement: Int
multiply: Int
divide: Int
}
input FloatOperation {
set: Float
increment: Float
decrement: Float
multiply: Float
divide: Float
}
input AWSDateTimeFilter {
equals: AWSDateTime
gt: AWSDateTime
gte: AWSDateTime
in: [AWSDateTime!]
lt: AWSDateTime
lte: AWSDateTime
not: AWSDateTimeFilter
notIn: [AWSDateTime!]
}
input AWSDateTimeListFilter {
equals: [AWSDateTime!]
has: AWSDateTime
hasEvery: [AWSDateTime!]
hasSome: [AWSDateTime!]
isEmpty: Boolean
}
input FloatFilter {
equals: Float
gt: Float
gte: Float
in: [Float!]
lt: Float
lte: Float
not: FloatFilter
notIn: [Float!]
}
input FloatListFilter {
equals: [Float!]
has: Float
hasEvery: [Float!]
hasSome: [Float!]
isEmpty: Boolean
}
input IntFilter {
equals: Int
gt: Int
gte: Int
in: [Int!]
lt: Int
lte: Int
not: IntFilter
notIn: [Int!]
}
input IntListFilter {
equals: [Int!]
has: Int
hasEvery: [Int!]
hasSome: [Int!]
isEmpty: Boolean
}
input AWSJSONFilter {
contains: String
endsWith: String
equals: AWSJSON
in: [AWSJSON!]
not: AWSJSONFilter
notIn: [AWSJSON!]
startsWith: String
}
input AWSJSONListFilter {
equals: [AWSJSON!]
has: AWSJSON
hasEvery: [AWSJSON!]
hasSome: [AWSJSON!]
isEmpty: Boolean
}
input AWSEmailFilter {
contains: String
endsWith: String
equals: AWSEmail
in: [AWSEmail!]
not: AWSEmailFilter
notIn: [AWSEmail!]
startsWith: String
}
input AWSEmailListFilter {
equals: [AWSEmail!]
has: AWSEmail
hasEvery: [AWSEmail!]
hasSome: [AWSEmail!]
isEmpty: Boolean
}
input AWSURLFilter {
contains: String
endsWith: String
equals: AWSURL
in: [AWSURL!]
not: AWSURLFilter
notIn: [AWSURL!]
startsWith: String
}
input AWSURLListFilter {
equals: [AWSURL!]
has: AWSURL
hasEvery: [AWSURL!]
hasSome: [AWSURL!]
isEmpty: Boolean
}
input StringFilter {
contains: String
endsWith: String
equals: String
in: [String!]
not: StringFilter
notIn: [String!]
startsWith: String
mode: String
}
input StringListFilter {
equals: [String!]
has: String
hasEvery: [String!]
hasSome: [String!]
isEmpty: Boolean
}
input BooleanFilter {
equals: Boolean
not: BooleanFilter
}
input BooleanListFilter {
equals: [Boolean!]
has: Boolean
hasEvery: [Boolean!]
hasSome: [Boolean!]
}
type Query {
"""
Find a single User record by unique identifier.
"""
getUser(where: UserWhereUniqueInput!): User
"""
Find many User records (optional query filters).
"""
listUsers(
where: UserWhereInput
orderBy: [UserOrderByInput]
skip: Int
take: Int
): [User]
"""
Count all User records (optional query filters).
"""
countUsers(
where: UserWhereInput
orderBy: [UserOrderByInput]
skip: Int
take: Int
): Int
}
Hey @mikerudge, I am not familiar with MongoDB - but looking at your Prisma schema, I can see that both Address
and Photo
don't have id fields specified? This could explain why Prisma-AppSync is skipping these models.
I have found some Prisma documentation on the topic, but it is quite lite for people who aren't familiar with MongoDB. To fix the issue, I would probably need some time to play with MongoDB and see how we can best support IDs and relation scalar fields with the @map
directive.
Is the same Prisma schema (with no id
fields on Address
and Photo
) working ok with Prisma Client outside of Prisma-AppSync?
Hey
Yup it works fine with just prisma, in fact this example is from the prisms docs.
There is no need to have IDs on embedded documents,they are stored as just a json object on the document.There is no referencing or relationship needed.
Here is an example:
const newOrder = await prisma.order.create({
data: {
// Relation (via reference ID)
product: { connect: { id: 'some-object-id' } },
color: 'Red',
// Embedded document
shippingAddress: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
},
})
I will see if I can manually update the generated schema to show what I would expect the output to be.
I will see if I can manually update the generated schema to show what I would expect the output to be.
Yes please, that would definitely help!
Hopefully this helps.
So I added
type Address {
street: String
city: String
state: String
zip: String
}
type Photo {
height: Int
width: Int
url: String
}
input AddressInput {
street: String
city: String
state: String
zip: String
}
input PhotoInput {
height: Int
width: Int
url: String
}
Then I updated all the address
fields and photo
fields to use the inputs, except for the user type, which uses the regular Address
type.
input UserWhereInput {
OR: [UserWhereInput]
NOT: [UserWhereInput]
AND: [UserWhereInput]
id: StringFilter
email: AWSEmailFilter
name: StringFilter
photo: PhotoInput
address: AddressInput
createdAt: AWSDateTimeFilter
updatedAt: AWSDateTimeFilter
}
type User {
id: String!
email: AWSEmail!
name: String
photo: Photo
address: Address
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
That seems to work?
it maybe a little more complex than this actually.
You can specify a set
when you want to just update a single value in the embedded object
So I think the schema would be something like
type Address {
street: String
city: String
state: String
zip: String
}
input AddressInput {
street: String
city: String
state: String
zip: String
}
input AddressInputWithSet {
street: String
city: String
state: String
zip: String
set: AddressInput
}
input PhotoInput {
height: Int
width: Int
url: String
}
input PhotoInputWithSet {
height: Int
width: Int
url: String
set: PhotoInput
}
Here is the prisma typescript for reference
export type AddressNullableCreateEnvelopeInput = {
set?: AddressCreateInput | null
}
export type AddressCreateInput = {
street: string
city: string
zip: string
}
I also need this feature since we heavily rely on MongoDB in production. Is anyone working on this atm? I can open a PR
@giovanni-orciuolo I don't have experience with MongoDB, so PRs are more than welcomed on this one!