improve bounty performance
This commit is contained in:
parent
e13e37744e
commit
5306b11157
@ -920,27 +920,6 @@ export default {
|
|||||||
|
|
||||||
return (msats && msatsToSats(msats)) || 0
|
return (msats && msatsToSats(msats)) || 0
|
||||||
},
|
},
|
||||||
bountyPaid: async (item, args, { models }) => {
|
|
||||||
if (!item.bounty) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there's a child where the OP paid the amount, but it isn't the OP's own comment
|
|
||||||
const paid = await models.$queryRaw`
|
|
||||||
-- Sum up the sats and if they are greater than or equal to item.bounty than return true, else return false
|
|
||||||
SELECT "Item"."id"
|
|
||||||
FROM "ItemAct"
|
|
||||||
JOIN "Item" ON "ItemAct"."itemId" = "Item"."id"
|
|
||||||
WHERE "ItemAct"."userId" = ${item.userId}
|
|
||||||
AND "Item".path <@ text2ltree (${item.path})
|
|
||||||
AND "Item"."userId" <> ${item.userId}
|
|
||||||
AND act IN ('TIP', 'FEE')
|
|
||||||
GROUP BY "Item"."id"
|
|
||||||
HAVING coalesce(sum("ItemAct"."msats"), 0) >= ${item.bounty * 1000}
|
|
||||||
`
|
|
||||||
|
|
||||||
return paid.length > 0
|
|
||||||
},
|
|
||||||
bountyPaidTo: async (item, args, { models }) => {
|
bountyPaidTo: async (item, args, { models }) => {
|
||||||
if (!item.bounty) {
|
if (!item.bounty) {
|
||||||
return []
|
return []
|
||||||
@ -951,7 +930,7 @@ export default {
|
|||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
JOIN "Item" ON "ItemAct"."itemId" = "Item"."id"
|
JOIN "Item" ON "ItemAct"."itemId" = "Item"."id"
|
||||||
WHERE "ItemAct"."userId" = ${item.userId}
|
WHERE "ItemAct"."userId" = ${item.userId}
|
||||||
AND "Item".path <@ text2ltree (${item.path})
|
AND "Item"."rootId" = ${item.id}
|
||||||
AND "Item"."userId" <> ${item.userId}
|
AND "Item"."userId" <> ${item.userId}
|
||||||
AND act IN ('TIP', 'FEE')
|
AND act IN ('TIP', 'FEE')
|
||||||
GROUP BY "Item"."id"
|
GROUP BY "Item"."id"
|
||||||
@ -990,13 +969,7 @@ export default {
|
|||||||
if (!item.parentId) {
|
if (!item.parentId) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return (await models.$queryRaw(`
|
return await models.item.findUnique({ where: { id: item.rootId } })
|
||||||
${SELECT}
|
|
||||||
FROM "Item"
|
|
||||||
WHERE id = (
|
|
||||||
SELECT ltree2text(subltree(path, 0, 1))::integer
|
|
||||||
FROM "Item"
|
|
||||||
WHERE id = $1)`, Number(item.id)))[0]
|
|
||||||
},
|
},
|
||||||
parent: async (item, args, { models }) => {
|
parent: async (item, args, { models }) => {
|
||||||
if (!item.parentId) {
|
if (!item.parentId) {
|
||||||
@ -1160,7 +1133,8 @@ function nestComments (flat, parentId) {
|
|||||||
// we have to do our own query because ltree is unsupported
|
// we have to do our own query because ltree is unsupported
|
||||||
export const SELECT =
|
export const SELECT =
|
||||||
`SELECT "Item".id, "Item".created_at as "createdAt", "Item".updated_at as "updatedAt", "Item".title,
|
`SELECT "Item".id, "Item".created_at as "createdAt", "Item".updated_at as "updatedAt", "Item".title,
|
||||||
"Item".text, "Item".url, "Item"."bounty", "Item"."userId", "Item"."fwdUserId", "Item"."parentId", "Item"."pinId", "Item"."maxBid",
|
"Item".text, "Item".url, "Item"."bounty", "Item"."userId", "Item"."fwdUserId", "Item"."parentId",
|
||||||
|
"Item"."pinId", "Item"."maxBid", "Item"."rootId",
|
||||||
"Item".company, "Item".location, "Item".remote, "Item"."deletedAt",
|
"Item".company, "Item".location, "Item".remote, "Item"."deletedAt",
|
||||||
"Item"."subName", "Item".status, "Item"."uploadId", "Item"."pollCost",
|
"Item"."subName", "Item".status, "Item"."uploadId", "Item"."pollCost",
|
||||||
"Item".msats, "Item".ncomments, "Item"."commentMsats", "Item"."lastCommentAt", "Item"."weightedVotes",
|
"Item".msats, "Item".ncomments, "Item"."commentMsats", "Item"."lastCommentAt", "Item"."weightedVotes",
|
||||||
|
@ -90,7 +90,6 @@ export default gql`
|
|||||||
mine: Boolean!
|
mine: Boolean!
|
||||||
boost: Int!
|
boost: Int!
|
||||||
bounty: Int
|
bounty: Int
|
||||||
bountyPaid: Boolean
|
|
||||||
bountyPaidTo: [Int]!
|
bountyPaidTo: [Int]!
|
||||||
sats: Int!
|
sats: Int!
|
||||||
commentSats: Int!
|
commentSats: Int!
|
||||||
|
@ -101,7 +101,7 @@ function TopLevelItem ({ item, noReply, ...props }) {
|
|||||||
{item.poll && <Poll item={item} />}
|
{item.poll && <Poll item={item} />}
|
||||||
{item.bounty &&
|
{item.bounty &&
|
||||||
<div className='font-weight-bold mt-2 mb-3'>
|
<div className='font-weight-bold mt-2 mb-3'>
|
||||||
{item.bountyPaid
|
{item.bountyPaidTo?.length
|
||||||
? (
|
? (
|
||||||
<div className='px-3 py-1 d-inline-block bg-grey-medium rounded text-success'>
|
<div className='px-3 py-1 d-inline-block bg-grey-medium rounded text-success'>
|
||||||
<Check className='fill-success' /> {item.bounty} sats paid
|
<Check className='fill-success' /> {item.bounty} sats paid
|
||||||
|
@ -78,8 +78,8 @@ export default function Item ({ item, rank, showFwdUser, toc, children }) {
|
|||||||
{item.pollCost && <span> <PollIcon className='fill-grey vertical-align-baseline' height={14} width={14} /></span>}
|
{item.pollCost && <span> <PollIcon className='fill-grey vertical-align-baseline' height={14} width={14} /></span>}
|
||||||
{item.bounty > 0 &&
|
{item.bounty > 0 &&
|
||||||
<span>
|
<span>
|
||||||
<ActionTooltip notForm overlayText={`${abbrNum(item.bounty)} ${item.bountyPaid ? 'sats paid' : 'sats bounty'}`}>
|
<ActionTooltip notForm overlayText={`${abbrNum(item.bounty)} ${item.bountyPaidTo?.length ? 'sats paid' : 'sats bounty'}`}>
|
||||||
<BountyIcon className={`${styles.bountyIcon} ${item.bountyPaid ? 'fill-success vertical-align-middle' : 'fill-grey vertical-align-middle'}`} height={16} width={16} />
|
<BountyIcon className={`${styles.bountyIcon} ${item.bountyPaidTo?.length ? 'fill-success vertical-align-middle' : 'fill-grey vertical-align-middle'}`} height={16} width={16} />
|
||||||
</ActionTooltip>
|
</ActionTooltip>
|
||||||
</span>}
|
</span>}
|
||||||
</a>
|
</a>
|
||||||
|
@ -50,9 +50,6 @@ export default function PayBounty ({ children, item }) {
|
|||||||
cache.modify({
|
cache.modify({
|
||||||
id: `Item:${item.root.id}`,
|
id: `Item:${item.root.id}`,
|
||||||
fields: {
|
fields: {
|
||||||
bountyPaid () {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
bountyPaidTo (existingPaidTo = []) {
|
bountyPaidTo (existingPaidTo = []) {
|
||||||
return [...existingPaidTo, Number(item.id)]
|
return [...existingPaidTo, Number(item.id)]
|
||||||
}
|
}
|
||||||
@ -84,7 +81,7 @@ export default function PayBounty ({ children, item }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!me || item.root.user.name !== me.name || item.mine || item.root.bountyPaid) {
|
if (item.mine || item.root.user.name !== me.name) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export const ITEM_FIELDS = gql`
|
|||||||
upvotes
|
upvotes
|
||||||
boost
|
boost
|
||||||
bounty
|
bounty
|
||||||
bountyPaid
|
bountyPaidTo
|
||||||
path
|
path
|
||||||
meSats
|
meSats
|
||||||
meDontLike
|
meDontLike
|
||||||
|
8
prisma/migrations/20230126180748_root_id/migration.sql
Normal file
8
prisma/migrations/20230126180748_root_id/migration.sql
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Item" ADD COLUMN "rootId" INTEGER;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Item.rootId_index" ON "Item"("rootId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Item" ADD FOREIGN KEY ("rootId") REFERENCES "Item"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
28
prisma/migrations/20230126184544_root_id_funcs/migration.sql
Normal file
28
prisma/migrations/20230126184544_root_id_funcs/migration.sql
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-- Store root ids of all existing items
|
||||||
|
UPDATE "Item"
|
||||||
|
SET "rootId" = ltree2text(subltree(path, 0, 1))::integer
|
||||||
|
WHERE "parentId" IS NOT NULL;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION update_item_path() RETURNS TRIGGER AS $$
|
||||||
|
DECLARE
|
||||||
|
npath ltree;
|
||||||
|
root_id INTEGER;
|
||||||
|
BEGIN
|
||||||
|
IF NEW."parentId" IS NULL THEN
|
||||||
|
SELECT NEW.id::text::ltree INTO npath;
|
||||||
|
NEW."path" = npath;
|
||||||
|
ELSEIF TG_OP = 'INSERT' OR OLD."parentId" IS NULL OR OLD."parentId" != NEW."parentId" THEN
|
||||||
|
SELECT "path" || NEW.id::text, ltree2text(subltree("path", 0, 1))::integer
|
||||||
|
FROM "Item"
|
||||||
|
WHERE id = NEW."parentId"
|
||||||
|
INTO npath, root_id;
|
||||||
|
|
||||||
|
IF npath IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Invalid parent_id %', NEW."parentId";
|
||||||
|
END IF;
|
||||||
|
NEW."path" = npath;
|
||||||
|
NEW."rootId" = root_id;
|
||||||
|
END IF;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
@ -222,6 +222,9 @@ model Item {
|
|||||||
parent Item? @relation("ParentChildren", fields: [parentId], references: [id])
|
parent Item? @relation("ParentChildren", fields: [parentId], references: [id])
|
||||||
parentId Int?
|
parentId Int?
|
||||||
children Item[] @relation("ParentChildren")
|
children Item[] @relation("ParentChildren")
|
||||||
|
root Item? @relation("RootDescendant", fields: [rootId], references: [id])
|
||||||
|
rootId Int?
|
||||||
|
descendants Item[] @relation("RootDescendant")
|
||||||
actions ItemAct[]
|
actions ItemAct[]
|
||||||
mentions Mention[]
|
mentions Mention[]
|
||||||
path Unsupported("LTREE")?
|
path Unsupported("LTREE")?
|
||||||
@ -280,6 +283,7 @@ model Item {
|
|||||||
@@index([freebie])
|
@@index([freebie])
|
||||||
@@index([createdAt])
|
@@index([createdAt])
|
||||||
@@index([userId])
|
@@index([userId])
|
||||||
|
@@index([rootId])
|
||||||
@@index([parentId])
|
@@index([parentId])
|
||||||
@@index([status])
|
@@index([status])
|
||||||
@@index([maxBid])
|
@@index([maxBid])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user