diff --git a/prisma/migrations/20220218193307_sub_desc/migration.sql b/prisma/migrations/20220218193307_sub_desc/migration.sql index d3b5818c..280b28b1 100644 --- a/prisma/migrations/20220218193307_sub_desc/migration.sql +++ b/prisma/migrations/20220218193307_sub_desc/migration.sql @@ -1,4 +1,4 @@ -- AlterTable -ALTER TABLE "Sub" ADD COLUMN "desc" TEXT; +ALTER TABLE "Sub" ADD COLUMN IF NOT EXISTS "desc" TEXT; -UPDATE "Sub" SET desc = 'jobs at bitcoin and lightning companies' WHERE name = 'jobs'; \ No newline at end of file +UPDATE "Sub" SET "desc" = 'jobs at bitcoin and lightning companies' WHERE name = 'jobs'; \ No newline at end of file diff --git a/prisma/migrations/20220224203227_item_status/migration.sql b/prisma/migrations/20220224203227_item_status/migration.sql new file mode 100644 index 00000000..3dba9cc5 --- /dev/null +++ b/prisma/migrations/20220224203227_item_status/migration.sql @@ -0,0 +1,6 @@ +-- CreateEnum +CREATE TYPE "Status" AS ENUM ('ACTIVE', 'STOPPED', 'NOSATS'); + +-- AlterTable +ALTER TABLE "Item" ADD COLUMN "noSatsAt" TIMESTAMP(3), +ADD COLUMN "status" "Status" NOT NULL DEFAULT E'ACTIVE'; diff --git a/prisma/migrations/20220224205443_run_auction/migration.sql b/prisma/migrations/20220224205443_run_auction/migration.sql new file mode 100644 index 00000000..7202db38 --- /dev/null +++ b/prisma/migrations/20220224205443_run_auction/migration.sql @@ -0,0 +1,30 @@ +-- charge the user for the auction item +CREATE OR REPLACE FUNCTION run_auction(item_id INTEGER) RETURNS void AS $$ + DECLARE + bid INTEGER; + user_id INTEGER; + user_msats INTEGER; + item_status "Status"; + BEGIN + PERFORM ASSERT_SERIALIZED(); + + -- extract data we need + SELECT ("maxBid" * 1000 / 30 / 24 / 60), "userId", status INTO bid, user_id, item_status FROM "Item" WHERE id = item_id; + SELECT msats INTO user_msats FROM users WHERE id = user_id; + + -- check if user wallet has enough sats + IF bid > user_msats THEN + -- if not, set status = NOSATS and noSatsAt to now_utc if not already set + IF item_status <> 'NOSATS' THEN + UPDATE "Item" SET status = 'NOSATS', "noSatsAt" = now_utc() WHERE id = item_id; + END IF; + ELSE + -- if so, deduct from user + UPDATE users SET msats = msats - bid WHERE id = user_id; + -- update item status = ACTIVE and noSatsAt = null if NOSATS + IF item_status = 'NOSATS' THEN + UPDATE "Item" SET status = 'ACTIVE', "noSatsAt" = null WHERE id = item_id; + END IF; + END IF; + END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index eff89986..1e9201b4 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -80,6 +80,12 @@ model Message { userId Int } +enum Status { + ACTIVE + STOPPED + NOSATS +} + model Item { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) @map(name: "created_at") @@ -106,6 +112,8 @@ model Item { minSalary Int? maxSalary Int? maxBid Int? + status Status @default(ACTIVE) + noSatsAt DateTime? location String? latitude Float? longitude Float? diff --git a/worker/auction.js b/worker/auction.js new file mode 100644 index 00000000..3b57c083 --- /dev/null +++ b/worker/auction.js @@ -0,0 +1,30 @@ +const serialize = require('../api/resolvers/serial') + +function auction ({ models }) { + return async function ({ name }) { + console.log('running', name) + // get all items we need to check + const items = await models.item.findMany( + { + where: { + maxBid: { + not: null + }, + status: { + not: 'STOPPED' + } + } + } + ) + + // for each item, run serialized auction function + items.forEach(async item => { + await serialize(models, + models.$executeRaw`SELECT run_auction(${item.id})`) + }) + + console.log('done', name) + } +} + +module.exports = { auction } diff --git a/worker/index.js b/worker/index.js index cc77ede5..d163266d 100644 --- a/worker/index.js +++ b/worker/index.js @@ -5,6 +5,7 @@ const { PrismaClient } = require('@prisma/client') const { checkInvoice, checkWithdrawal } = require('./wallet') const { repin } = require('./repin') const { trust } = require('./trust') +const { auction } = require('./auction') const { ApolloClient, HttpLink, InMemoryCache } = require('@apollo/client') const { indexItem, indexAllItems } = require('./search') const fetch = require('cross-fetch') @@ -41,6 +42,7 @@ async function work () { await boss.work('trust', trust(args)) await boss.work('indexItem', indexItem(args)) await boss.work('indexAllItems', indexAllItems(args)) + await boss.work('auction', auction(args)) console.log('working jobs') }