Skip to content

Commit 2722e74

Browse files
authored
Mejor DX :) (#23)
1 parent ff25561 commit 2722e74

29 files changed

+278
-2381
lines changed

.dev.vars.example

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
DATABASE_URL=""
2+
DATABASE_TOKEN=""
3+
CLERK_PEM_PUBLIC_KEY=""
4+
CLERK_ISSUER_ID=""
5+
ENFORCED_JWT_TOKEN=""

.eslintrc.cjs

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ module.exports = {
5050
"plugin:@graphql-eslint/operations-recommended",
5151
],
5252
parserOptions: {
53-
schema: "http://127.0.0.1:8787/graphql",
53+
schema: "./src/generated/schema.graphql",
5454
operations: ["./src/tests/**/*.gql", "./src/tests/**/*.graphql"],
5555
},
5656
rules: {
@@ -87,6 +87,7 @@ module.exports = {
8787
"/.husky",
8888
"/.yarn",
8989
"/*/dist",
90+
"./src/generated",
9091
"src/@types/schema.generated.ts",
9192
],
9293
};

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.vscode
1+
.vscode/settings.json
22
.yalc
33
yalc.lock
44

.vscode/extensions.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"recommendations": [
3+
"dbaeumer.vscode-eslint",
4+
"esbenp.prettier-vscode",
5+
"GraphQL.vscode-graphql",
6+
"GraphQL.vscode-graphql-syntax"
7+
]
8+
}

README.md

