Nahuel Castro
La verdad que la forma de explicar es bastante desordenada. No hay estructura, no se explica muchas veces de dónde y por qué vienen los conceptos. Es muy difícil de seguirlo.
Nahuel Castro
La verdad que la forma de explicar es bastante desordenada. No hay estructura, no se explica muchas veces de dónde y por qué vienen los conceptos. Es muy difícil de seguirlo.
Jonathan 🦑 Alvarez
Profesor¿Estas obteniendo un error en GraphQL por alguno de los atributos?
. Aunque en una clase posterior los agregamos, tal vez puedas necesitarlo ahora dependiendo si tú query solicita atributos.
. Se le pide a Prisma que incluya atributos: https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#include . Ej:
export async function createAvo(...) { // ... const avo = await orm.avocado.create({ data: { // ... }, include: { attributes: true }, // <--- 👈 }) // ... }
Steve Anthony Luzquiños Agama
Las variables del profesor:
{ "data": { "name": "Lamb Hass Avocado", "price": 1.34, "image": "/images/lamb.jpg", "description": "The Lamb Hass Avocado", "shape": "Obovate", "hardiness": "-2 ºC", "taste": "Great, is an avocado" } }
Cristian Iñiguez
Si intentan hacer una consulta asi:
query Query { avos { id name attributes { description } } }
Tendran el error de Cannot read properties of undefined (reading 'description')
Esto es porque al usar avocado.findMany() no incluye los attributes. Para que se incluyan hay que usar avocado.findMany({ include: { attributes: true } })
Sebastian Delgado
mira mi aporte
Steve Anthony Luzquiños Agama
Jonathan 🦑 Alvarez
ProfesorSteve Anthony Luzquiños Agama
Hola Jonathan, gracias por tu respuesta, pero mira, lo acabo de probar nuevamente y el mismo error. ¿Crees que te serviría si te comparto mi repo de GitHub?
Emmanuel Rodríguez
Matias Gabino Santana Cabrera
Si alguno tiene problemas al levantar querer consultar los 'avos' con un error similar a este 👇🏻 es un problema con el monorepo, si saca la api a un repositorio normal con la configuración del monorepo + config del Repo Api ya la consulta correrá correctamente. Ahora si alguno lo pudo solucionar utilizando el monorepo y quiere postear la solución se agradecerá.
"\nInvalid `context.orm.avocado.findMany()` invocation in\n/Users/.../proyectos/nextjs/nextjs-graphql-fullstack/api/src/modules/avocado/avocado.resolver.ts:14:30\n\n 11 args: unknown,\n 12 context: ResolverContext\n 13 ): Promise<Avocado[]> {\n→ 14 return context.orm.avocado.findMany(\n The table `main.Avocado` does not exist in the current database.",
Josué Hernández
Tengo el mismo error, pero no entiendo muy bien cómo solicionar este problema
Antonio Silva
JHDEZ1108 Pudiste solucionarlo ¿?
Jonathan 🦑 Alvarez
Profesor👉 El código con la versión finalizada de esta clase lo puedes encontrar en la etiqueta 2-queries
Para chequearlo crea un nuevo branch usando:
git checkout -b filtros-queries 2-queries
filtros-queries es el nombre del branch. Puedes usar cualquier otro nombre
José María C. L.
El Teacher comenta que no quiere atar los conceptos a la implementación de la herramienta de turno, lo cual está súper.
Pero si el tipo de orm al final está siendo definido por la interface que nos da prisma... no nos estamos acoplando aún a esa implementación? cómo podemos evitar eso? ah y también, cómo podemos evitar caer en el uso de header interfaces?
Emmanuel Rodríguez
José María C. L.
@roremDev Me agrada cómo lo implementaste. En mi caso estoy usando los ApolloDataSources para proveer el acceso a Prisma, donde prisma es un colaborador inyectado por constructor y solo el PrismaAvocadoRepository (que implementa AvocadoRepository) lo conoce.
Algo que te voy a copiar es tu export type Query = Pick<Account, 'id'> para implementar el patrón specification
https://thinkinginobjects.com/2012/08/26/dont-use-dao-use-repository/
Sebastian Delgado
Para quienes tengan problemas con el findMany() y los atributos, pasen un objeto con el atributo include pidiendo que incluya la asociación de la siguiente manera:
export function findAll(): Promise<Avocado[]> { return prisma.avocado.findMany( { include: { attributes: true } } ) }
Jose Alberto Reyes Quevedo
Para crear un avocado y que regrese los attributes, la función de createAvo se tendría que ver así
export function createAvo( parent: unknown, { data, }: { data: Pick<Avocado, 'name' | 'price' | 'image'> & Attributes }, context: ResolverContext, ): Promise<Avocado> { const { name, price, image, ...attributes } = data; return context.orm.avocado.create({ data: { name, price, image, sku: Date.now().toString(36) + Math.random().toString(36).substring(2), attributes: { create: attributes, } }, include: { attributes: true, } }); }
José Luis Encastin Flores
¿Cómo hizo el profe lo del minuto 15:19, es algun pluggin o así?
¿A alguien le sale este error?
Error getting all the avocados PrismaClientKnownRequestError: Invalid orm.avocado.findMany() invocation in /home/anthony/Development/Platzi/GraphQL/apollo/api/src/graphql/models/avocado/queries.ts:9:30 6 { orm }: ResolverContext 7 ): Promise<Avocado[]> => { 8 try { 9 return await orm.avocado.findMany( The table `main.Avocado` does not exist in the current database.
El código que tengo es el siguiente:
const getAllAvocados = async ( parent: unknown, args: unknown, { orm }: ResolverContext ): Promise<Avocado[]> => { try { return await orm.avocado.findMany() } catch (error) { console.error('Error getting all the avocados') console.error(error) throw error } }
Hola hola Steve! . Según este error:
The table `main.Avocado` does not exist in the current database
. Diría que la base de datos no existe/ está lista. Revisa la configuración de Prisma y luego corres: .
npx prisma migrate dev
Clean Architecture
.
📚 Repositorio
. Para esta sección, en vez de utilizar los Data sources, desarrollo una abstracción mediante el patrón MVC (Model-View-Controller). Para ello defino la siguiente estructura de trabajo:
src └─⫸ controllers │ └─⫸ Account.controller.ts └─⫸ graphql │ └─⫸ schemas │ └─⫸ Account.schema.ts └─⫸ models └─⫸ Account └─⫸ Account.entity.ts └─⫸ Account.model.ts
Partiendo de la capa del modelo tenemos que:
Un modelo define la capa de definición y abstracción a la información.
.
export interface Account { id: number email: string password: string } export type Query = Pick<Account, 'id'> export type Payload = Pick<Account, 'email' | 'password'>
export default class AccountModel extends Model<Account, Query, Payload> { /** * @private * @description Prisma ORM definition handler library. */ private client = new Prisma('account') /** * @description Find an account by id. * @param {Query} query * @returns Account */ async findUnique(query: Query): Promise<Account> { return await this.client.findUnique({ where: query, }) } // More code ... }
Para el controlador tenemos que:
Un controlador gestiona y administra el acceso a los datos, así como la secuencia necesaria para su manipulación basadas en las reglas de negocio.
.
import Error from '@controllers/Error.controller' import Account from '@models/Account/Account.model' import { Query, Payload } from '@models/Account/Account.entity' export default class AccountController { private model = new Account() /** * @description Find an account by id. * @param {Query} query * @returns Account */ async findAccount(query: Query) { const account = await this.model.findUnique({ id: Number(query.id), }) if (!account) throw new Error('NOT_FOUND') return account } // More code ... }
Por último, el esquema la defino como su puente o límite mediante prototipos:
import { gql } from 'apollo-server' import { Query, Payload } from '@models/Account/Account.entity' import AccountController from '@controllers/Account.contoller' const accountController = new AccountController() export default { Schema: gql` type Account { id: ID! email: String! password: String! } input CreateAccount { email: String! password: String! } extend type Query { account(id: ID!): Account! accounts: [Account!]! } `, Query: { account: async (_: any, query: Query) => { return await accountController.findAccount(query) }, accounts: async () => { return await accountController.findAccounts() }, }, Mutation: { createAccount: async (_: any, { account }: { account: Payload }) => { validate(account) return await accountController.createAccount(account) }, }, }
Hola 👋 . En mi opinión, he desarrollado los proyectos desde el enfoque Clean Architecture implementando la arquitectura MVC. En este caso, los resolver se comunican a los Controladores, los cuales poseerán las reglas de negocio con los que se operará. . 📚 Repositorio . Un ejemplo de mi controlador en este curso es:
export default class AccountController { // Code definitions ... /** * @description Find an account by id. * @param {Query} query * @returns Account */ async findAccount(query: Query) { const account = await this.model.findUnique({ id: Number(query.id), }) if (!account) throw new Error('NOT_FOUND') return account } // Code definitions ... }
Para el caso del model, sugiero definir entidades con modelos descentralizados.
// Account.entity.ts export interface Account { id: number email: string password: string } export type Query = Pick<Account, 'id'> export type Payload = Pick<Account, 'email' | 'password'>
export default class AccountModel extends Model<Account, Query, Payload> { // Code definitions ... /** * @description Find an account by id. * @param {Query} query * @returns Account */ async findUnique(query: Query): Promise<Account> { return await this.client.findUnique({ where: query, }) } // Code definitions ... }
Donde el modelo, permite trabajar desconociendo el ORM porque al final, tu defines una abstracción intercambiable:
export default class Model<TModel, TQuery, TPayload> { findUnique(query: TQuery): Promise<TModel> { throw new Error('Method not implemented.') } // Code definitions ... }