This commit is contained in:
keyan 2021-09-08 16:51:23 -05:00
parent 28d684da73
commit 93428e3183
7 changed files with 64 additions and 63 deletions

View File

@ -209,7 +209,7 @@ export default {
return await updateItem(parent, { id, data: { text } }, { me, models }) return await updateItem(parent, { id, data: { text } }, { me, models })
}, },
vote: async (parent, { id, sats = 1 }, { me, models }) => { act: async (parent, { id, act, sats }, { me, models }) => {
// need to make sure we are logged in // need to make sure we are logged in
if (!me) { if (!me) {
throw new AuthenticationError('you must be logged in') throw new AuthenticationError('you must be logged in')
@ -219,7 +219,7 @@ export default {
throw new UserInputError('sats must be positive', { argumentName: 'sats' }) throw new UserInputError('sats must be positive', { argumentName: 'sats' })
} }
await serialize(models, models.$queryRaw`SELECT vote(${Number(id)}, ${me.name}, ${Number(sats)})`) await serialize(models, models.$queryRaw`SELECT item_act(${Number(id)}, ${me.id}, ${act}, ${Number(sats)})`)
return sats return sats
} }
}, },
@ -235,26 +235,26 @@ export default {
return count || 0 return count || 0
}, },
sats: async (item, args, { models }) => { sats: async (item, args, { models }) => {
const { sum: { sats } } = await models.vote.aggregate({ const { sum: { sats } } = await models.itemAct.aggregate({
sum: { sum: {
sats: true sats: true
}, },
where: { where: {
itemId: item.id, itemId: item.id,
boost: false act: 'VOTE'
} }
}) })
return sats || 0 return sats || 0
}, },
boost: async (item, args, { models }) => { boost: async (item, args, { models }) => {
const { sum: { sats } } = await models.vote.aggregate({ const { sum: { sats } } = await models.itemAct.aggregate({
sum: { sum: {
sats: true sats: true
}, },
where: { where: {
itemId: item.id, itemId: item.id,
boost: true act: 'BOOST'
} }
}) })
@ -263,13 +263,14 @@ export default {
meSats: async (item, args, { me, models }) => { meSats: async (item, args, { me, models }) => {
if (!me) return 0 if (!me) return 0
const { sum: { sats } } = await models.vote.aggregate({ const { sum: { sats } } = await models.itemAct.aggregate({
sum: { sum: {
sats: true sats: true
}, },
where: { where: {
itemId: item.id, itemId: item.id,
userId: me.id userId: me.id,
act: 'VOTE'
} }
}) })
@ -353,7 +354,7 @@ const createItem = async (parent, { title, url, text, parentId }, { me, models }
const [item] = await serialize(models, models.$queryRaw( const [item] = await serialize(models, models.$queryRaw(
`${SELECT} FROM create_item($1, $2, $3, $4, $5) AS "Item"`, `${SELECT} FROM create_item($1, $2, $3, $4, $5) AS "Item"`,
title, url, text, Number(parentId), me.name)) title, url, text, Number(parentId), me.id))
await createMentions(item, models) await createMentions(item, models)
@ -391,19 +392,19 @@ 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"."userId", "Item"."parentId", ltree2text("Item"."path") AS "path"` "Item".text, "Item".url, "Item"."userId", "Item"."parentId", ltree2text("Item"."path") AS "path"`
const LEFT_JOIN_SATS_SELECT = 'SELECT i.id, SUM(CASE WHEN "Vote".boost THEN 0 ELSE "Vote".sats END) as sats, SUM(CASE WHEN "Vote".boost THEN "Vote".sats ELSE 0 END) as boost' const LEFT_JOIN_SATS_SELECT = 'SELECT i.id, SUM(CASE WHEN "ItemAct".act = \'VOTE\' THEN "ItemAct".sats ELSE 0 END) as sats, SUM(CASE WHEN "ItemAct".act = \'BOOST\' THEN "ItemAct".sats ELSE 0 END) as boost'
function timedLeftJoinSats (num) { function timedLeftJoinSats (num) {
return `LEFT JOIN (${LEFT_JOIN_SATS_SELECT} return `LEFT JOIN (${LEFT_JOIN_SATS_SELECT}
FROM "Item" i FROM "Item" i
JOIN "Vote" ON i.id = "Vote"."itemId" AND "Vote".created_at <= $${num} JOIN "ItemAct" ON i.id = "ItemAct"."itemId" AND "ItemAct".created_at <= $${num}
GROUP BY i.id) x ON "Item".id = x.id` GROUP BY i.id) x ON "Item".id = x.id`
} }
const LEFT_JOIN_SATS = const LEFT_JOIN_SATS =
`LEFT JOIN (${LEFT_JOIN_SATS_SELECT} `LEFT JOIN (${LEFT_JOIN_SATS_SELECT}
FROM "Item" i FROM "Item" i
JOIN "Vote" ON i.id = "Vote"."itemId" JOIN "ItemAct" ON i.id = "ItemAct"."itemId"
GROUP BY i.id) x ON "Item".id = x.id` GROUP BY i.id) x ON "Item".id = x.id`
function timedOrderBySats (num) { function timedOrderBySats (num) {

View File

@ -53,14 +53,14 @@ export default {
(SELECT ${ITEM_SUBQUERY_FIELDS}, max(subquery.voted_at) as "sortTime", (SELECT ${ITEM_SUBQUERY_FIELDS}, max(subquery.voted_at) as "sortTime",
sum(subquery.sats) as "earnedSats", false as mention sum(subquery.sats) as "earnedSats", false as mention
FROM FROM
(SELECT ${ITEM_FIELDS}, "Vote".created_at as voted_at, "Vote".sats, (SELECT ${ITEM_FIELDS}, "ItemAct".created_at as voted_at, "ItemAct".sats,
ROW_NUMBER() OVER(ORDER BY "Vote".created_at) - ROW_NUMBER() OVER(ORDER BY "ItemAct".created_at) -
ROW_NUMBER() OVER(PARTITION BY "Item".id ORDER BY "Vote".created_at) as island ROW_NUMBER() OVER(PARTITION BY "Item".id ORDER BY "ItemAct".created_at) as island
FROM "Vote" FROM "ItemAct"
JOIN "Item" on "Vote"."itemId" = "Item".id JOIN "Item" on "ItemAct"."itemId" = "Item".id
WHERE "Vote"."userId" <> $1 WHERE "ItemAct"."userId" <> $1
AND "Vote".created_at <= $2 AND "ItemAct".created_at <= $2
AND "Vote".boost = false AND "ItemAct".act <> 'BOOST'
AND "Item"."userId" = $1) subquery AND "Item"."userId" = $1) subquery
GROUP BY ${ITEM_SUBQUERY_FIELDS}, subquery.island ORDER BY max(subquery.voted_at) desc) GROUP BY ${ITEM_SUBQUERY_FIELDS}, subquery.island ORDER BY max(subquery.voted_at) desc)
UNION ALL UNION ALL

View File

@ -44,10 +44,10 @@ export default {
}, },
stacked: async (user, args, { models }) => { stacked: async (user, args, { models }) => {
const [{ sum }] = await models.$queryRaw` const [{ sum }] = await models.$queryRaw`
SELECT sum("Vote".sats) SELECT sum("ItemAct".sats)
FROM "Vote" FROM "ItemAct"
JOIN "Item" on "Vote"."itemId" = "Item".id JOIN "Item" on "ItemAct"."itemId" = "Item".id
WHERE "Vote"."userId" <> ${user.id} AND boost = false WHERE "ItemAct"."userId" <> ${user.id} AND "ItemAct".act <> 'BOOST'
AND "Item"."userId" = ${user.id}` AND "Item"."userId" = ${user.id}`
return sum || 0 return sum || 0
}, },
@ -57,12 +57,12 @@ export default {
hasNewNotes: async (user, args, { models }) => { hasNewNotes: async (user, args, { models }) => {
// check if any votes have been cast for them since checkedNotesAt // check if any votes have been cast for them since checkedNotesAt
const votes = await models.$queryRaw(` const votes = await models.$queryRaw(`
SELECT "Vote".id, "Vote".created_at SELECT "ItemAct".id, "ItemAct".created_at
FROM "Vote" FROM "ItemAct"
JOIN "Item" on "Vote"."itemId" = "Item".id JOIN "Item" on "ItemAct"."itemId" = "Item".id
WHERE "Vote"."userId" <> $1 WHERE "ItemAct"."userId" <> $1
AND ("Vote".created_at > $2 OR $2 IS NULL) AND ("ItemAct".created_at > $2 OR $2 IS NULL)
AND "Vote".boost = false AND "ItemAct".act <> 'BOOST'
AND "Item"."userId" = $1 AND "Item"."userId" = $1
LIMIT 1`, user.id, user.checkedNotesAt) LIMIT 1`, user.id, user.checkedNotesAt)
if (votes.length > 0) { if (votes.length > 0) {

View File

@ -16,7 +16,7 @@ export default gql`
updateDiscussion(id: ID!, title: String!, text: String): Item! updateDiscussion(id: ID!, title: String!, text: String): Item!
createComment(text: String!, parentId: ID!): Item! createComment(text: String!, parentId: ID!): Item!
updateComment(id: ID!, text: String!): Item! updateComment(id: ID!, text: String!): Item!
vote(id: ID!, sats: Int): Int! act(id: ID!, act: String!, sats: Int): Int!
} }
type Items { type Items {

View File

@ -9,18 +9,18 @@ import ActionTooltip from './action-tooltip'
export default function UpVote ({ itemId, meSats, className }) { export default function UpVote ({ itemId, meSats, className }) {
const [session] = useSession() const [session] = useSession()
const { setError } = useFundError() const { setError } = useFundError()
const [vote] = useMutation( const [act] = useMutation(
gql` gql`
mutation vote($id: ID!, $sats: Int!) { mutation act($id: ID!, $sats: Int!) {
vote(id: $id, sats: $sats) act(id: $id, act: 'VOTE', sats: $sats)
}`, { }`, {
update (cache, { data: { vote } }) { update (cache, { data: { act } }) {
// read in the cached object so we don't use meSats prop // read in the cached object so we don't use meSats prop
// which can be stale // which can be stale
const item = cache.readFragment({ const item = cache.readFragment({
id: `Item:${itemId}`, id: `Item:${itemId}`,
fragment: gql` fragment: gql`
fragment votedItem on Item { fragment actedItem on Item {
meSats meSats
} }
` `
@ -29,13 +29,13 @@ export default function UpVote ({ itemId, meSats, className }) {
id: `Item:${itemId}`, id: `Item:${itemId}`,
fields: { fields: {
meSats (existingMeSats = 0) { meSats (existingMeSats = 0) {
return existingMeSats + vote return existingMeSats + act
}, },
sats (existingSats = 0) { sats (existingSats = 0) {
return item.meSats === 0 ? existingSats + vote : existingSats return item.meSats === 0 ? existingSats + act : existingSats
}, },
boost (existingBoost = 0) { boost (existingBoost = 0) {
return item.meSats >= 1 ? existingBoost + vote : existingBoost return item.meSats >= 1 ? existingBoost + act : existingBoost
} }
} }
}) })
@ -62,7 +62,7 @@ export default function UpVote ({ itemId, meSats, className }) {
strike() strike()
if (!itemId) return if (!itemId) return
try { try {
await vote({ variables: { id: itemId, sats: 1 } }) await act({ variables: { id: itemId, sats: 1 } })
} catch (error) { } catch (error) {
if (error.toString().includes('insufficient funds')) { if (error.toString().includes('insufficient funds')) {
setError(true) setError(true)

View File

@ -5,7 +5,7 @@
*/ */
-- CreateEnum -- CreateEnum
CREATE TYPE "ItemAct" AS ENUM ('VOTE', 'BOOST', 'TIP'); CREATE TYPE "ItemActType" AS ENUM ('VOTE', 'BOOST', 'TIP');
-- DropForeignKey -- DropForeignKey
ALTER TABLE "Vote" DROP CONSTRAINT "Vote_itemId_fkey"; ALTER TABLE "Vote" DROP CONSTRAINT "Vote_itemId_fkey";

View File

@ -11,24 +11,24 @@ generator client {
} }
model User { model User {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
createdAt DateTime @default(now()) @map(name: "created_at") createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @default(now()) @updatedAt @map(name: "updated_at") updatedAt DateTime @default(now()) @updatedAt @map(name: "updated_at")
name String? @unique @db.Citext name String? @unique @db.Citext
email String? @unique email String? @unique
emailVerified DateTime? @map(name: "email_verified") emailVerified DateTime? @map(name: "email_verified")
image String? image String?
items Item[] items Item[]
mentions Mention[] mentions Mention[]
messages Message[] messages Message[]
itemActions ItemAction[] itemActions ItemAct[]
invoices Invoice[] invoices Invoice[]
withdrawls Withdrawl[] withdrawls Withdrawl[]
msats Int @default(0) msats Int @default(0)
freeComments Int @default(5) freeComments Int @default(5)
freePosts Int @default(2) freePosts Int @default(2)
checkedNotesAt DateTime? checkedNotesAt DateTime?
pubkey String? @unique pubkey String? @unique
@@map(name: "users") @@map(name: "users")
} }
@ -60,7 +60,7 @@ 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")
actions ItemAction[] actions ItemAct[]
mentions Mention[] mentions Mention[]
path Unsupported("LTREE")? path Unsupported("LTREE")?
@ -68,26 +68,26 @@ model Item {
@@index([parentId]) @@index([parentId])
} }
enum ItemActionType { enum ItemActType {
VOTE VOTE
BOOST BOOST
TIP TIP
} }
model ItemAction { model ItemAct {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
createdAt DateTime @default(now()) @map(name: "created_at") createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at") updatedAt DateTime @updatedAt @map(name: "updated_at")
sats Int @default(1) sats Int
action ItemActionType @default(VOTE) act ItemActType
item Item @relation(fields: [itemId], references: [id]) item Item @relation(fields: [itemId], references: [id])
itemId Int itemId Int
user User @relation(fields: [userId], references: [id]) user User @relation(fields: [userId], references: [id])
userId Int userId Int
@@index([itemId]) @@index([itemId])
@@index([userId]) @@index([userId])
@@index([action]) @@index([act])
} }
model Mention { model Mention {