WIP: feat: Create new db app #32

Closed
Ghost wants to merge 6 commits from feat/migrate-to-blitzjs into development
49 changed files with 2724 additions and 41 deletions
Showing only changes of commit 4b26395870 - Show all commits

View File

@ -9,7 +9,8 @@ This is a minimal [Blitz.js](https://github.com/blitz-js/blitz) app.
Run your app in the development mode.
```
blitz dev
yarn blitz p generate
yarn blitz dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

View File

@ -0,0 +1,13 @@
import { Queue } from "quirrel/blitz"
export interface Greetings {
to: string
message: string
}
export default Queue(
"api/greetingsQueue", // the path of this API route
async ({ to, message }: Greetings) => {
console.log(`Greetings, ${to}! Thy ears shall hear: "${message}"`)
}
)

View File

@ -0,0 +1,34 @@
import { CronJob } from "quirrel/blitz"
import { PrismaClient, Item } from '@prisma/client';
import { RawItemData } from '../../core/dto/rawData/RawItemData';
import { propsToClassKey } from "@mui/styles";
export default CronJob(
"api/items/refresh", // the path of this API route
"@daily", // cron schedule (see https://crontab.guru)
async () => {
const itemsResponse = await fetch('https://dev.sp-tarkov.com/SPT-AKI/Server/raw/branch/development/project/assets/database/templates/items.json');
if (itemsResponse.status >= 300) {
throw Error(`Could not retrieve items from Gitea: code ${itemsResponse.status}`)
}
const items: { [id: string]: RawItemData } = await itemsResponse.json();
const prisma: PrismaClient = new PrismaClient();
const promises: any[] = []
Object.entries(items).forEach(
async ([key, value]) => {
const {props, ...data} = RawItemData.fromRawData(value).toItemData();
promises.push(await prisma.item.upsert({
create: {props, ...data},
update: data,
where: {
internalId: data.internalId
},
}))
}
);
await Promise.all(promises);
}
)

View File

@ -0,0 +1,53 @@
import { ReactNode, PropsWithoutRef } from "react"
import { Form as FinalForm, FormProps as FinalFormProps } from "react-final-form"
import { z } from "zod"
import { validateZodSchema } from "blitz"
export { FORM_ERROR } from "final-form"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */
submitText?: string
schema?: S
onSubmit: FinalFormProps<z.infer<S>>["onSubmit"]
initialValues?: FinalFormProps<z.infer<S>>["initialValues"]
}
export function Form<S extends z.ZodType<any, any>>({
children,
submitText,
schema,
initialValues,
onSubmit,
...props
}: FormProps<S>) {
return (
<FinalForm
initialValues={initialValues}
validate={validateZodSchema(schema)}
onSubmit={onSubmit}
render={({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit} className="form" {...props}>
{/* Form fields supplied as children are rendered here */}
{children}
{submitError && (
<div role="alert" style={{ color: "red" }}>
{submitError}
</div>
)}
{submitText && (
<button type="submit" disabled={submitting}>
{submitText}
</button>
)}
</form>
)}
/>
)
}
export default Form

View File

@ -3,4 +3,57 @@ export interface ItemData {
_name: string
_parent?: string
_type?: string
_props: {
Name: string
ShortName: string
Description: string
Weight: number
BackgroundColor: string
Width: number
Height: number
StackMaxSize: number
ItemSound: string
Prefab: {
path: string
rcid: string
}
UsePrefab: {
path: string
rcid: string
}
StackObjectsCount: number
NotShownInSlot: boolean
ExaminedByDefault: boolean
ExamineTime: number
IsUndiscardable: boolean
IsUnsaleable: boolean
IsUnbuyable: boolean
IsUngivable: boolean
IsLockedafterEquip: boolean
QuestItem: boolean
LootExperience: number
ExamineExperience: number
HideEntrails: boolean
RepairCost: number
RepairSpeed: number
ExtraSizeLeft: number
ExtraSizeRight: number
ExtraSizeUp: number
ExtraSizeDown: number
ExtraSizeForceAdd: boolean
MergesWithChildren: boolean
CanSellOnRagfair: boolean
CanRequireOnRagfair: boolean
ConflictingItems: string[]
Unlootable: boolean
UnlootableFromSlot: string
UnlootableFromSide: string[]
AnimationVariantsNumber: number
DiscardingBlock: boolean
RagFairCommissionModifier: number
IsAlwaysAvailableForInsurance: boolean
MaxResource: number
Resource: number
}
_proto?: string
}

View File

@ -0,0 +1,29 @@
import { Prisma } from '@prisma/client';
import { RawItemProps } from './RawItemProps';
export class RawItemData {
_id: string;
_name: string;
_parent: string;
_type: string;
_props: RawItemProps;
_proto?: string | undefined;
static fromRawData(data: any): RawItemData {
const rawData = new RawItemData();
Object.assign(rawData, data)
rawData._props = RawItemProps.fromRawData(data['_props'])
return rawData;
}
toItemData(): Prisma.XOR<Prisma.ItemCreateInput, Prisma.ItemUncheckedCreateInput> {
return {
internalId: this._id,
name: this._name,
type: this._type,
props: this._props.toItemPropsData(),
proto: this._proto
}
}
}

View File

@ -0,0 +1,27 @@
import { Prisma } from "@prisma/client"
export class RawItemPrefab {
id: number
path: string
rcid: string
static fromRawData(data: any): RawItemPrefab {
const rawData = new RawItemPrefab();
Object.assign(rawData, data)
return rawData
}
toItemPrefabData(): Prisma.ItemPrefabCreateNestedOneWithoutItemPropInput {
return {
connectOrCreate: {
where: {
id: this.id
},
create: {
path: this.path,
rcid: this.path
}
}
}
}
}

View File

@ -0,0 +1,77 @@
import { Prisma } from '@prisma/client';
import { RawItemPrefab } from './RawItemPrefab';
import { RawItemUsePrefab } from './RawItemUsePrefab';
export class RawItemProps {
id: number
Name: string
ShortName: string
Description: string
Weight: number
BackgroundColor: string
Width: number
Height: number
StackMaxSize: number
ItemSound: string
Prefab: RawItemPrefab
UsePrefab: RawItemUsePrefab
StackObjectsCount: number
NotShownInSlot: boolean
ExaminedByDefault: boolean
ExamineTime: number
IsUndiscardable: boolean
IsUnsaleable: boolean
IsUnbuyable: boolean
IsUngivable: boolean
IsLockedafterEquip: boolean
QuestItem: boolean
LootExperience: number
ExamineExperience: number
HideEntrails: boolean
RepairCost: number
RepairSpeed: number
ExtraSizeLeft: number
ExtraSizeRight: number
ExtraSizeUp: number
ExtraSizeDown: number
ExtraSizeForceAdd: boolean
MergesWithChildren: boolean
CanSellOnRagfair: boolean
CanRequireOnRagfair: boolean
ConflictingItems: string[]
Unlootable: boolean
UnlootableFromSlot: string
UnlootableFromSide: string[]
AnimationVariantsNumber: number
DiscardingBlock: boolean
RagFairCommissionModifier: number
IsAlwaysAvailableForInsurance: boolean
MaxResource: number
Resource: number
Backgroundcolor: string
IsLockedAfterEquip: boolean
static fromRawData(data: any): RawItemProps {
const rawData = new RawItemProps();
Object.assign(rawData, data)
rawData.Prefab = RawItemPrefab.fromRawData(data['Prefab'])
rawData.UsePrefab = RawItemUsePrefab.fromRawData(data['UsePrefab'])
return rawData
}
toItemPropsData(): Prisma.ItemPropCreateNestedOneWithoutItemInput {
const {id, ...data} = this;
return {
connectOrCreate: {
where: {
id
},
create: {
...data,
Prefab: this.Prefab.toItemPrefabData(),
UsePrefab: this.UsePrefab.toItemUsePrefabData()
}
}
}
}
}

View File

@ -0,0 +1,26 @@
import { Prisma } from '@prisma/client';
export class RawItemUsePrefab {
id: number
path: string
rcid: string
static fromRawData(data: any): RawItemUsePrefab {
const rawData = new RawItemUsePrefab();
Object.assign(rawData, data)
return rawData
}
toItemUsePrefabData(): Prisma.ItemUsePrefabCreateNestedOneWithoutItemPropInput {
return {
connectOrCreate: {
where: {
id: this.id
},
create: {
path: this.path,
rcid: this.rcid
}
}
}
}
}

View File

@ -31,3 +31,5 @@ export const Layout = (props: PropsWithChildren<Props>) => {
</>
)
}
export default Layout ;

View File

@ -0,0 +1,12 @@
import { Form, FormProps } from "app/core/components/Form"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { z } from "zod"
export { FORM_ERROR } from "app/core/components/Form"
export function ItemPrefabForm<S extends z.ZodType<any, any>>(props: FormProps<S>) {
return (
<Form<S> {...props}>
<LabeledTextField name="name" label="Name" placeholder="Name" />
</Form>
)
}

View File

@ -0,0 +1,18 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const CreateItemPrefab = z.object({
name: z.string(),
})
export default resolver.pipe(
resolver.zod(CreateItemPrefab),
resolver.authorize(),
async (input) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemPrefab = await db.itemPrefab.create({ data: input })
return itemPrefab
}
)

View File

@ -0,0 +1,18 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const DeleteItemPrefab = z.object({
id: z.number(),
})
export default resolver.pipe(
resolver.zod(DeleteItemPrefab),
resolver.authorize(),
async ({ id }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemPrefab = await db.itemPrefab.deleteMany({ where: { id } })
return itemPrefab
}
)

View File

@ -0,0 +1,19 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const UpdateItemPrefab = z.object({
id: z.number(),
name: z.string(),
})
export default resolver.pipe(
resolver.zod(UpdateItemPrefab),
resolver.authorize(),
async ({ id, ...data }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemPrefab = await db.itemPrefab.update({ where: { id }, data })
return itemPrefab
}
)

View File

@ -0,0 +1,17 @@
import { resolver, NotFoundError } from "blitz"
import db from "db"
import { z } from "zod"
const GetItemPrefab = z.object({
// This accepts type of undefined, but is required at runtime
id: z.number().optional().refine(Boolean, "Required"),
})
export default resolver.pipe(resolver.zod(GetItemPrefab), resolver.authorize(), async ({ id }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemPrefab = await db.itemPrefab.findFirst({ where: { id } })
if (!itemPrefab) throw new NotFoundError()
return itemPrefab
})

View File

@ -0,0 +1,30 @@
import { paginate, resolver } from "blitz"
import db, { Prisma } from "db"
interface GetItemPrefabsInput
extends Pick<Prisma.ItemPrefabFindManyArgs, "where" | "orderBy" | "skip" | "take"> {}
export default resolver.pipe(
resolver.authorize(),
async ({ where, orderBy, skip = 0, take = 100 }: GetItemPrefabsInput) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const {
items: itemPrefabs,
hasMore,
nextPage,
count,
} = await paginate({
skip,
take,
count: () => db.itemPrefab.count({ where }),
query: (paginateArgs) => db.itemPrefab.findMany({ ...paginateArgs, where, orderBy }),
})
return {
itemPrefabs,
nextPage,
hasMore,
count,
}
}
)

View File

@ -0,0 +1,12 @@
import { Form, FormProps } from "app/core/components/Form"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { z } from "zod"
export { FORM_ERROR } from "app/core/components/Form"
export function ItemPropForm<S extends z.ZodType<any, any>>(props: FormProps<S>) {
return (
<Form<S> {...props}>
<LabeledTextField name="name" label="Name" placeholder="Name" />
</Form>
)
}

View File

@ -0,0 +1,14 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const CreateItemProp = z.object({
name: z.string(),
})
export default resolver.pipe(resolver.zod(CreateItemProp), resolver.authorize(), async (input) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemProp = await db.itemProp.create({ data: input })
return itemProp
})

View File

@ -0,0 +1,14 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const DeleteItemProp = z.object({
id: z.number(),
})
export default resolver.pipe(resolver.zod(DeleteItemProp), resolver.authorize(), async ({ id }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemProp = await db.itemProp.deleteMany({ where: { id } })
return itemProp
})

View File

@ -0,0 +1,19 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const UpdateItemProp = z.object({
id: z.number(),
name: z.string(),
})
export default resolver.pipe(
resolver.zod(UpdateItemProp),
resolver.authorize(),
async ({ id, ...data }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemProp = await db.itemProp.update({ where: { id }, data })
return itemProp
}
)

View File

@ -0,0 +1,17 @@
import { resolver, NotFoundError } from "blitz"
import db from "db"
import { z } from "zod"
const GetItemProp = z.object({
// This accepts type of undefined, but is required at runtime
id: z.number().optional().refine(Boolean, "Required"),
})
export default resolver.pipe(resolver.zod(GetItemProp), resolver.authorize(), async ({ id }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemProp = await db.itemProp.findFirst({ where: { id } })
if (!itemProp) throw new NotFoundError()
return itemProp
})

View File

@ -0,0 +1,30 @@
import { paginate, resolver } from "blitz"
import db, { Prisma } from "db"
interface GetItemPropsInput
extends Pick<Prisma.ItemPropFindManyArgs, "where" | "orderBy" | "skip" | "take"> {}
export default resolver.pipe(
resolver.authorize(),
async ({ where, orderBy, skip = 0, take = 100 }: GetItemPropsInput) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const {
items: itemProps,
hasMore,
nextPage,
count,
} = await paginate({
skip,
take,
count: () => db.itemProp.count({ where }),
query: (paginateArgs) => db.itemProp.findMany({ ...paginateArgs, where, orderBy }),
})
return {
itemProps,
nextPage,
hasMore,
count,
}
}
)

View File

@ -0,0 +1,12 @@
import { Form, FormProps } from "app/core/components/Form"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { z } from "zod"
export { FORM_ERROR } from "app/core/components/Form"
export function ItemUsePrefabForm<S extends z.ZodType<any, any>>(props: FormProps<S>) {
return (
<Form<S> {...props}>
<LabeledTextField name="name" label="Name" placeholder="Name" />
</Form>
)
}

View File

@ -0,0 +1,18 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const CreateItemUsePrefab = z.object({
name: z.string(),
})
export default resolver.pipe(
resolver.zod(CreateItemUsePrefab),
resolver.authorize(),
async (input) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemUsePrefab = await db.itemUsePrefab.create({ data: input })
return itemUsePrefab
}
)

View File

@ -0,0 +1,18 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const DeleteItemUsePrefab = z.object({
id: z.number(),
})
export default resolver.pipe(
resolver.zod(DeleteItemUsePrefab),
resolver.authorize(),
async ({ id }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemUsePrefab = await db.itemUsePrefab.deleteMany({ where: { id } })
return itemUsePrefab
}
)

View File

@ -0,0 +1,19 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const UpdateItemUsePrefab = z.object({
id: z.number(),
name: z.string(),
})
export default resolver.pipe(
resolver.zod(UpdateItemUsePrefab),
resolver.authorize(),
async ({ id, ...data }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemUsePrefab = await db.itemUsePrefab.update({ where: { id }, data })
return itemUsePrefab
}
)

View File

@ -0,0 +1,21 @@
import { resolver, NotFoundError } from "blitz"
import db from "db"
import { z } from "zod"
const GetItemUsePrefab = z.object({
// This accepts type of undefined, but is required at runtime
id: z.number().optional().refine(Boolean, "Required"),
})
export default resolver.pipe(
resolver.zod(GetItemUsePrefab),
resolver.authorize(),
async ({ id }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const itemUsePrefab = await db.itemUsePrefab.findFirst({ where: { id } })
if (!itemUsePrefab) throw new NotFoundError()
return itemUsePrefab
}
)

View File

@ -0,0 +1,30 @@
import { paginate, resolver } from "blitz"
import db, { Prisma } from "db"
interface GetItemUsePrefabsInput
extends Pick<Prisma.ItemUsePrefabFindManyArgs, "where" | "orderBy" | "skip" | "take"> {}
export default resolver.pipe(
resolver.authorize(),
async ({ where, orderBy, skip = 0, take = 100 }: GetItemUsePrefabsInput) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const {
items: itemUsePrefabs,
hasMore,
nextPage,
count,
} = await paginate({
skip,
take,
count: () => db.itemUsePrefab.count({ where }),
query: (paginateArgs) => db.itemUsePrefab.findMany({ ...paginateArgs, where, orderBy }),
})
return {
itemUsePrefabs,
nextPage,
hasMore,
count,
}
}
)

View File

@ -0,0 +1,12 @@
import { Form, FormProps } from "app/core/components/Form"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { z } from "zod"
export { FORM_ERROR } from "app/core/components/Form"
export function ItemForm<S extends z.ZodType<any, any>>(props: FormProps<S>) {
return (
<Form<S> {...props}>
<LabeledTextField name="name" label="Name" placeholder="Name" />
</Form>
)
}

View File

@ -0,0 +1,16 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const CreateItem = z.object({
id: z.number().optional().refine(Boolean, "Required"),
name: z.string().optional().refine(String, "Required"),
type: z.string().optional().refine(String, "Required"),
})
export default resolver.pipe(resolver.zod(CreateItem), resolver.authorize(), async (input) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const item = await db.item.create({ data: input })
return item
})

View File

@ -0,0 +1,14 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const DeleteItem = z.object({
id: z.number(),
})
export default resolver.pipe(resolver.zod(DeleteItem), resolver.authorize(), async ({ id }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const item = await db.item.deleteMany({ where: { id } })
return item
})

View File

@ -0,0 +1,19 @@
import { resolver } from "blitz"
import db from "db"
import { z } from "zod"
const UpdateItem = z.object({
id: z.number(),
name: z.string(),
})
export default resolver.pipe(
resolver.zod(UpdateItem),
resolver.authorize(),
async ({ id, ...data }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const item = await db.item.update({ where: { id }, data })
return item
}
)

View File

@ -0,0 +1,17 @@
import { resolver, NotFoundError } from "blitz"
import db from "db"
import { z } from "zod"
const GetItem = z.object({
// This accepts type of undefined, but is required at runtime
id: z.number().optional().refine(Boolean, "Required")
})
export default resolver.pipe(resolver.zod(GetItem), resolver.authorize(), async ({ id }) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const item = await db.item.findFirst({ where: { id } })
if (!item) throw new NotFoundError()
return item
})

View File

@ -0,0 +1,30 @@
import { paginate, resolver } from "blitz"
import db, { Prisma } from "db"
interface GetItemsInput
extends Pick<Prisma.ItemFindManyArgs, "where" | "orderBy" | "skip" | "take"> {}
export default resolver.pipe(
resolver.authorize(),
async ({ where, orderBy, skip = 0, take = 100 }: GetItemsInput) => {
// TODO: in multi-tenant app, you must add validation to ensure correct tenant
const {
items: items,
hasMore,
nextPage,
count,
} = await paginate({
skip,
take,
count: () => db.item.count({ where }),
query: (paginateArgs) => db.item.findMany({ ...paginateArgs, where, orderBy }),
})
return {
items,
nextPage,
hasMore,
count,
}
}
)

View File

@ -0,0 +1,8 @@
import greetingsQueue from "app/api/greetingsQueue"
export default async function enqueueGreeting() {
await greetingsQueue.enqueue({
to: "Sandy Cheeks",
message: "Howdy!",
})
}

7
db/db/index.ts Normal file
View File

@ -0,0 +1,7 @@
import { enhancePrisma } from "blitz"
import { PrismaClient } from "@prisma/client"
const EnhancedPrisma = enhancePrisma(PrismaClient)
export * from "@prisma/client"
export default new EnhancedPrisma()

View File

@ -0,0 +1,41 @@
-- CreateTable
CREATE TABLE "Item" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"name" TEXT NOT NULL,
"type" TEXT NOT NULL,
"itemId" INTEGER NOT NULL,
CONSTRAINT "Item_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ItemProp" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"name" TEXT NOT NULL,
"shortName" TEXT NOT NULL,
"description" TEXT NOT NULL,
"weight" INTEGER NOT NULL,
"backgroundcolor" TEXT NOT NULL,
"width" INTEGER NOT NULL,
"height" INTEGER NOT NULL,
"stackMaxSize" INTEGER NOT NULL,
"itemSound" TEXT NOT NULL,
"stackObjectsCount" INTEGER NOT NULL,
"notShownInSlot" BOOLEAN NOT NULL,
"examinedByDefault" BOOLEAN NOT NULL,
"examineTime" INTEGER NOT NULL,
"isUndiscardable" BOOLEAN NOT NULL,
"isUnsaleable" BOOLEAN NOT NULL,
"isUnbuyable" BOOLEAN NOT NULL,
"isUngivable" BOOLEAN NOT NULL,
"isLockedAfterEquip" BOOLEAN NOT NULL,
CONSTRAINT "ItemProp_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "Item" ADD CONSTRAINT "Item_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;

View File

@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "ItemPrefab" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"path" TEXT NOT NULL,
"rcid" TEXT NOT NULL,
CONSTRAINT "ItemPrefab_pkey" PRIMARY KEY ("id")
);

View File

@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "ItemUsePrefab" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"path" TEXT NOT NULL,
"rcid" TEXT NOT NULL,
CONSTRAINT "ItemUsePrefab_pkey" PRIMARY KEY ("id")
);

View File

@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "ItemProp" ADD COLUMN "conflictingItems" TEXT[],
ADD COLUMN "unlootableFromSide" TEXT[];

View File

@ -0,0 +1,18 @@
/*
Warnings:
- Added the required column `itemPrefabId` to the `ItemProp` table without a default value. This is not possible if the table is not empty.
- Added the required column `itemProp` to the `ItemProp` table without a default value. This is not possible if the table is not empty.
- Added the required column `itemUsePrefabId` to the `ItemProp` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "ItemProp" ADD COLUMN "itemPrefabId" INTEGER NOT NULL,
ADD COLUMN "itemProp" TEXT NOT NULL,
ADD COLUMN "itemUsePrefabId" INTEGER NOT NULL;
-- AddForeignKey
ALTER TABLE "ItemProp" ADD CONSTRAINT "ItemProp_itemPrefabId_fkey" FOREIGN KEY ("itemPrefabId") REFERENCES "ItemPrefab"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ItemProp" ADD CONSTRAINT "ItemProp_itemUsePrefabId_fkey" FOREIGN KEY ("itemUsePrefabId") REFERENCES "ItemUsePrefab"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -0,0 +1,11 @@
/*
Warnings:
- Added the required column `itemPropId` to the `Item` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "Item" ADD COLUMN "itemPropId" INTEGER NOT NULL;
-- AddForeignKey
ALTER TABLE "Item" ADD CONSTRAINT "Item_itemPropId_fkey" FOREIGN KEY ("itemPropId") REFERENCES "ItemProp"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -0,0 +1,8 @@
/*
Warnings:
- Added the required column `internalId` to the `Item` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "Item" ADD COLUMN "internalId" TEXT NOT NULL;

View File

@ -0,0 +1,8 @@
/*
Warnings:
- A unique constraint covering the columns `[internalId]` on the table `Item` will be added. If there are existing duplicate values, this will fail.
*/
-- CreateIndex
CREATE UNIQUE INDEX "Item_internalId_key" ON "Item"("internalId");

View File

@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"

79
db/db/schema.prisma Normal file
View File

@ -0,0 +1,79 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
// --------------------------------------
model Item {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
type String
parentItem Item? @relation("ItemToItem", fields: [parent], references: [internalId], onDelete: NoAction, onUpdate: NoAction)
Item Item[] @relation("ItemToItem")
parent String
internalId String @unique
props ItemProp @relation(fields: [itemPropId], references: [id])
itemPropId Int
proto String?
}
model ItemProp {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
Name String
ShortName String
Description String
Weight Int
Backgroundcolor String
Width Int
Height Int
StackMaxSize Int
ItemSound String
StackObjectsCount Int
NotShownInSlot Boolean
ExaminedByDefault Boolean
ExamineTime Int
IsUndiscardable Boolean
IsUnsaleable Boolean
IsUnbuyable Boolean
IsUngivable Boolean
IsLockedAfterEquip Boolean
ConflictingItems String[]
UnlootableFromSide String[]
Prefab ItemPrefab @relation(fields: [ItemPrefabId], references: [id])
UsePrefab ItemUsePrefab @relation(fields: [ItemUsePrefabId], references: [id])
ItemPrefabId Int
ItemUsePrefabId Int
Item Item[]
}
model ItemPrefab {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
path String
rcid String
ItemProp ItemProp[]
}
model ItemUsePrefab {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
path String
rcid String
ItemProp ItemProp[]
}

15
db/db/seeds.ts Normal file
View File

@ -0,0 +1,15 @@
// import db from "./index"
/*
* This seed function is executed when you run `blitz db seed`.
*
* Probably you want to use a library like https://chancejs.com
* to easily generate realistic data.
*/
const seed = async () => {
// for (let i = 0; i < 5; i++) {
// await db.project.create({ data: { name: "Project " + i } })
// }
}
export default seed

View File

@ -3,12 +3,14 @@
"version": "1.0.0",
"type": "commonjs",
"scripts": {
"dev": "blitz dev",
"dev": "concurrently --raw \"blitz dev\" 'quirrel'",
"build": "blitz build",
"start": "blitz start",
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
"test": "jest",
"test:watch": "jest --watch"
"test:watch": "jest --watch",
"studio": "blitz prisma studio",
"blitz": "blitz"
},
"prettier": {
"semi": false,
@ -19,26 +21,38 @@
"eslint --fix"
]
},
"prisma": {
"schema": "db/schema.prisma"
},
"engines": {
"node": ">=12.2.0"
},
"dependencies": {
"@emotion/react": "11.x",
"@emotion/styled": "11.x",
"@mui/icons-material": "5.2.4",
"@mui/material": "5.x",
"@mui/styles": "5.x",
"@prisma/client": "3.12.0",
"blitz": "0.44.4",
"final-form": "4.20.6",
"next-themes": "0.0.15",
"quirrel": "1.x",
"react": "18.0.0-beta-149b420f6-20211119",
"react-dom": "18.0.0-alpha-5ca4b0433-20211020",
"react-final-form": "6.5.9",
"react-json-view": "1.21.3",
"zustand": "3.6.7"
},
"devDependencies": {
"@types/react": "17.0.37",
"concurrently": "6.x",
"eslint": "7.32.0",
"lint-staged": "11.3.0-beta.2",
"prettier": "2.5.1",
"pretty-quick": "3.1.2",
"prisma": "3.12.0",
"typescript": "~4.5"
},
"private": true
}
}

File diff suppressed because it is too large Load Diff