prisma pretty noice

This commit is contained in:
ntr committed 2022-07-28 00:18:11 +10:00
1 parent eb04fdb9a5
commit adcc19564f
11 files changed
+125 -177

No files matched your search

@@ -1,8 +0,0 @@
# #!/bin/bash
# set -e
# psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
# CREATE USER mcrates;
# CREATE DATABASE mcrates;
# GRANT ALL PRIVILEGES ON DATABASE mcrates TO mcrates;
# EOSQL
+7 -4
View File
@@ -1,13 +1,15 @@
import fs from 'fs/promises'; import fs from 'fs/promises';
import _ from 'lodash'; import _ from 'lodash';
import Promise from 'bluebird'; import Promise from 'bluebird';
import { PrismaClient } from '@prisma/client'
import discogsService from './src/discogs'; import discogsService from './src/discogs';
import pgService from './src/pg'; import pgService from './src/pg';
import { logAxiosError } from './src/utils'; import { logAxiosError } from './src/utils';
async function start() { async function start() {
const pg = pgService(); const prisma = new PrismaClient();
const pg = pgService(prisma);
const discogs = discogsService(pg); const discogs = discogsService(pg);
const usernames = [ const usernames = [
@@ -47,9 +49,10 @@ async function start() {
// return listings; // return listings;
} }
return Promise.resolve(usernames) for (const u of usernames) {
.map(u => discogs.user(u)) const user = await discogs.user(u)
.map(populateUserListings); await populateUserListings(user);
}
// return Promise.map(releases, async w => { // return Promise.map(releases, async w => {
// try { // try {
-17
View File
@@ -1,17 +0,0 @@
exports.up = async knex => {
await knex.schema.createTable('users', table => {
table.uuid('id')
.primary()
.defaultTo(knex.raw('gen_random_uuid()'));
table.string('discogs')
.unique();
table.jsonb('data')
.notNullable();
table.timestamps(true, true);
});
};
exports.down = async () => true;
-27
View File
@@ -1,27 +0,0 @@
exports.up = async knex => {
await knex.schema.createTable('wants', table => {
table.uuid('id')
.primary()
.defaultTo(knex.raw('gen_random_uuid()'));
table.integer('release')
.notNullable()
.index();
table.uuid('user')
table.foreign('user')
.references('id')
.inTable('users')
.onDelete('CASCADE');
table.jsonb('data')
.notNullable();
// user can only want a release once
table.unique(['user', 'release']);
table.timestamps(true, true);
});
};
exports.down = async () => true;
-23
View File
@@ -1,23 +0,0 @@
exports.up = async knex => {
await knex.schema.createTable('listings', table => {
table.integer('id')
.primary();
table.uuid('want')
table.foreign('want')
.references('id')
.inTable('wants')
.onDelete('CASCADE');
table.integer('seller')
.notNullable()
.index();
table.jsonb('data')
.notNullable();
table.timestamps(true, true);
});
};
exports.down = async () => true;
@@ -1,13 +0,0 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"discogs" TEXT,
"data" JSONB NOT NULL,
"creaedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "User_discogs_key" ON "User"("discogs");
-3
View File
@@ -1,3 +0,0 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
+35 -5
View File
@@ -1,6 +1,3 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client { generator client {
provider = "prisma-client-js" provider = "prisma-client-js"
} }
@@ -10,11 +7,44 @@ datasource db {
url = env("DATABASE_URL") url = env("DATABASE_URL")
} }
model Listing {
id Int @id
seller Int
data Json
wantId String @db.Uuid
want Want @relation(fields: [wantId], references: [id], onDelete: Cascade, onUpdate: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([seller])
}
model User { model User {
id String @id @default(uuid()) id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
discogs String? @unique discogs String? @unique
data Json data Json
creaedAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
wants Want[]
}
model Want {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
release Int?
data Json
userId String @db.Uuid
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
listings Listing[]
@@unique([userId, release])
@@index([release])
} }
+7 -4
View File
@@ -2,6 +2,7 @@ import fs from 'fs/promises';
import axios from 'axios'; import axios from 'axios';
import cheerio from 'cheerio'; import cheerio from 'cheerio';
import type { PrismaClient, Want, User, Listing } from '@prisma/client';
import { logAxiosError } from './utils'; import { logAxiosError } from './utils';
import { Pg } from './pg'; import { Pg } from './pg';
@@ -25,17 +26,19 @@ export default function discogs(pg: Pg) {
} }
async function user(discogs: string) { async function user(discogs: string) {
const user = await pg.userGetName(discogs); const user = await pg.userFindName(discogs);
if (user) return user; if (user) return user;
console.log('fetching user', discogs); console.log('fetching user', discogs);
const res = await api.get(`${apiBase}/users/${discogs}`); const res = await api.get(`${apiBase}/users/${discogs}`);
return pg.userUpsert(res.data); return pg.userUpsert(res.data);
} }
async function wantlist(user: User): Promise<Want[]> { async function wantlist(user: User): Promise<Want[]> {
const stored = await pg.userWants(user); const stored = await pg.userWants(user);
if (stored.length) return stored; if (stored.length) return stored;
const { data: { wants, pagination }} = await api.get(`${apiBase}/users/${user.data.username}/wants`); const { username } = user.data as { username: string };
const { data: { wants, pagination }} = await api.get(`${apiBase}/users/${username}/wants`);
return Promise.all(wants.map(r => pg.wantUpsert(r, user))) return Promise.all(wants.map(r => pg.wantUpsert(r, user)))
} }
@@ -44,7 +47,7 @@ export default function discogs(pg: Pg) {
return res.data.listings; return res.data.listings;
} }
async function listings(want: Want): Promise<Listing[]> { async function listings(want: Want) {
const res = await api.get(`https://www.discogs.com/sell/release/${want.release}`); const res = await api.get(`https://www.discogs.com/sell/release/${want.release}`);
const $ = cheerio.load(res.data); const $ = cheerio.load(res.data);
const ids = $('.item_description_title[href]') const ids = $('.item_description_title[href]')
@@ -57,7 +60,7 @@ export default function discogs(pg: Pg) {
} }
async function listing(id, want) { async function listing(id, want) {
const listing = await pg.listingGet(id); const listing = await pg.listingFind(id);
if (listing) return listing; if (listing) return listing;
try { try {
+17 -17
View File
@@ -1,21 +1,21 @@
type UUID = string; type UUID = string;
type User = { // type User = {
id: UUID, // id: UUID,
discogs: string, // discogs: string,
data: any, // data: any,
} // }
type Listing = { // type Listing = {
id: number, // id: number,
want: UUID, // want: UUID,
seller: number, // seller: number,
data: any, // data: any,
} // }
type Want = { // type Want = {
id: UUID, // id: UUID,
release: number, // release: number,
user: UUID, // user: UUID,
data: any, // data: any,
} // }
+59 -56
View File
@@ -1,98 +1,101 @@
import Knex from 'knex'; import Knex from 'knex';
import config from '../knexfile'; import config from '../knexfile';
import type { PrismaClient, Want, User, Listing, Prisma } from '@prisma/client';
export interface Pg { export interface Pg {
userGetId: (id: UUID) => Promise<User>, userFindId: (id: UUID) => Promise<User>,
userGetName: (name: string) => Promise<User>, userFindName: (name: string) => Promise<User>,
userUpsert: (user: User) => Promise<User>, userUpsert: (user: User) => Promise<User>,
userWants: (user: User) => Promise<Want[]>, userWants: (user: User) => Promise<Want[]>,
wantUpsert: (want: Want, user: User) => Promise<Want>, wantUpsert: (want: Want, user: User) => Promise<Want>,
listingUpsert: (listing: Listing, want: Want) => Promise<Listing>, listingUpsert: (listing: Listing, want: Want) => Promise<Listing>,
listingGet: (id: number) => Promise<Listing>, listingFind: (id: number) => Promise<Listing>,
} }
export default function createPg(): Pg { export default function createPg(prisma: PrismaClient): Pg {
const pg = Knex(config); // const pg = Knex(config);
async function userGetId(id): Promise<User> { async function userFindId(id) {
return pg('users') return prisma.user.findUnique({ where: { id }});
.where({ id })
.first();
} }
async function userGetName(name): Promise<User> { async function userFindName(name) {
return pg('users') return prisma.user.findUnique({ where: { discogs: name }});
.where({ discogs: name })
.first();
} }
async function userWants(user: User): Promise<Want[]> { async function userWants(user: User) {
return pg('wants') return prisma.want.findMany({ where: { userId: user.id }});
.where({ user: user.id });
} }
async function userUpsert(user): Promise<User> { async function userUpsert(user) {
const [row] = await pg('users') const data = {
.insert({
discogs: user.username, discogs: user.username,
data: user, data: user as Prisma.JsonObject,
}) };
.onConflict('id')
.merge()
.onConflict('discogs')
.merge()
.returning('*');
return row; return prisma.user.upsert({
where: {
discogs: user.username,
},
update: data,
create: data,
});
} }
async function wantUpsert(want, user): Promise<Want> { async function wantUpsert(dcWant, user) {
const [row] = await pg('wants') const values: { userId: string, release: number, data: any } = {
.insert({ data: dcWant,
data: want, release: dcWant.id,
release: want.id, userId: user.id,
user: user.id, };
})
.onConflict('id')
.merge()
.onConflict(['user', 'release'])
.merge()
.returning('*');
return row; return prisma.want.upsert({
// get these from the generated types
// ./node_modules/.prisma/client/index.d.ts
where: { userId_release: {
userId: values.userId,
release: values.release || null,
}},
update: values,
create: values,
});
} }
async function listingUpsert(listing, want): Promise<Listing> { async function listingUpsert(listing, want) {
const [row] = await pg('listings') const values = {
.insert({
id: listing.id, id: listing.id,
want: want.id, wantId: want.id,
seller: listing.seller.id, seller: listing.seller.id,
data: listing, data: listing,
}) };
.onConflict('id')
.merge()
.returning('*');
return row; return prisma.listing.upsert({
where: {
id: listing.id
},
update: values,
create: values,
});
} }
async function listingGet(id): Promise<Listing> { async function listingFind(id) {
return pg('listings') return prisma.listing.findUnique({
.where({ id }) where: {
.first(); id,
}
});
} }
return { return {
userGetId, userFindId,
userGetName, userFindName,
userUpsert, userUpsert,
userWants, userWants,
wantUpsert, wantUpsert,
listingUpsert, listingUpsert,
listingGet, listingFind,
}; };
} }