mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
Builds migration with seed
This commit is contained in:
parent
1c53c03294
commit
0efff0c907
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -5,6 +5,8 @@ node_modules
|
|||
/public/build
|
||||
.env
|
||||
|
||||
notes.md
|
||||
|
||||
db*.sqlite3*
|
||||
dump
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import * as plusSuggestions from "./models/plusSuggestions/queries.server";
|
|||
import * as plusVotes from "./models/plusVotes/queries.server";
|
||||
import * as badges from "./models/badges/queries.server";
|
||||
import * as calendarEvents from "./models/calendar/queries.server";
|
||||
import * as builds from "./models/builds/queries.server";
|
||||
|
||||
export const db = {
|
||||
users,
|
||||
|
|
@ -10,4 +11,5 @@ export const db = {
|
|||
plusVotes,
|
||||
badges,
|
||||
calendarEvents,
|
||||
builds,
|
||||
};
|
||||
|
|
|
|||
20
app/db/models/builds/createBuild.sql
Normal file
20
app/db/models/builds/createBuild.sql
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
insert into
|
||||
"Build" (
|
||||
"ownerId",
|
||||
"title",
|
||||
"description",
|
||||
"modes",
|
||||
"headGearSplId",
|
||||
"clothesGearSplId",
|
||||
"shoesGearSplId"
|
||||
)
|
||||
values
|
||||
(
|
||||
@ownerId,
|
||||
@title,
|
||||
@description,
|
||||
@modes,
|
||||
@headGearSplId,
|
||||
@clothesGearSplId,
|
||||
@shoesGearSplId
|
||||
) returning *
|
||||
4
app/db/models/builds/createBuildAbility.sql
Normal file
4
app/db/models/builds/createBuildAbility.sql
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
insert into
|
||||
"BuildAbility" ("buildId", "gearType", "ability", "slotIndex")
|
||||
values
|
||||
(@buildId, @gearType, @ability, @slotIndex)
|
||||
4
app/db/models/builds/createBuildWeapon.sql
Normal file
4
app/db/models/builds/createBuildWeapon.sql
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
insert into
|
||||
"BuildWeapon" ("buildId", "weaponSplId")
|
||||
values
|
||||
(@buildId, @weaponSplId)
|
||||
53
app/db/models/builds/queries.server.ts
Normal file
53
app/db/models/builds/queries.server.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { sql } from "~/db/sql";
|
||||
import type { Build, BuildAbility, BuildWeapon } from "~/db/types";
|
||||
import type { Ability, ModeShort } from "~/modules/in-game-lists";
|
||||
import createBuildSql from "./createBuild.sql";
|
||||
import createBuildWeaponSql from "./createBuildWeapon.sql";
|
||||
import createBuildAbilitySql from "./createBuildAbility.sql";
|
||||
|
||||
const createBuildStm = sql.prepare(createBuildSql);
|
||||
const createBuildWeaponStm = sql.prepare(createBuildWeaponSql);
|
||||
const createBuildAbilityStm = sql.prepare(createBuildAbilitySql);
|
||||
|
||||
interface CreateArgs {
|
||||
ownerId: Build["ownerId"];
|
||||
title: Build["title"];
|
||||
description: Build["description"];
|
||||
modes: Array<ModeShort> | null;
|
||||
headGearSplId: Build["headGearSplId"];
|
||||
clothesGearSplId: Build["clothesGearSplId"];
|
||||
shoesGearSplId: Build["shoesGearSplId"];
|
||||
weaponSplIds: Array<BuildWeapon["weaponSplId"]>;
|
||||
abilities: Array<{
|
||||
gearType: BuildAbility["gearType"];
|
||||
ability: Ability;
|
||||
slotIndex: BuildAbility["slotIndex"];
|
||||
}>;
|
||||
}
|
||||
export const create = sql.transaction((build: CreateArgs) => {
|
||||
const createdBuild = createBuildStm.get({
|
||||
ownerId: build.ownerId,
|
||||
title: build.title,
|
||||
description: build.description,
|
||||
modes: build.modes?.join(",") ?? null,
|
||||
headGearSplId: build.headGearSplId,
|
||||
clothesGearSplId: build.clothesGearSplId,
|
||||
shoesGearSplId: build.shoesGearSplId,
|
||||
}) as Build;
|
||||
|
||||
for (const weaponSplId of build.weaponSplIds) {
|
||||
createBuildWeaponStm.run({
|
||||
buildId: createdBuild.id,
|
||||
weaponSplId,
|
||||
});
|
||||
}
|
||||
|
||||
for (const { gearType, ability, slotIndex } of build.abilities) {
|
||||
createBuildAbilityStm.run({
|
||||
buildId: createdBuild.id,
|
||||
gearType,
|
||||
ability,
|
||||
slotIndex,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -1,17 +1,25 @@
|
|||
import { faker } from "@faker-js/faker";
|
||||
import capitalize from "just-capitalize";
|
||||
import shuffle from "just-shuffle";
|
||||
import invariant from "tiny-invariant";
|
||||
import { ADMIN_DISCORD_ID } from "~/constants";
|
||||
import { db } from "~/db";
|
||||
import { sql } from "~/db/sql";
|
||||
import {
|
||||
abilityCodes,
|
||||
clothesGearIds,
|
||||
headGearIds,
|
||||
modesShort,
|
||||
shoesGearIds,
|
||||
weaponIds,
|
||||
} from "~/modules/in-game-lists";
|
||||
import {
|
||||
lastCompletedVoting,
|
||||
nextNonCompletedVoting,
|
||||
} from "~/modules/plus-server";
|
||||
import { db } from "~/db";
|
||||
import { sql } from "~/db/sql";
|
||||
import type { UpsertManyPlusVotesArgs } from "./models/plusVotes/queries.server";
|
||||
import { ADMIN_DISCORD_ID } from "~/constants";
|
||||
import shuffle from "just-shuffle";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import capitalize from "just-capitalize";
|
||||
import allTags from "~/routes/calendar/tags.json";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import type { UpsertManyPlusVotesArgs } from "./models/plusVotes/queries.server";
|
||||
|
||||
const ADMIN_TEST_AVATAR = "e424e1ba50d2019fdc4730d261e56c55";
|
||||
|
||||
|
|
@ -36,6 +44,7 @@ const basicSeeds = [
|
|||
calendarEvents,
|
||||
calendarEventBadges,
|
||||
calendarEventResults,
|
||||
adminBuilds,
|
||||
];
|
||||
|
||||
export function seed() {
|
||||
|
|
@ -486,3 +495,63 @@ function calendarEventResults() {
|
|||
userIds = userIdsInRandomOrder();
|
||||
}
|
||||
}
|
||||
|
||||
function adminBuilds() {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const randomOrderHeadGear = shuffle(headGearIds.slice());
|
||||
const randomOrderClothesGear = shuffle(clothesGearIds.slice());
|
||||
const randomOrderShoesGear = shuffle(shoesGearIds.slice());
|
||||
const randomOrderWeaponIds = shuffle(weaponIds.slice());
|
||||
|
||||
db.builds.create({
|
||||
title: `${capitalize(faker.word.adjective())} ${capitalize(
|
||||
faker.word.noun()
|
||||
)}`,
|
||||
ownerId: 1,
|
||||
description: Math.random() < 0.75 ? faker.lorem.paragraph() : null,
|
||||
clothesGearSplId: randomOrderHeadGear[0]!,
|
||||
headGearSplId: randomOrderClothesGear[0]!,
|
||||
shoesGearSplId: randomOrderShoesGear[0]!,
|
||||
weaponSplIds: new Array(
|
||||
faker.helpers.arrayElement([1, 1, 1, 2, 2, 3, 4, 5, 6])
|
||||
)
|
||||
.fill(null)
|
||||
.map(() => randomOrderWeaponIds.pop()!),
|
||||
modes:
|
||||
Math.random() < 0.75
|
||||
? modesShort.filter(() => Math.random() < 0.5)
|
||||
: null,
|
||||
abilities: new Array(12).fill(null).map((_, i) => {
|
||||
const gearType = i < 4 ? "HEAD" : i < 8 ? "CLOTHES" : "SHOES";
|
||||
|
||||
const randomOrderAbilities = shuffle([...abilityCodes]);
|
||||
|
||||
const getAbility = () => {
|
||||
const legalAbilityForSlot = randomOrderAbilities.find((ability) => {
|
||||
if (ability.type === "HEAD_ONLY" && gearType !== "HEAD") {
|
||||
return false;
|
||||
}
|
||||
if (ability.type === "CLOTHES_ONLY" && gearType !== "CLOTHES") {
|
||||
return false;
|
||||
}
|
||||
if (ability.type === "SHOES_ONLY" && gearType !== "SHOES") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
invariant(legalAbilityForSlot);
|
||||
|
||||
return legalAbilityForSlot.name;
|
||||
};
|
||||
|
||||
return {
|
||||
ability: getAbility(),
|
||||
gearType,
|
||||
slotIndex: (i % 4) as any,
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import type { Ability } from "~/modules/in-game-lists";
|
||||
import type allTags from "../routes/calendar/tags.json";
|
||||
|
||||
export interface User {
|
||||
|
|
@ -117,3 +118,27 @@ export interface CalendarEventBadge {
|
|||
eventId: number;
|
||||
badgeId: number;
|
||||
}
|
||||
|
||||
export interface Build {
|
||||
id: number;
|
||||
ownerId: number;
|
||||
title: string;
|
||||
description: string | null;
|
||||
modes: string | null;
|
||||
headGearSplId: number;
|
||||
clothesGearSplId: number;
|
||||
shoesGearSplId: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
export interface BuildWeapon {
|
||||
buildId: number;
|
||||
weaponSplId: number;
|
||||
}
|
||||
|
||||
export interface BuildAbility {
|
||||
buildId: number;
|
||||
gearType: "HEAD" | "CLOTHES" | "SHOES";
|
||||
ability: Ability;
|
||||
slotIndex: 0 | 1 | 2 | 3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,4 @@
|
|||
export type AbilityType =
|
||||
| "STACKABLE"
|
||||
| "HEAD_ONLY"
|
||||
| "CLOTHES_ONLY"
|
||||
| "SHOES_ONLY";
|
||||
|
||||
export const abilityCodes: Readonly<
|
||||
Array<{ name: string; type: AbilityType }>
|
||||
> = [
|
||||
export const abilityCodes = [
|
||||
{ name: "AD", type: "CLOTHES_ONLY" },
|
||||
{ name: "BRU", type: "STACKABLE" },
|
||||
{ name: "CB", type: "HEAD_ONLY" },
|
||||
|
|
@ -34,3 +26,5 @@ export const abilityCodes: Readonly<
|
|||
{ name: "T", type: "CLOTHES_ONLY" },
|
||||
{ name: "TI", type: "CLOTHES_ONLY" },
|
||||
] as const;
|
||||
|
||||
export const abilitiesShort = abilityCodes.map((ability) => ability.name);
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ export { stages } from "./stages";
|
|||
export { modes, modesShort } from "./modes";
|
||||
export { weaponIds } from "./weapon-ids";
|
||||
export { headGearIds, clothesGearIds, shoesGearIds } from "./gear-ids";
|
||||
export type { ModeShort, Stage } from "./types";
|
||||
export { abilitiesShort, abilityCodes } from "./abilities";
|
||||
export type { Ability, AbilityType, ModeShort, Stage } from "./types";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import type { abilityCodes } from "./abilities";
|
||||
import type { modes } from "./modes";
|
||||
import type { stages } from "./stages";
|
||||
|
||||
export type ModeShort = typeof modes[number]["short"];
|
||||
|
||||
export type Stage = typeof stages[number];
|
||||
|
||||
export type Ability = typeof abilityCodes[number]["name"];
|
||||
export type AbilityType = typeof abilityCodes[number]["type"];
|
||||
|
|
|
|||
48
migrations/007-builds.js
Normal file
48
migrations/007-builds.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
module.exports.up = function (db) {
|
||||
db.prepare(
|
||||
`
|
||||
create table "Build" (
|
||||
"id" integer primary key,
|
||||
"ownerId" integer not null,
|
||||
"title" text not null,
|
||||
"description" text,
|
||||
"modes" text,
|
||||
"headGearSplId" integer not null,
|
||||
"clothesGearSplId" integer not null,
|
||||
"shoesGearSplId" integer not null,
|
||||
"updatedAt" integer default (strftime('%s', 'now')) not null,
|
||||
foreign key ("ownerId") references "User"("id") on delete restrict
|
||||
) strict
|
||||
`
|
||||
).run();
|
||||
|
||||
db.prepare(
|
||||
`
|
||||
create table "BuildWeapon" (
|
||||
"buildId" integer not null,
|
||||
"weaponSplId" integer not null,
|
||||
foreign key ("buildId") references "Build"("id") on delete cascade,
|
||||
unique("buildId", "weaponSplId") on conflict rollback
|
||||
) strict
|
||||
`
|
||||
).run();
|
||||
|
||||
db.prepare(
|
||||
`
|
||||
create table "BuildAbility" (
|
||||
"buildId" integer not null,
|
||||
"gearType" text not null,
|
||||
"ability" text not null,
|
||||
"slotIndex" integer not null,
|
||||
foreign key ("buildId") references "Build"("id") on delete cascade,
|
||||
unique("buildId", "gearType", "slotIndex") on conflict rollback
|
||||
) strict
|
||||
`
|
||||
).run();
|
||||
};
|
||||
|
||||
module.exports.down = function (db) {
|
||||
for (const table of ["Build", "BuildWeapon", "BuildAbility"]) {
|
||||
db.prepare(`drop table "${table}"`).run();
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user