How to use enum in both Prisma model and Nestjs GraphQL SDL first - enums

I'm using Prisma in NestJS GraphQL SDL first app. Prisma model lokks like;
enum Continent {
Asia
Europe
America
Africa
}
model Country {
id Int #id #default(autoincrement())
name String #unique()
continent Continent #map("continent")
City City[]
population Int?
treaties CountryTreaty[]
##map("country")
}
When I run the Prisma migration, it creates Country table with continent field of Continent type very nicely.
My country.graphql schema is like;
enum Continent {
Asia
Europe
America
Africa
Australia
}
type Country {
id: Int!
name: String!
population: Int
cities: [City!]
treaties: [Treaty!]
capital: City
continent: Continent!
abbr: String
}
and generated typings.ts is like;
export enum Continent {
Asia = "Asia",
Europe = "Europe",
America = "America",
Africa = "Africa",
Australia = "Australia"
}
export class Country {
id: number;
name: string;
population?: Nullable<number>;
cities?: Nullable<City[]>;
treaties?: Nullable<Treaty[]>;
capital?: Nullable<City>;
continent: Continent;
abbr?: Nullable<string>;
}
My country service has findAll method which uses Prisma service;
async findAll(name?: string) {
if (name) {
return await this.prisma.country.findMany({
where: {
name: {
contains: name,
},
},
});
} else {
return await this.prisma.country.findMany();
}
}
Finally, query resolver is;
#Query()
async countries(
#Args('name', { nullable: true }) name?: string,
): Promise<Country[]> {
return await this.countryService.findAll(name);
}
At this point, countries resolver complains about the Continent enum;
Type 'import("E:/git/dev.to/hotchocolate-apollo-federation/country-subgraph/node_modules/.prisma/client/index").Country[]' is not assignable to type 'import("e:/git/dev.to/hotchocolate-apollo-federation/country-subgraph/src/graphql").Country[]'.
Type 'import("E:/git/dev.to/hotchocolate-apollo-federation/country-subgraph/node_modules/.prisma/client/index").Country' is not assignable to type 'import("e:/git/dev.to/hotchocolate-apollo-federation/country-subgraph/src/graphql").Country'.
Types of property 'continent' are incompatible.
Type 'import("E:/git/dev.to/hotchocolate-apollo-federation/country-subgraph/node_modules/.prisma/client/index").Continent' is not assignable to type 'import("e:/git/dev.to/hotchocolate-apollo-federation/country-subgraph/src/graphql").Continent'.ts(2322)
Apparently, the two continents, in prisma client and in generated graphql.ts are not assignable each other!
What should I do differently not to make the resolver complain about this Continent enum?

Related

PetUncheckedCreateInput and PetCreateInput type Error in prisma

