Denormalize betAmount
and betOutcome
fields on comments (#838)
* Create and use `betAmount` and `betOutcome` fields on comments * Be robust to ridiculous bet IDs on dev
This commit is contained in:
parent
a15230e7ab
commit
6ef2beed8f
|
@ -23,10 +23,16 @@ export type Comment<T extends AnyCommentType = AnyCommentType> = {
|
||||||
type OnContract = {
|
type OnContract = {
|
||||||
commentType: 'contract'
|
commentType: 'contract'
|
||||||
contractId: string
|
contractId: string
|
||||||
contractSlug: string
|
|
||||||
contractQuestion: string
|
|
||||||
answerOutcome?: string
|
answerOutcome?: string
|
||||||
betId?: string
|
betId?: string
|
||||||
|
|
||||||
|
// denormalized from contract
|
||||||
|
contractSlug: string
|
||||||
|
contractQuestion: string
|
||||||
|
|
||||||
|
// denormalized from bet
|
||||||
|
betAmount?: number
|
||||||
|
betOutcome?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type OnGroup = {
|
type OnGroup = {
|
||||||
|
|
|
@ -63,11 +63,15 @@ export const onCreateCommentOnContract = functions
|
||||||
.doc(comment.betId)
|
.doc(comment.betId)
|
||||||
.get()
|
.get()
|
||||||
bet = betSnapshot.data() as Bet
|
bet = betSnapshot.data() as Bet
|
||||||
|
|
||||||
answer =
|
answer =
|
||||||
contract.outcomeType === 'FREE_RESPONSE' && contract.answers
|
contract.outcomeType === 'FREE_RESPONSE' && contract.answers
|
||||||
? contract.answers.find((answer) => answer.id === bet?.outcome)
|
? contract.answers.find((answer) => answer.id === bet?.outcome)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
|
await change.ref.update({
|
||||||
|
betOutcome: bet.outcome,
|
||||||
|
betAmount: bet.amount,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const comments = await getValues<ContractComment>(
|
const comments = await getValues<ContractComment>(
|
||||||
|
|
69
functions/src/scripts/denormalize-comment-bet-data.ts
Normal file
69
functions/src/scripts/denormalize-comment-bet-data.ts
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// Filling in the bet-based fields on comments.
|
||||||
|
|
||||||
|
import * as admin from 'firebase-admin'
|
||||||
|
import { zip } from 'lodash'
|
||||||
|
import { initAdmin } from './script-init'
|
||||||
|
import {
|
||||||
|
DocumentCorrespondence,
|
||||||
|
findDiffs,
|
||||||
|
describeDiff,
|
||||||
|
applyDiff,
|
||||||
|
} from './denormalize'
|
||||||
|
import { log } from '../utils'
|
||||||
|
import { Transaction } from 'firebase-admin/firestore'
|
||||||
|
|
||||||
|
initAdmin()
|
||||||
|
const firestore = admin.firestore()
|
||||||
|
|
||||||
|
async function getBetComments(transaction: Transaction) {
|
||||||
|
const allComments = await transaction.get(
|
||||||
|
firestore.collectionGroup('comments')
|
||||||
|
)
|
||||||
|
const betComments = allComments.docs.filter((d) => d.get('betId'))
|
||||||
|
log(`Found ${betComments.length} comments associated with bets.`)
|
||||||
|
return betComments
|
||||||
|
}
|
||||||
|
|
||||||
|
async function denormalize() {
|
||||||
|
let hasMore = true
|
||||||
|
while (hasMore) {
|
||||||
|
hasMore = await admin.firestore().runTransaction(async (trans) => {
|
||||||
|
const betComments = await getBetComments(trans)
|
||||||
|
const bets = await Promise.all(
|
||||||
|
betComments.map((doc) =>
|
||||||
|
trans.get(
|
||||||
|
firestore
|
||||||
|
.collection('contracts')
|
||||||
|
.doc(doc.get('contractId'))
|
||||||
|
.collection('bets')
|
||||||
|
.doc(doc.get('betId'))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
log(`Found ${bets.length} bets associated with comments.`)
|
||||||
|
const mapping = zip(bets, betComments)
|
||||||
|
.map(([bet, comment]): DocumentCorrespondence => {
|
||||||
|
return [bet!, [comment!]] // eslint-disable-line
|
||||||
|
})
|
||||||
|
.filter(([bet, _]) => bet.exists) // dev DB has some invalid bet IDs
|
||||||
|
|
||||||
|
const amountDiffs = findDiffs(mapping, 'amount', 'betAmount')
|
||||||
|
const outcomeDiffs = findDiffs(mapping, 'outcome', 'betOutcome')
|
||||||
|
log(`Found ${amountDiffs.length} comments with mismatched amounts.`)
|
||||||
|
log(`Found ${outcomeDiffs.length} comments with mismatched outcomes.`)
|
||||||
|
const diffs = amountDiffs.concat(outcomeDiffs)
|
||||||
|
diffs.slice(0, 500).forEach((d) => {
|
||||||
|
log(describeDiff(d))
|
||||||
|
applyDiff(trans, d)
|
||||||
|
})
|
||||||
|
if (diffs.length > 500) {
|
||||||
|
console.log(`Applying first 500 because of Firestore limit...`)
|
||||||
|
}
|
||||||
|
return diffs.length > 500
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
denormalize().catch((e) => console.error(e))
|
||||||
|
}
|
|
@ -125,15 +125,12 @@ export function FeedComment(props: {
|
||||||
} = props
|
} = props
|
||||||
const { text, content, userUsername, userName, userAvatarUrl, createdTime } =
|
const { text, content, userUsername, userName, userAvatarUrl, createdTime } =
|
||||||
comment
|
comment
|
||||||
let betOutcome: string | undefined,
|
const betOutcome = comment.betOutcome
|
||||||
bought: string | undefined,
|
let bought: string | undefined
|
||||||
money: string | undefined
|
let money: string | undefined
|
||||||
|
if (comment.betAmount != null) {
|
||||||
const matchedBet = betsBySameUser.find((bet) => bet.id === comment.betId)
|
bought = comment.betAmount >= 0 ? 'bought' : 'sold'
|
||||||
if (matchedBet) {
|
money = formatMoney(Math.abs(comment.betAmount))
|
||||||
betOutcome = matchedBet.outcome
|
|
||||||
bought = matchedBet.amount >= 0 ? 'bought' : 'sold'
|
|
||||||
money = formatMoney(Math.abs(matchedBet.amount))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const [highlighted, setHighlighted] = useState(false)
|
const [highlighted, setHighlighted] = useState(false)
|
||||||
|
@ -148,7 +145,7 @@ export function FeedComment(props: {
|
||||||
const { userPosition, outcome } = getBettorsLargestPositionBeforeTime(
|
const { userPosition, outcome } = getBettorsLargestPositionBeforeTime(
|
||||||
contract,
|
contract,
|
||||||
comment.createdTime,
|
comment.createdTime,
|
||||||
matchedBet ? [] : betsBySameUser
|
comment.betId ? [] : betsBySameUser
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -175,7 +172,7 @@ export function FeedComment(props: {
|
||||||
username={userUsername}
|
username={userUsername}
|
||||||
name={userName}
|
name={userName}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
{!matchedBet &&
|
{!comment.betId != null &&
|
||||||
userPosition > 0 &&
|
userPosition > 0 &&
|
||||||
contract.outcomeType !== 'NUMERIC' && (
|
contract.outcomeType !== 'NUMERIC' && (
|
||||||
<>
|
<>
|
||||||
|
@ -194,7 +191,6 @@ export function FeedComment(props: {
|
||||||
of{' '}
|
of{' '}
|
||||||
<OutcomeLabel
|
<OutcomeLabel
|
||||||
outcome={betOutcome ? betOutcome : ''}
|
outcome={betOutcome ? betOutcome : ''}
|
||||||
value={(matchedBet as any).value}
|
|
||||||
contract={contract}
|
contract={contract}
|
||||||
truncate="short"
|
truncate="short"
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user