diff --git a/api/resolvers/notifications.js b/api/resolvers/notifications.js index 9cf21567..5fe0832d 100644 --- a/api/resolvers/notifications.js +++ b/api/resolvers/notifications.js @@ -184,15 +184,11 @@ export default { if (meFull.noteItemSats) { queries.push( - `(SELECT "Item".id::TEXT, MAX("ItemAct".created_at) AS "sortTime", - MAX("Item".msats/1000) as "earnedSats", 'Votification' AS type + `(SELECT "Item".id::TEXT, "Item"."lastZapAt" AS "sortTime", + "Item".msats/1000 as "earnedSats", 'Votification' AS type FROM "Item" - JOIN "ItemAct" ON "ItemAct"."itemId" = "Item".id - WHERE "ItemAct"."userId" <> $1 - AND "ItemAct".created_at < $2 - AND "ItemAct".act IN ('TIP', 'FEE') - AND "Item"."userId" = $1 - GROUP BY "Item".id + WHERE "Item"."userId" = $1 + AND "Item"."lastZapAt" < $2 ORDER BY "sortTime" DESC LIMIT ${LIMIT})` ) @@ -200,16 +196,12 @@ export default { if (meFull.noteForwardedSats) { queries.push( - `(SELECT "Item".id::TEXT, MAX("ItemAct".created_at) AS "sortTime", - MAX("Item".msats / 1000 * "ItemForward".pct / 100) as "earnedSats", 'ForwardedVotification' AS type + `(SELECT "Item".id::TEXT, "Item"."lastZapAt" AS "sortTime", + ("Item".msats / 1000 * "ItemForward".pct / 100) as "earnedSats", 'ForwardedVotification' AS type FROM "Item" - JOIN "ItemAct" ON "ItemAct"."itemId" = "Item".id JOIN "ItemForward" ON "ItemForward"."itemId" = "Item".id AND "ItemForward"."userId" = $1 - WHERE "ItemAct"."userId" <> $1 - AND "Item"."userId" <> $1 - AND "ItemAct".created_at < $2 - AND "ItemAct".act IN ('TIP') - GROUP BY "Item".id + WHERE "Item"."userId" <> $1 + AND "Item"."lastZapAt" < $2 ORDER BY "sortTime" DESC LIMIT ${LIMIT})` ) @@ -298,23 +290,11 @@ export default { LIMIT ${LIMIT})` ) - // we do all this crazy subquery stuff to make 'reward' islands const notifications = await models.$queryRawUnsafe( - `SELECT MAX(id) AS id, MAX("sortTime") AS "sortTime", sum("earnedSats") AS "earnedSats", type, - MIN("sortTime") AS "minSortTime" + `SELECT id, "sortTime", "earnedSats", type, + "sortTime" AS "minSortTime" FROM - (SELECT *, - CASE - WHEN type = 'Earn' THEN - ROW_NUMBER() OVER(ORDER BY "sortTime" DESC) - - ROW_NUMBER() OVER(PARTITION BY type = 'Earn' ORDER BY "sortTime" DESC) - ELSE - ROW_NUMBER() OVER(ORDER BY "sortTime" DESC) - END as island - FROM - (${queries.join(' UNION ALL ')}) u - ) sub - GROUP BY type, island + (${queries.join(' UNION ALL ')}) u ORDER BY "sortTime" DESC LIMIT ${LIMIT}`, me.id, decodedCursor.time) diff --git a/api/resolvers/user.js b/api/resolvers/user.js index 8ee5e868..8032b99a 100644 --- a/api/resolvers/user.js +++ b/api/resolvers/user.js @@ -220,12 +220,8 @@ export default { SELECT EXISTS( SELECT * FROM "Item" - JOIN "ItemAct" ON - "ItemAct"."itemId" = "Item".id - AND "ItemAct"."userId" <> "Item"."userId" - WHERE "ItemAct".created_at > $2 - AND "Item"."userId" = $1 - AND "ItemAct".act = 'TIP')`, me.id, lastChecked) + WHERE "Item"."lastZapAt" > $2 + AND "Item"."userId" = $1)`, me.id, lastChecked) if (newSats.exists) { foundNotes() return true @@ -296,15 +292,11 @@ export default { SELECT EXISTS( SELECT * FROM "Item" - JOIN "ItemAct" ON - "ItemAct"."itemId" = "Item".id - AND "ItemAct"."userId" <> "Item"."userId" JOIN "ItemForward" ON "ItemForward"."itemId" = "Item".id AND "ItemForward"."userId" = $1 - WHERE "ItemAct".created_at > $2 - AND "Item"."userId" <> $1 - AND "ItemAct".act = 'TIP')`, me.id, lastChecked) + WHERE "Item"."lastZapAt" > $2 + AND "Item"."userId" <> $1)`, me.id, lastChecked) if (newFwdSats.exists) { foundNotes() return true diff --git a/prisma/migrations/20240324164838_last_zap_at/migration.sql b/prisma/migrations/20240324164838_last_zap_at/migration.sql new file mode 100644 index 00000000..72e5983f --- /dev/null +++ b/prisma/migrations/20240324164838_last_zap_at/migration.sql @@ -0,0 +1,45 @@ +-- AlterTable +ALTER TABLE "Item" ADD COLUMN "lastZapAt" TIMESTAMP(3); + +-- CreateIndex +CREATE INDEX "Item_lastZapAt_idx" ON "Item"("lastZapAt"); + +-- CreateIndex +CREATE INDEX "Reply_itemId_idx" ON "Reply"("itemId"); + +-- CreateIndex +CREATE INDEX "Reply_userId_idx" ON "Reply"("userId"); + + +-- when an item is zapped, update the lastZapAt field +CREATE OR REPLACE FUNCTION sats_after_tip(item_id INTEGER, user_id INTEGER, tip_msats BIGINT) RETURNS INTEGER AS $$ +DECLARE + item "Item"; +BEGIN + SELECT * FROM "Item" WHERE id = item_id INTO item; + IF user_id <> 27 AND item."userId" = user_id THEN + RETURN 0; + END IF; + + UPDATE "Item" + SET "msats" = "msats" + tip_msats, + "lastZapAt" = now() + WHERE id = item.id; + + UPDATE "Item" + SET "commentMsats" = "commentMsats" + tip_msats + WHERE id <> item.id and path @> item.path; + + RETURN 1; +END; +$$ LANGUAGE plpgsql; + +-- retrofit the lastZapAt field for all existing items +UPDATE "Item" SET "lastZapAt" = "Zap".at +FROM ( + SELECT "ItemAct"."itemId", MAX("ItemAct"."created_at") AS at + FROM "ItemAct" + WHERE "ItemAct".act = 'TIP' + GROUP BY "ItemAct"."itemId" +) AS "Zap" +WHERE "Item"."id" = "Zap"."itemId"; \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 842d0c66..d9669156 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -355,6 +355,7 @@ model Item { paidImgLink Boolean @default(false) commentMsats BigInt @default(0) lastCommentAt DateTime? + lastZapAt DateTime? ncomments Int @default(0) msats BigInt @default(0) weightedDownVotes Float @default(0) @@ -393,6 +394,7 @@ model Item { Replies Reply[] @@index([uploadId]) + @@index([lastZapAt]) @@index([bio], map: "Item.bio_index") @@index([createdAt], map: "Item.created_at_index") @@index([freebie], map: "Item.freebie_index") @@ -428,6 +430,8 @@ model Reply { @@index([ancestorId]) @@index([ancestorUserId]) + @@index([itemId]) + @@index([userId]) @@index([level]) @@index([createdAt]) }