ranking mostly
This commit is contained in:
parent
c82c82bb7b
commit
84b69fc481
|
@ -8,7 +8,6 @@ import models from './models'
|
|||
|
||||
export default async function serverSideClient (req) {
|
||||
const session = await getSession({ req })
|
||||
console.log(session)
|
||||
return new ApolloClient({
|
||||
ssrMode: true,
|
||||
// Instead of "createHttpLink" use SchemaLink here
|
||||
|
|
|
@ -6,14 +6,16 @@ export default {
|
|||
return await models.$queryRaw(`
|
||||
${SELECT}
|
||||
FROM "Item"
|
||||
WHERE "parentId" IS NULL`)
|
||||
${LEFT_JOIN_SATS}
|
||||
WHERE "parentId" IS NULL
|
||||
${ORDER_BY_SATS}`)
|
||||
},
|
||||
recent: async (parent, args, { models }) => {
|
||||
return await models.$queryRaw(`
|
||||
${SELECT}
|
||||
FROM "Item"
|
||||
WHERE "parentId" IS NULL
|
||||
ORDER BY created_at`)
|
||||
ORDER BY created_at DESC`)
|
||||
},
|
||||
item: async (parent, { id }, { models }) => {
|
||||
return (await models.$queryRaw(`
|
||||
|
@ -82,6 +84,18 @@ export default {
|
|||
throw new AuthenticationError('You must be logged in')
|
||||
}
|
||||
|
||||
if (sats <= 0) {
|
||||
throw new UserInputError('Sats must be positive', { argumentName: 'sats' })
|
||||
}
|
||||
|
||||
// check if we've already voted for the item
|
||||
const boosted = await models.vote.findFirst({
|
||||
where: {
|
||||
itemId: parseInt(id),
|
||||
userId: me.id
|
||||
}
|
||||
})
|
||||
|
||||
const data = {
|
||||
sats,
|
||||
item: {
|
||||
|
@ -93,7 +107,8 @@ export default {
|
|||
connect: {
|
||||
name: me.name
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: !!boosted
|
||||
}
|
||||
|
||||
await models.vote.create({ data })
|
||||
|
@ -113,10 +128,17 @@ export default {
|
|||
},
|
||||
comments: async (item, args, { models }) => {
|
||||
const flat = await models.$queryRaw(`
|
||||
${SELECT}
|
||||
FROM "Item"
|
||||
WHERE path <@ (SELECT path FROM "Item" where id = ${item.id}) AND id != ${item.id}
|
||||
ORDER BY "path"`)
|
||||
WITH RECURSIVE base AS (
|
||||
${SELECT}, ARRAY[row_number() OVER (${ORDER_BY_SATS}, "Item".path)] AS sort_path
|
||||
FROM "Item"
|
||||
${LEFT_JOIN_SATS}
|
||||
WHERE "parentId" = ${item.id}
|
||||
UNION ALL
|
||||
${SELECT}, p.sort_path || row_number() OVER (${ORDER_BY_SATS}, "Item".path)
|
||||
FROM base p
|
||||
JOIN "Item" ON ltree2text(subpath("Item"."path", 0, -1)) = p."path"
|
||||
${LEFT_JOIN_SATS})
|
||||
SELECT * FROM base ORDER BY sort_path`)
|
||||
return nestComments(flat, item.id)[0]
|
||||
},
|
||||
sats: async (item, args, { models }) => {
|
||||
|
@ -125,7 +147,21 @@ export default {
|
|||
sats: true
|
||||
},
|
||||
where: {
|
||||
itemId: item.id
|
||||
itemId: item.id,
|
||||
boost: false
|
||||
}
|
||||
})
|
||||
|
||||
return sats
|
||||
},
|
||||
boost: async (item, args, { models }) => {
|
||||
const { sum: { sats } } = await models.vote.aggregate({
|
||||
sum: {
|
||||
sats: true
|
||||
},
|
||||
where: {
|
||||
itemId: item.id,
|
||||
boost: true
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -205,5 +241,14 @@ function nestComments (flat, parentId) {
|
|||
|
||||
// we have to do our own query because ltree is unsupported
|
||||
const SELECT =
|
||||
`SELECT id, created_at as "createdAt", updated_at as "updatedAt", title,
|
||||
text, url, "userId", "parentId", ltree2text("path") AS "path"`
|
||||
`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"`
|
||||
|
||||
const LEFT_JOIN_SATS =
|
||||
`LEFT JOIN (SELECT i.id, SUM("Vote".sats) as sats
|
||||
FROM "Item" i
|
||||
JOIN "Vote" ON i.id = "Vote"."itemId"
|
||||
GROUP BY i.id) x ON "Item".id = x.id`
|
||||
|
||||
const ORDER_BY_SATS =
|
||||
'ORDER BY (x.sats-1)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE \'UTC\') - "Item".created_at))/3600+2, 1.5) DESC NULLS LAST'
|
||||
|
|
|
@ -3,7 +3,6 @@ export default {
|
|||
me: async (parent, args, { models, me }) =>
|
||||
me ? await models.user.findUnique({ where: { id: me.id } }) : null,
|
||||
user: async (parent, { name }, { models }) => {
|
||||
console.log(name)
|
||||
return await models.user.findUnique({ where: { name } })
|
||||
},
|
||||
users: async (parent, args, { models }) =>
|
||||
|
@ -17,7 +16,14 @@ export default {
|
|||
ncomments: async (user, args, { models }) => {
|
||||
return await models.item.count({ where: { userId: user.id, parentId: { not: null } } })
|
||||
},
|
||||
stacked: () => 0,
|
||||
stacked: async (user, args, { models }) => {
|
||||
const [{ sum }] = await models.$queryRaw`
|
||||
SELECT sum("Vote".sats)
|
||||
FROM "Item"
|
||||
LEFT JOIN "Vote" on "Vote"."itemId" = "Item".id
|
||||
WHERE "Item"."userId" = ${user.id}`
|
||||
return sum
|
||||
},
|
||||
sats: () => 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ export default gql`
|
|||
user: User!
|
||||
depth: Int!
|
||||
sats: Int!
|
||||
boost: Int!
|
||||
meSats: Int!
|
||||
ncomments: Int!
|
||||
comments: [Item!]!
|
||||
|
|
|
@ -60,6 +60,11 @@ export default function Comment ({ item, children, replyOpen, includeParent, cac
|
|||
<span>{timeSince(new Date(item.createdAt))}</span>
|
||||
<span> \ </span>
|
||||
<span>{item.sats} sats</span>
|
||||
{!!item.boost &&
|
||||
<>
|
||||
<span> \ </span>
|
||||
<span>{item.boost} boost</span>
|
||||
</>}
|
||||
<span> \ </span>
|
||||
<Link href={`/items/${item.id}`} passHref>
|
||||
<a className='text-reset'>{item.ncomments} replies</a>
|
||||
|
|
|
@ -23,6 +23,11 @@ export default function Item ({ item, rank, children }) {
|
|||
</div>
|
||||
<div className={styles.other}>
|
||||
<span>{item.sats} sats</span>
|
||||
{!!item.boost &&
|
||||
<>
|
||||
<span> \ </span>
|
||||
<span>{item.boost} boost</span>
|
||||
</>}
|
||||
<span> \ </span>
|
||||
<Link href={`/items/${item.id}`} passHref>
|
||||
<a className='text-reset'>{item.ncomments} comments</a>
|
||||
|
|
|
@ -31,6 +31,9 @@ export default function Reply ({ parentId, onSuccess }) {
|
|||
fragmentName: 'CommentsRecursive'
|
||||
})
|
||||
return [newCommentRef, ...existingCommentRefs]
|
||||
},
|
||||
ncomments (existingNComments = 0) {
|
||||
return existingNComments + 1
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -3,23 +3,21 @@ import UpArrow from '../svgs/lightning-arrow.svg'
|
|||
import styles from './upvote.module.css'
|
||||
import { gql, useMutation } from '@apollo/client'
|
||||
|
||||
export default function UpVote ({ itemId, meSats, className, item }) {
|
||||
export default function UpVote ({ itemId, meSats, className }) {
|
||||
const [vote] = useMutation(
|
||||
gql`
|
||||
mutation vote($id: ID!, $sats: Int!) {
|
||||
vote(id: $id, sats: $sats)
|
||||
}`, {
|
||||
update (cache, { data: { vote } }) {
|
||||
if (item) {
|
||||
item.sats += vote
|
||||
item.meSats += vote
|
||||
return
|
||||
}
|
||||
cache.modify({
|
||||
id: `Item:${itemId}`,
|
||||
fields: {
|
||||
sats (existingSats = 0) {
|
||||
return existingSats + vote
|
||||
return existingSats || vote
|
||||
},
|
||||
boost (existingBoost = 0) {
|
||||
return meSats >= 1 ? existingBoost + vote : existingBoost
|
||||
},
|
||||
meSats (existingMeSats = 0) {
|
||||
return existingMeSats + vote
|
||||
|
|
|
@ -10,6 +10,7 @@ export const COMMENT_FIELDS = gql`
|
|||
name
|
||||
}
|
||||
sats
|
||||
boost
|
||||
meSats
|
||||
ncomments
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ export const ITEM_FIELDS = gql`
|
|||
name
|
||||
}
|
||||
sats
|
||||
boost
|
||||
meSats
|
||||
ncomments
|
||||
}`
|
||||
|
|
|
@ -7,12 +7,16 @@ import Comments, { CommentsSkeleton } from '../../components/comments'
|
|||
import { COMMENTS } from '../../fragments/comments'
|
||||
import { ITEM_FIELDS } from '../../fragments/items'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function FullItem ({ item }) {
|
||||
const router = useRouter()
|
||||
const { id } = router.query
|
||||
export async function getServerSideProps ({ params: { id } }) {
|
||||
return {
|
||||
props: {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function FullItem ({ id }) {
|
||||
const query = gql`
|
||||
${ITEM_FIELDS}
|
||||
${COMMENTS}
|
||||
|
|
|
@ -17,7 +17,7 @@ export async function getServerSideProps ({ req, res, query: { callbackUrl, erro
|
|||
Location: callbackUrl
|
||||
})
|
||||
res.end()
|
||||
return
|
||||
return { props: {} }
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
-- DropIndex
|
||||
DROP INDEX "item_gist_path_index";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Vote" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"sats" INTEGER NOT NULL,
|
||||
"itemId" INTEGER NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Vote.itemId_index" ON "Vote"("itemId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Vote.userId_index" ON "Vote"("userId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Vote" ADD FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Vote" ADD FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -1,3 +0,0 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Vote" ADD COLUMN "stimi" BOOLEAN NOT NULL DEFAULT false,
|
||||
ALTER COLUMN "sats" SET DEFAULT 1;
|
|
@ -20,6 +20,7 @@ CREATE TABLE "Message" (
|
|||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
|
||||
-- Edit: create extension for path
|
||||
CREATE EXTENSION ltree;
|
||||
|
||||
|
@ -63,6 +64,19 @@ CREATE TRIGGER path_tgr
|
|||
BEFORE INSERT OR UPDATE ON "Item"
|
||||
FOR EACH ROW EXECUTE PROCEDURE update_item_path();
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Vote" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"sats" INTEGER NOT NULL DEFAULT 1,
|
||||
"boost" BOOLEAN NOT NULL DEFAULT false,
|
||||
"itemId" INTEGER NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "accounts" (
|
||||
"id" SERIAL NOT NULL,
|
||||
|
@ -117,6 +131,12 @@ CREATE INDEX "Item.userId_index" ON "Item"("userId");
|
|||
-- CreateIndex
|
||||
CREATE INDEX "Item.parentId_index" ON "Item"("parentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Vote.itemId_index" ON "Vote"("itemId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Vote.userId_index" ON "Vote"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "accounts.compound_id_unique" ON "accounts"("compound_id");
|
||||
|
||||
|
@ -146,3 +166,9 @@ ALTER TABLE "Item" ADD FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE
|
|||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Item" ADD FOREIGN KEY ("parentId") REFERENCES "Item"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Vote" ADD FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Vote" ADD FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -0,0 +1,39 @@
|
|||
WITH RECURSIVE base AS (
|
||||
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",
|
||||
ARRAY[row_number() OVER (ORDER BY (x.sats-1)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE 'UTC') - "Item".created_at))/3600+2, 1.5) DESC NULLS LAST, "Item"."path")] AS sort_path
|
||||
FROM "Item"
|
||||
LEFT JOIN (SELECT i.id, SUM("Vote".sats) as sats
|
||||
FROM "Item" i
|
||||
JOIN "Vote" ON i.id = "Vote"."itemId"
|
||||
WHERE i."parentId" IS NULL
|
||||
GROUP BY i.id) x ON "Item".id = x.id
|
||||
WHERE "parentId" IS NULL
|
||||
UNION ALL
|
||||
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",
|
||||
p.sort_path || row_number() OVER (ORDER BY (x.sats-1)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE 'UTC') - "Item".created_at))/3600+2, 1.5) DESC NULLS LAST, "Item"."path")
|
||||
FROM base p
|
||||
JOIN "Item" ON ltree2text(subpath("Item"."path", 0, -1)) = p."path"
|
||||
LEFT JOIN (SELECT i.id, SUM("Vote".sats) as sats
|
||||
FROM "Item" i
|
||||
JOIN "Vote" ON i.id = "Vote"."itemId"
|
||||
WHERE i."parentId" IS NULL
|
||||
GROUP BY i.id) x ON "Item".id = x.id
|
||||
)
|
||||
select * from base order by sort_path;
|
||||
|
||||
WITH RECURSIVE base AS (
|
||||
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",
|
||||
ARRAY[row_number() OVER (ORDER BY "Item".created_at, "Item"."path")] AS sort_path
|
||||
FROM "Item"
|
||||
WHERE "parentId" IS NULL
|
||||
UNION ALL
|
||||
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",
|
||||
p.sort_path || row_number() OVER (ORDER BY "Item".created_at, "Item"."path")
|
||||
FROM base p
|
||||
JOIN "Item" ON ltree2text(subpath("Item"."path", 0, -1)) = p."path"
|
||||
)
|
||||
select * from base order by sort_path;
|
|
@ -56,7 +56,7 @@ model Vote {
|
|||
createdAt DateTime @default(now()) @map(name: "created_at")
|
||||
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
||||
sats Int @default(1)
|
||||
stimi Boolean @default(false)
|
||||
boost Boolean @default(false)
|
||||
item Item @relation(fields: [itemId], references: [id])
|
||||
itemId Int
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
|
Loading…
Reference in New Issue