+86-34
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,27 @@
33
- Asegurate de tener el archivo .dev.vars (Pídele al equipo los valores correspondientes.)
44
- Puedes correr una BDD local si te parece.
55
- Para correr el proyecto con las BDD de desarrollo, tienes que agregar un archivo `.dev.vars` con los valores de las mismas.
6-
- Preguntale al equipo por los valores de la BDD, (o crea tu propia BDD en [turso.tech](https://turso.tech/))
7-
- Pide las llaves de autenticacion para clerk
8-
- Agregala a .dev.vars bajo `CLERK_PEM_PUBLIC_KEY` y `CLERK_ISSUER_ID`
6+
- Crear una base de datos en turso.tech
7+
- Instala el CLI de turso [acá](https://github.com/tursodatabase/turso-cli)
8+
- Authentícate con `turso auth login`
9+
- Crea una base de datos con `turso db create NOMBRE_DE_TU_BDD`
10+
- Obten la TOKEN de tu DB con `turso db tokens create NOMBRE_DE_TU_BDD`
11+
- Obten la URL de tu DB con `turso db tokens list`
12+
- Guarda la URL de tu BDD y la token en el archivo .dev.vars bajo `DATABASE_URL` y `DATABASE_TOKEN`
913
- Finalmente, `npm i` & `num run dev`
10-
11-
# Cómo contribuir al proyecto
12-
13-
- Si buscas una feature nueva, sugiérela creando un issue [acá](https://github.com/JSConfCL/gql_api/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
14-
- Haz un fork del repositorio y crea una nueva rama para tu funcionalidad o corrección.
15-
- Realiza tus cambios, y escribe pruebas que cubran el nuevo código.
16-
- Envía una solicitud de pull.
14+
- Listo! Tu servidor GraphQL está corriendo en http://127.0.0.1:8787
1715

1816
# Cómo escribir tests
1917

18+
> PSA: Los tests se corren con `npm run tests` (o `npm run test:interactive` si quieres explorar una UI con mas informacion)
19+
2020
## Preparación del entorno de prueba
2121

22-
Antes de empezar a escribir tus tests, asegúrate de tener un entorno de prueba adecuado. Puedes necesitar borrar y recrear la base de datos antes de cada test para asegurarte de que los datos de un test no afecten a los demás. En nuestros ejemplos, usamos la función clearDatabase() en el hook afterEach() para lograr esto.
22+
> La expectativa de nuestros tests, es que cada archivo de tests pueda correr en paralelo (y aislados) el uno del otro.
23+
> Por lo mismo, creamos una base de datos nueva antes de correr cada test.
24+
> Para asegurarte de que esto tambien ocurra entre tests del mismo archivo, recuerda poner en tu archivo de tests,
25+
> un hook `afterEach` que limpie la base de datos.
26+
> (En nuestros ejemplos, usamos la función clearDatabase() en el hook afterEach() para lograr esto.)
2327
2428
## Escribir la query o mutación
2529

@@ -40,8 +44,13 @@ query getUsers {
4044
## Generar código
4145

4246
Para poder correr los test, necesitamos tener funciones y variables en JavaScript/Typescript, no en "graphql".
47+
Podríamos escribir la query o mutación, como un string, directamente en un archivo `.ts`. Pero eso es tedioso, propenso a errores, y no nos da autocompletado.
48+
49+
Para evitar esto, usamos un generador de código, que nos permite escribir la query o mutación en un archivo `.gql`, y luego generar el código asociado a esta operación de graphql.
50+
4351
Usaremos el archivo `.gql` que creamos recien, y correremos el comando `npm run generate`.
44-
Esto generará codigo y tipos asociados a esta operación de graphql, por ejemplo:
52+
53+
Esto generará codigo y tipos asociados a esta operación de graphql, por ejemplo, la query que definimos arriba, generará el siguiente archivo:
4554

4655
```typescript
4756
/* eslint-disable */
@@ -105,7 +114,8 @@ describe("My Resolver Tests", () => {
105114

106115
## Ejecuta tu query o mutación.
107116

108-
Tenemos un helper para realizar esto, llamado `executeGraphqlOperation`, donde puedes pasar la operación que definiste en el parametro `"document"`.
117+
Tenemos un helper para realizar esto, llamado `executeGraphqlOperation`.
118+
Donde puedes pasar la operación que definiste en el parametro `"document"`.
109119
La query y tipos los debes traer desde tu archivo generado.
110120

111121
Por ejemplo:
@@ -135,6 +145,31 @@ describe("My Resolver Tests", () => {
135145
});
136146
```
137147

148+
## Ejecuta tu query o mutación con otro usuario.
149+
150+
`executeGraphqlOperation` executa la query o mutación de manera anónima.
151+
Para poder executar una query o mutación con un usuario específico, puedes usar el helper `executeGraphqlOperationAsUser`.
152+
Este helper requiere que ademas de un documento/variables, le pases un usuario. como segundo parámetro.
153+
154+
Por ejemplo:
155+
156+
```TSX
157+
const user1 = await insertUser();
158+
const response = await executeGraphqlOperationAsUser<
159+
CreateEventMutation,
160+
CreateEventMutationVariables
161+
>(
162+
{
163+
document: SOME_DOCUMENT,
164+
variables: SOME_VARIABLES,
165+
},
166+
user1,
167+
);
168+
```
169+
170+
> De igual manera, tenemos el helper `executeGraphqlOperationAsAdmin` para ejecutar queries o mutaciones como un admin.
171+
> Es un helper similar a `executeGraphqlOperationAsUser`, con la salvedad que no requiere que le pases un usuario como segundo parámetro, y lo crea por ti.
172+
138173
## Verifica tus respuestas:
139174

140175
Puedes usar métodos assert o expect de [Vitest](https://vitest.dev/api/expect.html)
@@ -166,9 +201,10 @@ describe("My Resolver Tests", () => {
166201

167202
```
168203

169-
## Manejo de errores
204+
### Manejo de errores
170205

171-
Además de verificar que tu resolver devuelve los datos correctos, verifica cómo maneja los errores. Por ejemplo, puedes escribir un test que pase datos incorrectos a tu mutación y luego verificar que la respuesta contiene el error correcto, o que falla donde debería fallar 😀.
206+
Además de verificar que tu resolver devuelve los datos correctos, verifica cómo maneja los errores.
207+
Por ejemplo, puedes escribir un test que pase datos incorrectos a tu mutación y luego verificar que la respuesta contiene el error correcto, o que falla donde debería fallar 😀.
172208

173209
# Migraciones
174210

@@ -177,11 +213,16 @@ Usamos `drizzle` y `drizzle-kit` para manejar conexiones a la BDD, que genera au
177213

178214
## Cómo escribir migraciones?
179215

180-
### 1. Actualiza el esquema.
216+
### 1. Actualiza el esquema de la base de datos.
217+
218+
> AKA. Crea o edita Tablas, Columnas, Indices, etc.
219+
220+
Primero, necesitas actualizar el archivo del esquema en `./src/datasources/db/schema/tables.ts`. (o )
221+
Este archivo define la estructura de las tablas en la BDD.
222+
223+
> Las relaciones entre tablas, se definen en `./src/datasources/db/schema/relations.ts`.
224+
> Los esquemas de query/update se definen en `./src/datasources/db/schema/CRUD.ts`.
181225
182-
Primero, necesitas actualizar el archivo del esquema en `./src/datasources/db/schema.ts`.
183-
Este archivo define la estructura de la base de datos.
184-
Por ejemplo, aquí es donde se definen las tablas y sus campos, así como las relaciones entre las tablas.
185226
Para definir una tabla, utilizas la función `sqliteTable()`, donde el primer argumento es el nombre de la tabla y el segundo es un objeto que define los campos de la tabla.
186227

187228
Por ejemplo:
@@ -195,11 +236,12 @@ export const usersSchema = sqliteTable("users", {
195236
});
196237
```
197238

198-
En este ejemplo, se define una tabla users con varios campos, incluyendo id, name, y bio. Los campos se definen utilizando funciones como text() e integer(), y se pueden agregar opciones adicionales, como unique(), notNull(), y default().
239+
Esto define una tabla users con varios campos, incluyendo id, name, y bio.
240+
Los campos se definen utilizando funciones como text() e integer(), y se pueden agregar opciones adicionales, como unique(), notNull(), y default().
199241

200242
### 2. Genera los archivos de migración.
201243

202-
Una vez que hayas actualizado el esquema, debes generar los archivos de migración. Para hacerlo, ejecuta npx db:generate.
244+
Una vez que hayas actualizado el esquema, debes generar los archivos de migración. Para hacerlo, ejecuta `npx db:generate`.
203245

204246
### 3. Verifica las migraciones:
205247

@@ -211,24 +253,34 @@ Puedes hacer esto corriendo todos los tests. Estos geeneran una BDD desde 0, y c
211253
Finalmente, ejecuta las migraciones con `npm run db:migrate`.
212254
Estos comandos utilizan las variables de entorno definidas en el archivo .dev.vars para conectarse a las BDD de desarrollo.
213255

256+
### 5. Como limpiar tu base de datos:
257+
258+
- conectate a tu bdd con `turso db shell NOMBRE_DE_TU_BDD`
259+
- ejecuta `select 'drop table ' || name || ';' from sqlite_master where type = 'table';` para obtener todas las tablas de tu bdd
260+
- Esto te devolverá un resultado como el siguiente:
261+
```txt
262+
drop table users;
263+
drop table events;
264+
drop table event_attendees;
265+
drop table event_invitations;
266+
drop table event_invitation_tokens;
267+
```
268+
- copia y pega el resultado en tu terminal para eliminar todas las tablas de tu bdd.
269+
- sal de la shell con `.quit`
270+
- Listo! Tu bdd está 100% limpia. 😊
271+
214272
# Requisitos
215273
216274
- Tener un archivo `.dev.vars` con el siguiente contenido
217-
218-
```txt
219-
DATABASE_URL="PREGUNTALE AL EQUIPO POR ESTO"
220-
DATABASE_TOKEN="PREGUNTALE AL EQUIPO POR ESTO"
221-
CLERK_PEM_PUBLIC_KEY="PREGUNTALE AL EQUIPO POR ESTO"
222-
CLERK_ISSUER_ID="PREGUNTALE AL EQUIPO POR ESTO"
223-
```
275+
```txt
276+
DATABASE_URL="PREGUNTALE AL EQUIPO POR ESTO"
277+
DATABASE_TOKEN="PREGUNTALE AL EQUIPO POR ESTO"
278+
CLERK_PEM_PUBLIC_KEY="PREGUNTALE AL EQUIPO POR ESTO"
279+
CLERK_ISSUER_ID="PREGUNTALE AL EQUIPO POR ESTO"
280+
```
224281

225282
> BRO-TIP 🔥
226-
227-
Agrega una variable `ENFORCED_JWT_TOKEN` a tu archivo `.dev.vars`, para utilizarla por defecto en graphiql.
228-
229-
## Como correr tests
230-
231-
- `npm run test`
283+
> Agrega una variable `ENFORCED_JWT_TOKEN` a tu archivo `.dev.vars`, para utilizarla por defecto en graphiql.
232284
233285
# STACK
234286

codegen.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,9 @@ const codeInjection = {
1616

1717
const config: CodegenConfig = {
1818
ignoreNoDocuments: true,
19-
schema: "http://127.0.0.1:8787/graphql",
19+
schema: "./generated/schema.gql",
2020
documents: ["./src/**/*.gql"],
21-
2221
generates: {
23-
"src/generated/schema.json": {
24-
plugins: ["introspection"],
25-
},
2622
"src/generated/types.ts": {
2723
plugins: ["typescript", codeInjection],
2824
},

generated/generate.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {
2+
// printIntrospectionSchema,
3+
printSchema,
4+
} from "graphql/utilities";
5+
import { schema } from "~/schema";
6+
import { writeFile } from "node:fs/promises";
7+
8+
const start = async () => {
9+
const schemaString = printSchema(schema);
10+
await writeFile("./generated/schema.gql", schemaString, "utf-8");
11+
};
12+
13+
// eslint-disable-next-line no-console
14+
start().catch(console.error);

generated/schema.gql

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
enum CommnunityStatus {
2+
active
3+
inactive
4+
}
5+
6+
"""Representation of a Community"""
7+
type Community {
8+
description: String
9+
events: [Event!]!
10+
id: String!
11+
name: String
12+
status: CommnunityStatus!
13+
users: [User!]!
14+
}
15+
16+
"""
17+
A date string, such as 2007-12-03, compliant with the `full-date` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar.
18+
"""
19+
scalar Date
20+
21+
"""
22+
A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar.
23+
"""
24+
scalar DateTime
25+
26+
"""
27+
Representation of an Event (Events and Users, is what tickets are linked to)
28+
"""
29+
type Event {
30+
address: String
31+
community: Community
32+
description: String
33+
endDateTime: DateTime
34+
id: String!
35+
latitude: String
36+
longitude: String
37+
maxAttendees: Int
38+
meetingURL: String
39+
name: String!
40+
startDateTime: DateTime!
41+
status: EventStatus!
42+
tags: [Tag!]!
43+
users: [User!]!
44+
visibility: EventVisibility!
45+
}
46+
47+
input EventCreateInput {
48+
address: String
49+
communityId: String!
50+
description: String!
51+
endDateTime: DateTime
52+
latitude: String
53+
longitude: String
54+
maxAttendees: Int!
55+
meetingURL: String
56+
name: String!
57+
startDateTime: DateTime!
58+
status: EventStatus
59+
timeZone: String
60+
visibility: EventVisibility
61+
}
62+
63+
enum EventStatus {
64+
active
65+
inactive
66+
}
67+
68+
enum EventVisibility {
69+
private
70+
public
71+
unlisted
72+
}
73+
74+
input EventsSearchInput {
75+
id: String
76+
name: String
77+
startDateTimeFrom: DateTime
78+
startDateTimeTo: DateTime
79+
status: EventStatus
80+
visibility: EventVisibility
81+
}
82+
83+
type Mutation {
84+
"""Create an event"""
85+
createEvent(input: EventCreateInput!): Event!
86+
}
87+
88+
type Query {
89+
"""Get a list of communities. Filter by name, id, or status"""
90+
communities(id: String, name: String, status: CommnunityStatus): [Community!]!
91+
92+
"""Get a community by id"""
93+
community(id: String!): Community
94+
95+
"""Get an event by id"""
96+
event(id: String!): Event
97+
98+
"""Get a list of events. Filter by name, id, status or date"""
99+
events(input: EventsSearchInput): [Event!]!
100+
status(name: String): String!
101+
102+
"""Get a list of tags"""
103+
tags(input: TagSearchInput): [Tag!]!
104+
105+
"""Get a list of users"""
106+
users: [User!]!
107+
}
108+
109+
"""
110+
Representation of a tag. Tags can be associated to many things. An event, a community, etc.
111+
"""
112+
type Tag {
113+
description: String
114+
id: String!
115+
name: String
116+
slug: String!
117+
}
118+
119+
input TagSearchInput {
120+
description: String
121+
id: String
122+
name: String
123+
}
124+
125+
"""Representation of a user"""
126+
type User {
127+
communities: [Community!]!
128+
id: String!
129+
name: String
130+
username: String!
131+
}

0 commit comments

Comments
 (0)