I have 2 schema like so:
model Owner {
id Int #id #default(autoincrement())
name String? #unique
pets Pet[]
}
model Pet {
id Int #id #default(autoincrement())
name String? #unique
author Owner #relation(fields: [ownerId], references: [id])
ownerId Int
}
Now, I want them to be like an owner can have 0 pets, or the pet field can be null when I create owner but when a pet is created it has to have a ownerId.
createOwnerInput DTO
export class CreateOwnerInput {
#IsAlpha()
#Field()
name: string
}
owner.resolver.ts(I'm using GraphQL and Nest.js)
#Mutation(() => Owner)
createOwner(#Args('createOwnerInput') createOwnerInput: CreateOwnerInput): Promise<OwnerType> {
return this.ownersService.create(createOwnerInput);
}
owner.service.ts
create(data: Prisma.OwnerCreateInput): Promise<Owner> {
return this.prisma.owner.create({ data })
}
Prisma.OwnerCreateInput
type OwnerCreateInput = {
name?: string | null
pets?: PetCreateNestedManyWithoutOwnerInput
}
This works fine. I can use the Prisma.OwnerCreateInput and it creates the owner with a null value.
I tried to do the same thing but with pets this time and passing the ownerId
CreatePetInput DTO
#IsAlpha()
#Field()
name: string
#Field()
ownerId: number
}
The ownerId is required while creating a pet.
pets.resolver.ts
#Mutation(() => Pet)
createPet(#Args('createPetInput') createPetInput: CreatePetInput): Promise<PetType> {
return this.petsService.create(createPetInput)
pets.service.ts
async create(data: Prisma.PetUncheckedCreateInput): Promise<Pet> {
console.log("Data:", data)
return await this.prisma.pet.create({ data })
}
Prisma.PetUncheckedCreateInput
export type PetUncheckedCreateInput = {
id?: number
name?: string | null
ownerId?: number | null
}
When I try to create a pet, I get the following error.
Unknown arg `ownerId` in data.ownerId for type PetCreateInput. Did you mean `Owner`? Available args:
type PetCreateInput {
name?: String | Null
Owner?: OwnerCreateNestedOneWithoutPetsInput
}
I replace Prisma.PetUncheckedCreateInput with Prisma.PetCreateInput
and make the modifications in my pets.resolver.ts like so:
#Mutation(() => Pet)
createPet(#Args('createPetInput') createPetInput: CreatePetInput): Promise<PetType> {
let data = {
name: createPetInput.name,
Owner: {
connect: {
id: createPetInput.ownerId
}
}
}
return this.petsService.create(data)
}
I get this error:
Unknown arg `Owner` in data.Owner for type PetUncheckedCreateInput. Did you mean `ownerId`? Available args:
type PetUncheckedCreateInput {
id?: Int
name?: String | Null
ownerId?: Int | Null
}
This is my mutation query
mutation {
createPet(createPetInput: {
name: "Zulu"
ownerId: 14
}) {
id name
}
}

graphql prisma query get artists who has song track

I have three table, artist, album and track. I want to query artist who have at least one song track.
Here is my graphql prisma schema. May I know how write the query?
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl"]
}
generator typegraphql {
provider = "typegraphql-prisma"
emitTranspiledCode = true
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model Artist {
id String #id #default(cuid())
name String #unique #db.VarChar(255)
bio String? #db.VarChar(1024)
profile_picture String #db.VarChar(512)
albums Album[]
tracks Track[]
active Boolean #default(true)
user User #relation(fields: [user_id], references: [id])
user_id String
created_at DateTime #default(now())
updated_at DateTime? #updatedAt
##map("artists")
}
model Album {
id String #id #default(cuid())
title String #db.VarChar(255)
album_cover String #db.VarChar(512)
description String? #db.VarChar(5120)
released Int #default(1900)
artists Artist[]
genres Genre[]
tracks Track[]
active Boolean #default(true)
user User #relation(fields: [user_id], references: [id])
user_id String
created_at DateTime #default(now())
updated_at DateTime? #updatedAt
##map("albums")
}
model Track {
id String #id #default(cuid())
title String #db.VarChar(255)
description String? #db.VarChar(5120)
lyric String? #db.LongText
mp3_url String #db.VarChar(1024)
youtube_url String #db.VarChar(1024)
band String? #db.VarChar(255)
duration Int #default(0)
artists Artist[]
album Album #relation(fields: [album_id], references: [id])
album_id String
songWriters SongWriter[]
active Boolean #default(true)
user User #relation(fields: [user_id], references: [id])
user_id String
created_at DateTime #default(now())
updated_at DateTime? #updatedAt
##map("tracks")
}
Here is Resolver
import { Resolver, ArgsType, Field, Args, Query, Ctx, ObjectType,
Int } from "type-graphql";
import { Artist } from "#generated/type-graphql";
import { Context } from "../interfaces";
#ArgsType()
export class ArtistArgs {
#Field((type) => Int, { nullable: false })
page!: number;
#Field((type) => Int, { nullable: false })
take!: number;
}
#ObjectType()
export class ArtistResponse {
#Field(type => [Artist])
artists: Artist[] =[];
#Field((type) => Int, { nullable: false })
total!: number;
}
#Resolver()
class ArtistResolver {
//#Authorized("ADMIN")
#Query((returns) => ArtistResponse, { nullable: true })
async getArtists(#Ctx() { req, res, prisma }: Context, #Args()
{ page, take }: ArtistArgs): Promise<ArtistResponse | null> {
const artists = (await prisma.artist.findMany({
take: take,
skip: (page - 1) * take,
orderBy: [
{
name: "asc"
}
]
}));
const count = (await prisma.artist.count({
}));
return {artists: artists, total: count};
}
}
export default ArtistResolver;
This is like my answer in Prisma js ORM - how to filter for results that have entry in a related table (effectively JOIN)?
To get only Artists that have at least one Track, you should use some and specify a condition that always return true for any related record that exists.
And if you want to your query includes related Tracks you must specify it in include property.
await prisma.artist.findMany({
where: {
tracks: {
some: {
id: { not: "" } // It always should be true.
},
},
},
// if you want to include related tracks in returned object:
include: {
tracks: true,
},
});
You can use prisma OR and gt to filter artist who have at least one song track.
OR accept an arrary of conditions that must return true, while gt means value must be greater than x.

Get other related records (with id different that queried)

As a newbie to GraphQL I would appreciate some help in the following:
I have query which retrieves its author and that author's books. I would like the author's books to be author's other books, meaning - except the one being queried. What does it involve?
apollo-angular query:
const getBookQuery = gql`
query($id: ID){
book(id: $id){
id
name
year
author {
id
firstName
lastName
books { # <-- give me all _except_ the one with $id
name
year
id
}
}
}
}
`;
and in the schema.js (node.js server) I have something like:
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: { id: { type: GraphQLID } },
resolve(parent, args) {
const { id } = args;
return Book.findById(id);
},
},
books: {
type: GraphQLList(BookType),
resolve() {
return Book.find({});
},
},
// ... other queries ...
}
})
The solution I am looking for should, obviously, not break other queries for books.
You should be able to achieve the exclusion by adding an argument to the Author type def and then appropriately using that argument in the resolver for books (which should be nested resolver on your Author type). Will need to adapt syntax for apollo-angular.
type Author {
id:
firstName: String
lastName: String
books(exclude: ID): [Book]
}
const resolverMap = {
Query: {
book(arent, args, ctx, info) {
...
}
},
Author: {
books(obj, args, ctx, info) {
// Use args.exclude passed to filter results
},
},
};
const getBookQuery = gql`
query($id: ID){
book(id: $id){
id
name
year
author {
id
firstName
lastName
books(exclude: $id) {
name
year
id
}
}
}
}
`;

