Crea una cuenta o inicia sesión

¡Continúa aprendiendo sin ningún costo! Únete y comienza a potenciar tu carrera

Resolvers para mutaciones y filtros

7/23
Recursos

Aportes 11

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Es imposible aprender, en cada clase hay codigo y archivos nuevos, porque no te pones a programar todo de cero, la idea es aprender a estructurar y saber como funcionan estas tecnologias

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.

¿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 }, // <--- 👈
  })
  // ...
}

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"
  }
}

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 } })

Clean Architecture

.

<h5>📚 Repositorio</h5>

.
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)
        },
    },
}

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.",

👉 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

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 }
    }
  )
}

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,
    }
  });
}

¿Cómo hizo el profe lo del minuto 15:19, es algun pluggin o así?