feat: prisma integration and initial queries for graphql

This commit is contained in:
Vyacheslav Matyukhin 2022-04-14 23:32:01 +03:00
parent 71ab64343f
commit b02b730ac5
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
6 changed files with 256 additions and 27 deletions

162
package-lock.json generated
View File

@ -11,6 +11,8 @@
"dependencies": {
"@graphql-yoga/node": "^2.1.0",
"@pothos/core": "^3.5.1",
"@pothos/plugin-prisma": "^3.4.0",
"@pothos/plugin-relay": "^3.10.0",
"@prisma/client": "^3.11.1",
"@tailwindcss/forms": "^0.4.0",
"@tailwindcss/typography": "^0.5.1",
@ -2504,6 +2506,32 @@
"graphql": ">=15.1.0"
}
},
"node_modules/@pothos/plugin-prisma": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@pothos/plugin-prisma/-/plugin-prisma-3.4.0.tgz",
"integrity": "sha512-J0uiTNX9cDXzJ64N6Gd7EVUW90bxSr/NrijY41zc5VZqHv/l1JlWmwKJK5qF5CBULlqNIba/KDLZHvszMNAA8A==",
"dependencies": {
"@prisma/generator-helper": "^3.12.0"
},
"bin": {
"prisma-pothos-types": "bin/generator.js"
},
"peerDependencies": {
"@pothos/core": "*",
"@prisma/client": "*",
"graphql": ">=15.1.0",
"typescript": ">4.5.2"
}
},
"node_modules/@pothos/plugin-relay": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/@pothos/plugin-relay/-/plugin-relay-3.10.0.tgz",
"integrity": "sha512-ZNkSYPhDKanMrd8aFD4nEUeMHoeD6wyejBsO1Ik/q8IRHRRPQzLsc/ignxGEl5j+hdu/SsTuhMNszV9Ef0JOJw==",
"peerDependencies": {
"@pothos/core": "*",
"graphql": ">=15.1.0"
}
},
"node_modules/@prisma/client": {
"version": "3.11.1",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-3.11.1.tgz",
@ -2524,6 +2552,40 @@
}
}
},
"node_modules/@prisma/debug": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-3.12.0.tgz",
"integrity": "sha512-MFNsK8jzao3VX+cEP6+txABa3w8bU4gD0QpqTbGS3v3TW1c7TtHvhsmI7xTx9Cll7biuJdaRd3YwG2Fa/CHVmA==",
"dependencies": {
"@types/debug": "4.1.7",
"ms": "2.1.3",
"strip-ansi": "6.0.1"
}
},
"node_modules/@prisma/debug/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/@prisma/debug/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/@prisma/debug/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@prisma/engines": {
"version": "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9.tgz",
@ -2535,6 +2597,17 @@
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9.tgz",
"integrity": "sha512-HkcsDniA4iNb/gi0iuyOJNAM7nD/LwQ0uJm15v360O5dee3TM4lWdSQiTYBMK6FF68ACUItmzSur7oYuUZ2zkQ=="
},
"node_modules/@prisma/generator-helper": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/@prisma/generator-helper/-/generator-helper-3.12.0.tgz",
"integrity": "sha512-wfEcSVUX0HH0A/CIrsecV1CLH3McNCLH2A76UL7QpSX1XLoIDo6SxgMwAfXufNGDhPET6NAoWm8mSmDXJopgrw==",
"dependencies": {
"@prisma/debug": "3.12.0",
"@types/cross-spawn": "6.0.2",
"chalk": "4.1.2",
"cross-spawn": "7.0.3"
}
},
"node_modules/@repeaterjs/repeater": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz",
@ -3000,6 +3073,14 @@
"@types/responselike": "*"
}
},
"node_modules/@types/cross-spawn": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz",
"integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/debug": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types%2fdebug/-/debug-4.1.7.tgz",
@ -4719,7 +4800,6 @@
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
@ -7154,7 +7234,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true,
"license": "ISC"
},
"node_modules/isomorphic-fetch": {
@ -36108,7 +36187,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@ -37752,7 +37830,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@ -37765,7 +37842,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@ -39136,7 +39212,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
@ -41173,6 +41248,20 @@
"integrity": "sha512-xop9VL3JmcF7/wUw79HpY3ulUfmbs57yFHEnxDy6pgZbLbnuaDBjgUrBRfSGSdHyu2jexd72USpgv4y/lD4xow==",
"requires": {}
},
"@pothos/plugin-prisma": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@pothos/plugin-prisma/-/plugin-prisma-3.4.0.tgz",
"integrity": "sha512-J0uiTNX9cDXzJ64N6Gd7EVUW90bxSr/NrijY41zc5VZqHv/l1JlWmwKJK5qF5CBULlqNIba/KDLZHvszMNAA8A==",
"requires": {
"@prisma/generator-helper": "^3.12.0"
}
},
"@pothos/plugin-relay": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/@pothos/plugin-relay/-/plugin-relay-3.10.0.tgz",
"integrity": "sha512-ZNkSYPhDKanMrd8aFD4nEUeMHoeD6wyejBsO1Ik/q8IRHRRPQzLsc/ignxGEl5j+hdu/SsTuhMNszV9Ef0JOJw==",
"requires": {}
},
"@prisma/client": {
"version": "3.11.1",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-3.11.1.tgz",
@ -41181,6 +41270,36 @@
"@prisma/engines-version": "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9"
}
},
"@prisma/debug": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-3.12.0.tgz",
"integrity": "sha512-MFNsK8jzao3VX+cEP6+txABa3w8bU4gD0QpqTbGS3v3TW1c7TtHvhsmI7xTx9Cll7biuJdaRd3YwG2Fa/CHVmA==",
"requires": {
"@types/debug": "4.1.7",
"ms": "2.1.3",
"strip-ansi": "6.0.1"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"requires": {
"ansi-regex": "^5.0.1"
}
}
}
},
"@prisma/engines": {
"version": "3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9.tgz",
@ -41191,6 +41310,17 @@
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.11.1-1.1a2506facaf1a4727b7c26850735e88ec779dee9.tgz",
"integrity": "sha512-HkcsDniA4iNb/gi0iuyOJNAM7nD/LwQ0uJm15v360O5dee3TM4lWdSQiTYBMK6FF68ACUItmzSur7oYuUZ2zkQ=="
},
"@prisma/generator-helper": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/@prisma/generator-helper/-/generator-helper-3.12.0.tgz",
"integrity": "sha512-wfEcSVUX0HH0A/CIrsecV1CLH3McNCLH2A76UL7QpSX1XLoIDo6SxgMwAfXufNGDhPET6NAoWm8mSmDXJopgrw==",
"requires": {
"@prisma/debug": "3.12.0",
"@types/cross-spawn": "6.0.2",
"chalk": "4.1.2",
"cross-spawn": "7.0.3"
}
},
"@repeaterjs/repeater": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz",
@ -41453,6 +41583,14 @@
"@types/responselike": "*"
}
},
"@types/cross-spawn": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz",
"integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==",
"requires": {
"@types/node": "*"
}
},
"@types/debug": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types%2fdebug/-/debug-4.1.7.tgz",
@ -42758,7 +42896,6 @@
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@ -44475,8 +44612,7 @@
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"isomorphic-fetch": {
"version": "3.0.0",
@ -66349,8 +66485,7 @@
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"path-parse": {
"version": "1.0.7",
@ -67417,7 +67552,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"requires": {
"shebang-regex": "^3.0.0"
}
@ -67425,8 +67559,7 @@
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
},
"signal-exit": {
"version": "3.0.7",
@ -68401,7 +68534,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}

View File

@ -29,6 +29,8 @@
"dependencies": {
"@graphql-yoga/node": "^2.1.0",
"@pothos/core": "^3.5.1",
"@pothos/plugin-prisma": "^3.4.0",
"@pothos/plugin-relay": "^3.10.0",
"@prisma/client": "^3.11.1",
"@tailwindcss/forms": "^0.4.0",
"@tailwindcss/typography": "^0.5.1",

View File

@ -2,12 +2,16 @@ generator client {
provider = "prisma-client-js"
}
generator pothos {
provider = "prisma-pothos-types"
}
datasource db {
provider = "postgresql"
url = env("DIGITALOCEAN_POSTGRES")
}
model dashboards {
model Dashboard {
id String @id
title String
description String
@ -15,15 +19,19 @@ model dashboards {
timestamp DateTime @db.Timestamp(6)
creator String
extra Json
@@map("dashboards")
}
model frontpage {
model Frontpage {
id Int @id @default(autoincrement())
frontpage_full Json
frontpage_sliced Json
@@map("frontpage")
}
model history {
model History {
id String
title String
url String
@ -37,9 +45,10 @@ model history {
pk Int @id @default(autoincrement())
@@index([id])
@@map("history")
}
model questions {
model Question {
id String @id
title String
url String
@ -50,4 +59,6 @@ model questions {
stars Int
qualityindicators Json
extra Json
@@map("questions")
}

View File

@ -0,0 +1,3 @@
import { PrismaClient } from "@prisma/client";
export const prisma = new PrismaClient({});

View File

@ -1,3 +1,5 @@
// see https://pothos-graphql.dev/docs/guide/generating-client-types#export-schema-in-a-js-file,
// but we use ts-node instead of @boost/module
require("ts-node").register({});
module.exports = require("./schema.ts");

View File

@ -1,25 +1,104 @@
import SchemaBuilder from "@pothos/core";
import PrismaPlugin from "@pothos/plugin-prisma";
import RelayPlugin from "@pothos/plugin-relay";
import { Question } from "@prisma/client";
import { prisma } from "../backend/database/prisma";
import { getFrontpage } from "../backend/frontpage";
import { Question } from "../backend/platforms";
const builder = new SchemaBuilder({});
import type PrismaTypes from "@pothos/plugin-prisma/generated";
const builder = new SchemaBuilder<{
PrismaTypes: PrismaTypes;
Scalars: {
Date: {
Input: Date;
Output: Date;
};
};
}>({
plugins: [PrismaPlugin, RelayPlugin],
prisma: {
client: prisma,
},
relayOptions: {
clientMutationId: "omit",
cursorType: "String",
// these are required for some reason, though it's not documented and probably a bug
brandLoadedObjects: undefined,
encodeGlobalID: undefined,
decodeGlobalID: undefined,
},
});
const QuestionObj = builder.objectRef<Question>("Question").implement({
description: "Forecast question.",
builder.scalarType("Date", {
description: "Date serialized as the Unix timestamp.",
serialize: (d) => d.getTime() / 1000,
parseValue: (d) => {
return new Date(d as string); // not sure if this is correct, need to check
},
});
const QuestionObj = builder.prismaObject("Question", {
findUnique: (question) => ({ id: question.id }),
fields: (t) => ({
id: t.exposeString("id", {}),
title: t.exposeString("title", {}),
id: t.exposeID("id"),
title: t.exposeString("title"),
timestamp: t.field({
type: "Date",
resolve: (parent) => parent.timestamp,
}),
}),
});
builder.queryType({
fields: (t) => ({
firstQuestion: t.prismaField({
type: "Question",
resolve: async (query, root, args, ctx, info) =>
prisma.question.findUnique({
...query,
rejectOnNotFound: true,
where: { id: "foretold-e1ca8cc6-33a4-4e38-9ef3-553a050ba0a9" },
}),
}),
}),
});
builder.queryField("frontpage", (t) =>
t.field({
type: [QuestionObj],
resolve: async (parent) => {
return await getFrontpage();
resolve: async () => {
const legacyQuestions = await getFrontpage();
const ids = legacyQuestions.map((q) => q.id);
const questions = await prisma.question.findMany({
where: {
id: {
in: ids,
},
},
});
const id2q: { [k: string]: Question } = {};
for (const q of questions) {
id2q[q.id] = q;
}
return ids.map((id) => id2q[id] || null).filter((q) => q !== null);
},
})
);
builder.queryField("questions", (t) =>
t.prismaConnection(
{
type: "Question",
cursor: "id",
maxSize: 1000,
resolve: (query, parent, args, context, info) =>
prisma.question.findMany({ ...query }),
},
{},
{}
)
);
export const schema = builder.toSchema({});