Is it possible to fetch data from multiple tables using GraphQLList

In GraphQL we can write the object type in GraphQLList and fetch all the fields. I am using Association and it is joining the two tables but I am unable to fetch the field of both the tables. It only takes the fields what I have written in GraphQLList.As I want the list of data.
Here is the code
films table:
module.exports =(sequelize, DataTypes) => {
const films = sequelize.define(
'films',
{
id:{
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
},
name: {
type: DataTypes.STRING,
},
},
);
films.associate = (models) => {
films.hasMany(models.movie_stream, {
foreignKey: 'movie_id',
});
};
return films;
}
movie_stream table:
module.exports = (sequelize, DataTypes) => {
const movie_streams = sequelize.define('movie_streams', {
id:{
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
},
movie_id: {
type: DataTypes.STRING,
foreignKey: "movie_id",
},
});
movie_streams.associate = (models) => {
movie_streams.hasMany(models.films, {
foreignKey: 'id',
});
};
return movie_streams;
};
Schema file:
movieList:{
type: new GraphQLList(Films),
resolve: (parent,args)=>{
return newdb.films.findAll({attributes:['id','name','permalink'],
where: {content_category_value:parent.id },
include: [{
model:newdb.movie_stream,
attributes:['id','movie_id'],
}],
}).then(data=>{
return data;
})
}
Can I write here type: new GraphQLList(Films, MovieStream)??
I have tried but It does not work. Please give me some idea how do I fetch the fields of both the table???
There's two main ways of achieving this in GraphQL: unions and interfaces.
An interface is where two or more object types in your GraphQL schema share certain fields (characteristics). For example you might have a Product interface for all the items in your shop, where every product has a price, barcode, and shelfLocation. All your products, such as Shampoo, Bread, LawnChair would then implement this interface.
interface Product {
price: Float
barcode: Int
shelfLocation: ShelfLocation
}
type Bread implements Product {
price: Float
barcode: Int
shelfLocation: ShelfLocation
brand: String
numberOfSlices: Int
calories: Float
bestBefore: Date
}
extend type Query {
searchProducts(phrase: String!): [Product!]
}
A union is where you declare that something can return more than one object type, but those types don't have to have any properties in common.
type Shark {
name: String
numberOfTeeth: Int
}
type Shoe {
brand: String
size: String
}
union SharkOrShoe = Shark | Shoe
extend type Query {
searchSharksAndShoes(phrase: String!): [SharkOrShoe!]
}
In both cases you can query type specific fields using fragments or inline fragments:
query {
searchProducts(phrase: "tasty") {
# shared fields
__typename
price
barcode
shelfLocation { aisle, position }
# type specific fields
... on Bread { brand }
...breadFrag
}
searchSharksAndShoes(phrase: "sleek") {
# only the introspection fields are shared in a union
__typename
# type specific fields
... on Shark { name, numberOfTeeth }
...shoeFrag
}
}
fragment breadFrag on Bread {
barcode
bestBefore
}
fragment shoeFrag on Shoe {
brand
size
}
You can learn more about this in the GraphQL schema documentation and read about GraphQLInterfaceType and GraphQLUnionType in the GraphQL.js documentation.

Write resolvers for nested type definitions

Suppose I have following type definition for my GraphQL API:
const typeDef = `
type Book {
title: String
author: Author
likes: Int
}
type Author {
id: String
name: String
age: Int
books: [Book]
}
type Query{
books(authorid: String!): Book
}
`
Then, how many resolvers do I need for this? Should I handle this query request with only one resolver books and return all books and author info or should I make many resolvers such as Query -> books, Book -> author and Author -> books? I am not sure how the modular schema and resolver works together.
No matter how many type(Book, Author etc) or input you use you need to provide .
const schema = `
type Mutation {
mutatePost(postId:Int) :Int
}
type Query {
hello: String
posts: [String]
books(authorId: String!): Book
}
`
You need to use same name as you defined in Query must be same in resolver
const resolvers = {
Query: {
async hello() {
return 'Hello';
},
async posts() {
return ['Hello', 'World];
},
async books(_, { authorId }) {
//Return data which you is defined in type Book
//return Book
}
},
Mutation: {
async mutatePost(_, {
postId
}, context) {
//return Integer
}
},
}
Only thing every Query and Mutation need queryResolver and mutationResolver

Resources