mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-20 10:04:57 -05:00
PlusTier view
This commit is contained in:
@@ -25,7 +25,7 @@ export function Avatar({
|
||||
className={clsx("avatar", className)}
|
||||
src={
|
||||
discordAvatar
|
||||
? `https://cdn.discordapp.com/avatars/${discordId}/${discordAvatar}.png${
|
||||
? `https://cdn.discordapp.com/avatars/${discordId}/${discordAvatar}.webp${
|
||||
size === "lg" ? "" : "?size=80"
|
||||
}`
|
||||
: "/img/blank.gif" // avoid broken image placeholder
|
||||
|
||||
@@ -5,7 +5,7 @@ import clsx from "clsx";
|
||||
import type { Unpacked } from "~/utils/types";
|
||||
import { useFetcher } from "@remix-run/react";
|
||||
import type { UsersLoaderData } from "~/routes/users";
|
||||
import type { User } from "~/db/types";
|
||||
import type { UserWithPlusTier } from "~/db/types";
|
||||
|
||||
const MAX_RESULTS_SHOWN = 6;
|
||||
|
||||
@@ -97,7 +97,7 @@ export function UserCombobox({
|
||||
inputName,
|
||||
onChange,
|
||||
}: Pick<
|
||||
ComboboxProps<Pick<User, "discordId" | "plusTier">>,
|
||||
ComboboxProps<Pick<UserWithPlusTier, "discordId" | "plusTier">>,
|
||||
"inputName" | "onChange"
|
||||
>) {
|
||||
const fetcher = useFetcher<UsersLoaderData>();
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import * as users from "./models/users.server";
|
||||
import * as plusSuggestions from "./models/plusSuggestions.server";
|
||||
import * as plusVotes from "./models/plusVotes.server";
|
||||
|
||||
export const db = {
|
||||
users,
|
||||
plusSuggestions,
|
||||
plusVotes,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { MonthYear } from "~/core/plus";
|
||||
import { sql } from "../sql";
|
||||
import type { PlusSuggestion, User } from "../types";
|
||||
import type { PlusSuggestion, User, UserWithPlusTier } from "../types";
|
||||
|
||||
const createStm = sql.prepare(`
|
||||
INSERT INTO
|
||||
@@ -79,7 +79,7 @@ export interface FindVisibleForUser {
|
||||
}
|
||||
|
||||
export function findVisibleForUser(
|
||||
args: MonthYear & Pick<User, "plusTier">
|
||||
args: MonthYear & Pick<UserWithPlusTier, "plusTier">
|
||||
): FindVisibleForUser | undefined {
|
||||
if (!args.plusTier) return;
|
||||
return sortNewestPlayersToBeSuggestedFirst(
|
||||
|
||||
40
app/db/models/plusVotes.server.ts
Normal file
40
app/db/models/plusVotes.server.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import { sql } from "../sql";
|
||||
import type { PlusVote } from "../types";
|
||||
|
||||
const createStm = sql.prepare(`
|
||||
INSERT INTO
|
||||
"PlusVote" (
|
||||
"month",
|
||||
"year",
|
||||
"tier",
|
||||
"authorId",
|
||||
"votedId",
|
||||
"score",
|
||||
"validAfter"
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
$month,
|
||||
$year,
|
||||
$tier,
|
||||
$authorId,
|
||||
$votedId,
|
||||
$score,
|
||||
$validAfter
|
||||
)
|
||||
`);
|
||||
|
||||
export type CreateManyPlusVotesArgs = (Pick<
|
||||
PlusVote,
|
||||
"month" | "year" | "tier" | "authorId" | "votedId" | "score"
|
||||
> & { validAfter: Date })[];
|
||||
export const createMany = sql.transaction((votes: CreateManyPlusVotesArgs) => {
|
||||
for (const vote of votes) {
|
||||
const { validAfter, ...rest } = vote;
|
||||
createStm.run({
|
||||
...rest,
|
||||
validAfter: dateToDatabaseTimestamp(validAfter),
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { sql } from "../sql";
|
||||
import type { User } from "../types";
|
||||
import type { User, UserWithPlusTier } from "../types";
|
||||
|
||||
const upsertStm = sql.prepare(`
|
||||
INSERT INTO
|
||||
@@ -58,24 +58,28 @@ export function updateProfile(params: Pick<User, "country" | "id" | "bio">) {
|
||||
}
|
||||
|
||||
const findByIdentifierStm = sql.prepare(`
|
||||
SELECT *
|
||||
SELECT "User".*, "PlusTier".tier as "plusTier"
|
||||
FROM "User"
|
||||
LEFT JOIN "PlusTier" ON "PlusTier"."userId" = "User"."id"
|
||||
WHERE "discordId" = $identifier
|
||||
OR "id" = $identifier
|
||||
`);
|
||||
|
||||
export function findByIdentifier(identifier: string | number) {
|
||||
return findByIdentifierStm.get({ identifier }) as User | undefined;
|
||||
return findByIdentifierStm.get({ identifier }) as
|
||||
| UserWithPlusTier
|
||||
| undefined;
|
||||
}
|
||||
|
||||
const findAllStm = sql.prepare(`
|
||||
SELECT "id", "discordId", "discordName", "discordDiscriminator", "plusTier"
|
||||
SELECT "User"."id", "User"."discordId", "User"."discordName", "User"."discordDiscriminator", "PlusTier".tier as "plusTier"
|
||||
FROM "User"
|
||||
LEFT JOIN "PlusTier" ON "PlusTier"."userId" = "User"."id"
|
||||
`);
|
||||
|
||||
export function findAll() {
|
||||
return findAllStm.all() as Pick<
|
||||
User,
|
||||
UserWithPlusTier,
|
||||
"id" | "discordId" | "discordName" | "discordDiscriminator" | "plusTier"
|
||||
>[];
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
import { lastCompletedVoting } from "~/core/plus";
|
||||
import { db } from "~/db";
|
||||
import { sql } from "~/db/sql";
|
||||
import { faker } from "@faker-js/faker";
|
||||
import type { User } from "~/db/types";
|
||||
import invariant from "tiny-invariant";
|
||||
import { upcomingVoting } from "~/core/plus";
|
||||
import type { CreateManyPlusVotesArgs } from "./models/plusVotes.server";
|
||||
|
||||
const ADMIN_TEST_DISCORD_ID = "79237403620945920";
|
||||
const ADMIN_TEST_AVATAR = "fcfd65a3bea598905abb9ca25296816b";
|
||||
@@ -15,8 +14,8 @@ const basicSeeds = [
|
||||
adminUser,
|
||||
nzapUser,
|
||||
users,
|
||||
plusTierToUsers,
|
||||
plusSuggestions,
|
||||
initialPlusMembers,
|
||||
// thisMonthsSuggestions,
|
||||
];
|
||||
|
||||
export function seed() {
|
||||
@@ -74,37 +73,57 @@ function fakeUser() {
|
||||
};
|
||||
}
|
||||
|
||||
function plusTierToUsers() {
|
||||
sql.prepare(`update "User" set "plusTier" = 3 where id < 150`).run();
|
||||
sql.prepare(`update "User" set "plusTier" = 2 where id < 80`).run();
|
||||
sql.prepare(`update "User" set "plusTier" = 1 where id < 30`).run();
|
||||
function initialPlusMembers() {
|
||||
const votes: CreateManyPlusVotesArgs = [];
|
||||
|
||||
// omit N-ZAP user for testing
|
||||
sql.prepare(`update "User" set "plusTier" = null where id = 2`).run();
|
||||
}
|
||||
const { month, year } = lastCompletedVoting(new Date());
|
||||
|
||||
function plusSuggestions() {
|
||||
const usersInPlus = sql
|
||||
.prepare(`select * from "User" where "plusTier" is not null and "id" != 1`) // exclude admin
|
||||
.all() as User[];
|
||||
const { month, year } = upcomingVoting(new Date());
|
||||
const tier = (id: number) => {
|
||||
if (id < 30) return 1;
|
||||
if (id < 80) return 2;
|
||||
|
||||
for (let userId = 150; userId < 190; userId++) {
|
||||
const amountOfSuggestions = faker.helpers.arrayElement([1, 1, 2, 3, 4]);
|
||||
return 3;
|
||||
};
|
||||
|
||||
for (let i = 0; i < amountOfSuggestions; i++) {
|
||||
const suggester = usersInPlus.shift();
|
||||
invariant(suggester);
|
||||
invariant(suggester.plusTier);
|
||||
for (let id = 1; id < 151; id++) {
|
||||
if (id === 2) continue; // omit N-ZAP user for testing;
|
||||
|
||||
db.plusSuggestions.create({
|
||||
authorId: suggester.id,
|
||||
month,
|
||||
year,
|
||||
suggestedId: userId,
|
||||
text: faker.lorem.lines(),
|
||||
tier: suggester.plusTier,
|
||||
});
|
||||
}
|
||||
votes.push({
|
||||
authorId: 1,
|
||||
month,
|
||||
year,
|
||||
score: 1,
|
||||
tier: tier(id),
|
||||
validAfter: new Date(),
|
||||
votedId: id,
|
||||
});
|
||||
}
|
||||
|
||||
db.plusVotes.createMany(votes);
|
||||
}
|
||||
|
||||
// function thisMonthsSuggestions() {
|
||||
// const usersInPlus = sql
|
||||
// .prepare(`select * from "User" where "plusTier" is not null and "id" != 1`) // exclude admin
|
||||
// .all() as User[];
|
||||
// const { month, year } = upcomingVoting(new Date());
|
||||
|
||||
// for (let userId = 150; userId < 190; userId++) {
|
||||
// const amountOfSuggestions = faker.helpers.arrayElement([1, 1, 2, 3, 4]);
|
||||
|
||||
// for (let i = 0; i < amountOfSuggestions; i++) {
|
||||
// const suggester = usersInPlus.shift();
|
||||
// invariant(suggester);
|
||||
// invariant(suggester.plusTier);
|
||||
|
||||
// db.plusSuggestions.create({
|
||||
// authorId: suggester.id,
|
||||
// month,
|
||||
// year,
|
||||
// suggestedId: userId,
|
||||
// text: faker.lorem.lines(),
|
||||
// tier: suggester.plusTier,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -9,8 +9,11 @@ export interface User {
|
||||
youtubeId: string | null;
|
||||
bio: string | null;
|
||||
country: string | null;
|
||||
// xxx: problem with "votes that you don't have to end"... can we calcualte dynamically?
|
||||
plusTier: number | null;
|
||||
}
|
||||
|
||||
/** User table after joined with PlusTier table */
|
||||
export interface UserWithPlusTier extends User {
|
||||
plusTier: PlusTier["tier"] | null;
|
||||
}
|
||||
|
||||
export interface PlusSuggestion {
|
||||
@@ -31,4 +34,10 @@ export interface PlusVote {
|
||||
authorId: number;
|
||||
votedId: number;
|
||||
score: number;
|
||||
validAfter: number;
|
||||
}
|
||||
|
||||
export interface PlusTier {
|
||||
userId: number;
|
||||
tier: number;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type * as plusSuggestions from "~/db/models/plusSuggestions.server";
|
||||
import { monthsVotingRange } from "./core/plus";
|
||||
import type { PlusSuggestion, User } from "./db/types";
|
||||
import type { PlusSuggestion, User, UserWithPlusTier } from "./db/types";
|
||||
import { allTruthy } from "./utils/arrays";
|
||||
|
||||
// TODO: 1) move "root checkers" to one file and utils to one file 2) make utils const for more terseness
|
||||
|
||||
interface CanAddCommentToSuggestionArgs {
|
||||
user?: Pick<User, "id" | "plusTier">;
|
||||
user?: Pick<UserWithPlusTier, "id" | "plusTier">;
|
||||
suggestions: plusSuggestions.FindVisibleForUser;
|
||||
suggested: Pick<User, "id">;
|
||||
targetPlusTier: NonNullable<User["plusTier"]>;
|
||||
targetPlusTier: NonNullable<UserWithPlusTier["plusTier"]>;
|
||||
}
|
||||
export function canAddCommentToSuggestionFE(
|
||||
args: CanAddCommentToSuggestionArgs
|
||||
@@ -129,7 +129,7 @@ function suggestionHasNoOtherComments({
|
||||
}
|
||||
|
||||
interface CanSuggestNewUserFEArgs {
|
||||
user?: Pick<User, "id" | "plusTier">;
|
||||
user?: Pick<UserWithPlusTier, "id" | "plusTier">;
|
||||
suggestions: plusSuggestions.FindVisibleForUser;
|
||||
}
|
||||
export function canSuggestNewUserFE({
|
||||
@@ -147,8 +147,8 @@ export function canSuggestNewUserFE({
|
||||
}
|
||||
|
||||
interface CanSuggestNewUserBEArgs extends CanSuggestNewUserFEArgs {
|
||||
suggested: Pick<User, "id" | "plusTier">;
|
||||
targetPlusTier: NonNullable<User["plusTier"]>;
|
||||
suggested: Pick<UserWithPlusTier, "id" | "plusTier">;
|
||||
targetPlusTier: NonNullable<UserWithPlusTier["plusTier"]>;
|
||||
}
|
||||
export function canSuggestNewUserBE({
|
||||
user,
|
||||
@@ -176,7 +176,7 @@ function isVotingActive() {
|
||||
);
|
||||
}
|
||||
|
||||
function isPlusServerMember(user?: Pick<User, "plusTier">) {
|
||||
function isPlusServerMember(user?: Pick<UserWithPlusTier, "plusTier">) {
|
||||
return Boolean(user?.plusTier);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import globalStyles from "~/styles/global.css";
|
||||
import layoutStyles from "~/styles/layout.css";
|
||||
import resetStyles from "~/styles/reset.css";
|
||||
import { Layout } from "./components/layout";
|
||||
import type { User } from "./db/types";
|
||||
import type { UserWithPlusTier } from "./db/types";
|
||||
import { getUser } from "./utils/remix";
|
||||
|
||||
export const unstable_shouldReload: ShouldReloadFunction = () => false;
|
||||
@@ -40,7 +40,10 @@ export const meta: MetaFunction = () => ({
|
||||
});
|
||||
|
||||
export interface RootLoaderData {
|
||||
user?: Pick<User, "id" | "discordId" | "discordAvatar" | "plusTier">;
|
||||
user?: Pick<
|
||||
UserWithPlusTier,
|
||||
"id" | "discordId" | "discordAvatar" | "plusTier"
|
||||
>;
|
||||
}
|
||||
|
||||
export const loader: LoaderFunction = async ({ request }) => {
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
} from "~/utils/remix";
|
||||
import { upcomingVoting } from "~/core/plus";
|
||||
import { db } from "~/db";
|
||||
import type { User } from "~/db/types";
|
||||
import type { UserWithPlusTier } from "~/db/types";
|
||||
import { ErrorMessage } from "~/components/ErrorMessage";
|
||||
|
||||
const commentActionSchema = z.object({
|
||||
@@ -169,7 +169,7 @@ function getSelectedUserErrorMessage({
|
||||
}: {
|
||||
suggestions: NonNullable<PlusSuggestionsLoaderData["suggestions"]>;
|
||||
targetPlusTier: number;
|
||||
suggested?: Pick<User, "id" | "plusTier">;
|
||||
suggested?: Pick<UserWithPlusTier, "id" | "plusTier">;
|
||||
}) {
|
||||
if (!suggested) return;
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { LoaderFunction } from "@remix-run/node";
|
||||
import { json } from "@remix-run/node";
|
||||
import { db } from "~/db";
|
||||
import type { User } from "~/db/types";
|
||||
import type { UserWithPlusTier } from "~/db/types";
|
||||
import { discordFullName } from "~/utils/strings";
|
||||
|
||||
export interface UsersLoaderData {
|
||||
users: ({
|
||||
discordFullName: string;
|
||||
} & Pick<User, "id" | "discordId" | "plusTier">)[];
|
||||
} & Pick<UserWithPlusTier, "id" | "discordId" | "plusTier">)[];
|
||||
}
|
||||
|
||||
export const loader: LoaderFunction = () => {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
export function databaseTimestampToDate(timestamp: number) {
|
||||
return new Date(timestamp * 1000);
|
||||
}
|
||||
|
||||
export function dateToDatabaseTimestamp(date: Date) {
|
||||
return Math.floor(date.getTime() / 1000);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ CREATE TABLE "User" (
|
||||
"twitter" text,
|
||||
"youtubeId" text,
|
||||
"bio" text,
|
||||
"country" text,
|
||||
"plusTier" integer
|
||||
"country" text
|
||||
) STRICT;
|
||||
|
||||
---
|
||||
@@ -24,7 +23,13 @@ CREATE TABLE "PlusSuggestion" (
|
||||
"createdAt" integer DEFAULT (strftime('%s', 'now')) NOT NULL,
|
||||
FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE,
|
||||
FOREIGN KEY ("suggestedId") REFERENCES "User"("id") ON DELETE CASCADE,
|
||||
UNIQUE("month", "year", "suggestedId", "authorId", "tier") ON CONFLICT ROLLBACK
|
||||
UNIQUE(
|
||||
"month",
|
||||
"year",
|
||||
"suggestedId",
|
||||
"authorId",
|
||||
"tier"
|
||||
) ON CONFLICT ROLLBACK
|
||||
) STRICT;
|
||||
|
||||
CREATE INDEX plus_suggestion_author_id ON "PlusSuggestion"("authorId");
|
||||
@@ -39,9 +44,61 @@ CREATE TABLE "PlusVote" (
|
||||
"authorId" integer NOT NULL,
|
||||
"votedId" integer NOT NULL,
|
||||
"score" integer NOT NULL,
|
||||
"validAfter" integer NOT NULL,
|
||||
UNIQUE("month", "year", "authorId", "votedId") ON CONFLICT ROLLBACK
|
||||
) STRICT;
|
||||
|
||||
CREATE INDEX plus_vote_author_id ON "PlusVote"("authorId");
|
||||
|
||||
CREATE INDEX plus_vote_voted_id ON "PlusVote"("votedId");
|
||||
CREATE INDEX plus_vote_voted_id ON "PlusVote"("votedId");
|
||||
|
||||
-- 1) Get the latest finished month/year
|
||||
-- 2) Get votes that match this finished month/year then get vote average per user+tier
|
||||
-- 3) Final result is userId + lowest tier with average of 50 or greater
|
||||
CREATE VIEW "PlusTier" AS WITH "LastFinishedVotingMonthsAverages" AS (
|
||||
SELECT
|
||||
votedId,
|
||||
tier,
|
||||
AVG(score) AS average
|
||||
FROM
|
||||
PlusVote
|
||||
WHERE
|
||||
year = (
|
||||
SELECT
|
||||
year
|
||||
FROM
|
||||
PlusVote
|
||||
WHERE
|
||||
validAfter < strftime('%s', 'now')
|
||||
ORDER BY
|
||||
year desc,
|
||||
month desc
|
||||
LIMIT
|
||||
1
|
||||
)
|
||||
AND month = (
|
||||
SELECT
|
||||
month
|
||||
FROM
|
||||
PlusVote
|
||||
WHERE
|
||||
validAfter < strftime('%s', 'now')
|
||||
ORDER BY
|
||||
year desc,
|
||||
month desc
|
||||
LIMIT
|
||||
1
|
||||
)
|
||||
GROUP BY
|
||||
"votedId",
|
||||
tier
|
||||
)
|
||||
SELECT
|
||||
"votedId" as "userId",
|
||||
min(tier) AS tier
|
||||
FROM
|
||||
"LastFinishedVotingMonthsAverages"
|
||||
WHERE
|
||||
average >= 0.5
|
||||
GROUP BY
|
||||
"votedId";
|
||||
@@ -9,7 +9,7 @@
|
||||
"dev:cypress": "cross-env NODE_ENV=test PORT=4455 remix dev",
|
||||
"start": "remix-serve build",
|
||||
"migrate": "node ./migrations/index.mjs",
|
||||
"migrate:reset": "node scripts/delete-db-files.mjs && npm run migrate",
|
||||
"migrate:reset": "node scripts/delete-db-files.mjs && npm run migrate && npm run seed",
|
||||
"seed": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/seed.ts",
|
||||
"seed:cypress": "cross-env NODE_ENV=test npm run seed",
|
||||
"lint:ts": "eslint . --ext .ts,.tsx",
|
||||
|
||||
@@ -1,93 +1,6 @@
|
||||
import { db } from "~/db";
|
||||
import { sql } from "~/db/sql";
|
||||
import { faker } from "@faker-js/faker";
|
||||
import type { User } from "~/db/types";
|
||||
import invariant from "tiny-invariant";
|
||||
import { upcomingVoting } from "~/core/plus";
|
||||
|
||||
const ADMIN_TEST_DISCORD_ID = "79237403620945920";
|
||||
const ADMIN_TEST_AVATAR = "fcfd65a3bea598905abb9ca25296816b";
|
||||
|
||||
const basicSeeds = [adminUser, users, plusTierToUsers, plusSuggestions];
|
||||
|
||||
export function seed() {
|
||||
wipeDB();
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("database wiped...");
|
||||
for (const seedFunc of basicSeeds) {
|
||||
seedFunc();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("seeded!");
|
||||
}
|
||||
|
||||
function wipeDB() {
|
||||
const tablesToDelete = ["User"];
|
||||
|
||||
for (const table of tablesToDelete) {
|
||||
sql.prepare(`delete from "${table}"`).run();
|
||||
}
|
||||
}
|
||||
|
||||
function adminUser() {
|
||||
db.users.upsert({
|
||||
discordDiscriminator: "4059",
|
||||
discordId: ADMIN_TEST_DISCORD_ID,
|
||||
discordName: "Sendou",
|
||||
twitch: "Sendou",
|
||||
youtubeId: "UCWbJLXByvsfQvTcR4HLPs5Q",
|
||||
discordAvatar: ADMIN_TEST_AVATAR,
|
||||
twitter: "sendouc",
|
||||
});
|
||||
}
|
||||
|
||||
function users() {
|
||||
new Array(500).fill(null).map(fakeUser).forEach(db.users.upsert);
|
||||
}
|
||||
|
||||
function fakeUser() {
|
||||
return {
|
||||
discordAvatar: null,
|
||||
discordDiscriminator: String(faker.random.numeric(4)),
|
||||
discordId: String(faker.random.numeric(17)),
|
||||
discordName: faker.random.word(),
|
||||
twitch: null,
|
||||
twitter: null,
|
||||
youtubeId: null,
|
||||
};
|
||||
}
|
||||
|
||||
function plusTierToUsers() {
|
||||
sql.prepare(`update "USER" set "plusTier" = 3 where id < 150`).run();
|
||||
sql.prepare(`update "USER" set "plusTier" = 2 where id < 80`).run();
|
||||
sql.prepare(`update "USER" set "plusTier" = 1 where id < 30`).run();
|
||||
}
|
||||
|
||||
function plusSuggestions() {
|
||||
const usersInPlus = sql
|
||||
.prepare(`select * from "User" where "plusTier" is not null`)
|
||||
.all() as User[];
|
||||
const { month, year } = upcomingVoting(new Date());
|
||||
|
||||
for (let userId = 150; userId < 190; userId++) {
|
||||
const amountOfSuggestions = faker.helpers.arrayElement([1, 1, 2, 3, 4]);
|
||||
|
||||
for (let i = 0; i < amountOfSuggestions; i++) {
|
||||
const suggester = usersInPlus.shift();
|
||||
invariant(suggester);
|
||||
invariant(suggester.plusTier);
|
||||
|
||||
db.plusSuggestions.create({
|
||||
authorId: suggester.id,
|
||||
month,
|
||||
year,
|
||||
suggestedId: userId,
|
||||
text: faker.lorem.lines(),
|
||||
tier: suggester.plusTier,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
/* eslint-disable no-console */
|
||||
import { seed } from "~/db/seed";
|
||||
|
||||
console.log("seeding...");
|
||||
seed();
|
||||
console.log("done!");
|
||||
|
||||
Reference in New Issue
Block a user