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.
Related
I'm playing around with TypeGraphQL and have a simple api setup to query projects and their associated clients.
For my createClient mutation, I'm receiving an ArgumentValidation Error, 'an unknown value was passed to the validate function' and can't pinpoint whats going wrong.
Client Schema
import { ObjectType, Field, ID } from "type-graphql";
#ObjectType()
class ClientSchema {
#Field(type => ID)
id: string
#Field()
name: string
#Field()
email: string
#Field()
phone: string
}
export default ClientSchema
Client Resolver
import { Arg, Field, InputType, Mutation, Query, Resolver } from "type-graphql";
import exampleClients from "../utils/clients";
import ClientSchema from "../schemas/ClientsSchema";
#InputType()
class CreateClassInput {
#Field()
name: string
#Field()
email: string
#Field()
phone: string
}
#Resolver()
class ClientResolver {
#Query((returns) => [ClientSchema])
async clients() {
return exampleClients;
}
#Query((returns) => ClientSchema)
async client(#Arg("id") id: string) {
const client = exampleClients.find((client) => client.id === id);
if (!client) throw new Error("No such client");
return client;
}
#Mutation((returns) => ClientSchema)
async createClient(#Arg("data") createClassData: CreateClassInput) {
const { name, email, phone } = createClassData;
const newClient: ClientSchema = {
id: String(exampleClients.length + 1),
name,
email,
phone
};
exampleClients.push(newClient);
return newClient;
}
}
export default ClientResolver;
GraphQL Query
mutation createClient {
createClient(data: { name: "Test Name", email: "Test Email", phone: "Test phone" }) {
name
}
}
If i pass the arguments to the mutation directly, without de-structuring an object, I don't get the error however with it I do. Is there something I'm doing wrong?
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
}
}
I tried to create track record the have one to many relation with user table and I got the following error.
An operation failed because it depends on one or more records that were required but not found. No 'User' record(s) (needed to inline the relation on 'Track' record(s)) was found for a nested connect on one-to-many relation 'TrackToUser'."
I want who is created this record. So that I added the track to user as following in my schema.
I can create artist and album record.
May I know why I got this issue.
model Genre {
id String #id #default(cuid())
name String #unique #db.VarChar(255)
albums Album[]
##map("genres")
}
model SongWriter {
id String #id #default(cuid())
name String #unique #db.VarChar(255)
tracks Track[]
##map("songwriters")
}
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)
mp3_url String #db.VarChar(1024)
youtube_url String #db.VarChar(1024)
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")
}
model User {
id String #id #default(cuid())
name String #unique #db.VarChar(255)
password String #db.VarChar(512)
profile_picture String? #db.VarChar(512)
role Role #default(USER)
tokenVersion Int #default(0)
artists Artist[]
albums Album[]
tracks Track[]
active Boolean #default(true)
created_at DateTime #default(now())
updated_at DateTime? #updatedAt
##map("users")
}
I have tried to create a Track record and all has worked properly, here you go the code snippet (I do not know if it is what you want):
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const saveData = async () => {
const user = await prisma.user.create({
data: {
name: 'The Best User',
password: '123456',
profile_picture: 'https://www.example.com/user.jpg',
tokenVersion: 1,
}
})
console.log('USER', user)
const gnre = await prisma.genre.create({
data: {
name: 'The Best Genre',
}
})
console.log('GENRE', gnre)
const album = await prisma.album.create({
data: {
title: 'The Best Album',
album_cover: 'https://www.example.com/album.jpg',
description: 'This is the best album ever',
released: 1,
active: true,
user: {
connect: {
id: user.id
}
},
genres: {
connect: {
id: gnre.id
}
}
}
})
console.log('ALBUM', album)
const artist = await prisma.artist.create({
data: {
name: 'The Best Artist',
bio: 'The best artist ever',
profile_picture: 'https://www.example.com/artist.jpg',
active: true,
user: {
connect: {
id: user.id
}
}
}
})
console.log('ARTIST', artist)
const songWriter = await prisma.songWriter.create({
data: {
name: 'The Best Song Writer',
}
})
console.log('SONG WRITER', songWriter)
const track = await prisma.track.create({
data: {
title: 'The Best Track',
description: 'The best track ever',
mp3_url: 'https://www.example.com/track.mp3',
youtube_url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
duration: 1000,
active: true,
artists: {
connect: {
id: artist.id
}
},
album: {
connect: {
id: album.id
}
},
user: {
connect: {
id: user.id
}
},
songWriters: {
connect: {
id: songWriter.id
}
}
},
include: {
artists: true,
album: true,
user: true,
songWriters: true,
}
})
console.log('TRACK')
console.log(JSON.stringify(track, null, 2));
}
saveData()
Here you go the result:
When the createComment Mutation was excuted, an error called Invalid 'prisma.comment.create()' invocation:
I don't know what's wrong with this right now.๐ข
I use OSX and postgresql
schema.prisma
model User {
userId Int #id #default(autoincrement())
fullName String
username String #unique
avatar String?
email String #unique
password String
phoneNumber String #unique
location String?
searchHistoryOnOff Boolean #default(true)
notificationOnOff Boolean #default(true)
notifications Notification[]
searchHistories SearchHistory[]
products Product[]
comments Comment[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
model Product {
id Int #id #default(autoincrement())
authorId Int
title String
price Int
picture String[]
content String?
hits Int #default(0)
author User #relation(fields: [authorId], references: [userId])
hashtags Hashtag[]
comments Comment[]
createdAt DateTime #default(now())
updated
}
model Comment {
id Int #id #default(autoincrement())
authorId Int
productId Int
comment String
author User #relation(fields: [authorId], references: [userId])
product Product #relation(fields: [productId], references: [id])
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
typeDefs
import { gql } from 'apollo-server-express';
export default gql`
type Mutation {
createComment(productId: Int!, commment: String!): MutationResponse!
}
`;
resolvers
import { Comment } from '#prisma/client';
import { protectedResolver } from '../../users/user.utils';
import { Identity, Resolvers } from './../../types.d';
const resolvers: Resolvers = {
Mutation: {
createComment: protectedResolver(
async (_, { productId, comment }, { loggedInUser, client }) => {
const { userId } = loggedInUser;
const product: Identity = await client.product.findUnique({
where: { id: productId },
select: { id: true },
});
if (!product) {
return {
ok: false,
error: '๊ฒ์๊ธ์ด ์กด์ฌํ์ง ์์',
};
}
const newComment: Comment = await client.comment.create({
data: {
comment,
author: {
connect: { userId },
},
product: {
connect: { id: productId },
},
},
});
return { ok: true };
}
),
},
};
export default resolvers;
Please help me ๐ญ๐ญ
I have the following datamodel:
type Tvshow {
id: ID! #unique
title: String!
pricing: [Pricing]
startDate: DateTime!
endDate: DateTime!
subscribers: [Tvshowsubscription!]
.....
}
type FavoriteTvshow {
id: ID! #unique
tvshow: Tvshow!
user: User!
}
type User {
id: ID! #unique
name: String
email: String! #unique
password: String
googleID: String #unique
resetToken: String
resetTokenExpiry: String
permissions: [Permission]
address: Address
phone: String
favorites: [FavoriteTvshow!]
tvshowSubscriptions: [Tvshowsubscription!]
}
I have my custom Tvshow resolver using addFragmentToInfo:
resolver-queries.js
const Query = {
...
favoriteTvshows: forwardTo('db'),
tvshow: (parent, args, ctx, info) => {
const fragment = `fragment EnsureComputedFields on Tvshow { pricing { minQuantity maxQuantity unitPrice} subscribers { id }}`
return ctx.db.query.tvshow({}, addFragmentToInfo(info, fragment))
},
....
};
tvshow-resolver.js
const Tvshow = {
countSubscribers: (parent) => {
return parent.subscribers.length;
},
}
This is an example, I have more computed fields for Tvshow
I can query Tvshows with countSubscribers, It works fine doing something like this:
query SINGLE_TVSHOW_QUERY($id: ID!) {
tvshow(where: { id: $id }) {
id
title
pricing {
minQuantity
maxQuantity
unitPrice
}
startDate
endDate
countSubscribers
}
}
But what I want to do is to get all the favorite Tvshows from an user returning the countSubscribers, a query for that could be something like this:
query FAVORITES_FROM_USER($userId: ID!) {
favoriteTvshows(where: { user: {id: $userId} }) {
tvshow {
id
title
startDate
endDate
countSubscribers
}
}
}
The problem is that when I query this, in the tvshow-resolver.js I mentioned before, the parent doesnโt have any subscribers object
The error was very silly but I will post it anyway. I needed subscribers in the query
query FAVORITES_FROM_USER($userId: ID!) {
favoriteTvshows(where: { user: {id: $userId} }) {
tvshow {
id
title
startDate
endDate
subscribers { <---
id
quantity
}
countSubscribers
}
}
}
That way the parent in tvshow-resolver.js will have subscribers object