shared zod types and drizzle schema

This commit is contained in:
Oliver Bryan
2025-12-13 21:36:32 +00:00
parent b2284b1b30
commit 9d381ca4ff
13 changed files with 1269 additions and 1987 deletions

15
biome.json Normal file
View File

@@ -0,0 +1,15 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.8/schema.json",
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 4,
"lineWidth": 110
},
"css": {
"parser": {
"tailwindDirectives": true
}
}
}

View File

@@ -1,6 +1,6 @@
import { eq, sql, and } from "drizzle-orm"; import { eq, sql, and } from "drizzle-orm";
import { db } from "../client"; import { db } from "../client";
import { Issue } from "../schema"; import { Issue } from "@issue/shared";
export async function createIssue(projectId: number, title: string, description: string) { export async function createIssue(projectId: number, title: string, description: string) {
// prevents two issues with the same unique number // prevents two issues with the same unique number

View File

@@ -1,6 +1,6 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { db } from "../client"; import { db } from "../client";
import { Issue, Project, User } from "../schema"; import { Issue, Project, User } from "@issue/shared";
export async function createProject(blob: string, name: string, ownerId: number) { export async function createProject(blob: string, name: string, ownerId: number) {
const [project] = await db const [project] = await db

View File

@@ -1,6 +1,6 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { db } from "../client"; import { db } from "../client";
import { User } from "../schema"; import { User } from "@issue/shared";
export async function createUser(name: string, username: string) { export async function createUser(name: string, username: string) {
const [user] = await db.insert(User).values({ name, username }).returning(); const [user] = await db.insert(User).values({ name, username }).returning();

View File

@@ -1,5 +1,5 @@
import { db, testDB } from "./db/client"; import { db, testDB } from "./db/client";
import { User } from "./db/schema"; import { User } from "@issue/shared";
import { routes } from "./routes"; import { routes } from "./routes";
import { createDemoData } from "./utils"; import { createDemoData } from "./utils";

View File

@@ -1,35 +1,36 @@
{ {
"name": "@issue/frontend", "name": "@issue/frontend",
"version": "0.1.0", "version": "0.1.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
"preview": "vite preview", "preview": "vite preview",
"tauri": "tauri dev" "tauri": "export __NV_DISABLE_EXPLICIT_SYNC=1 && tauri dev"
}, },
"dependencies": { "dependencies": {
"@radix-ui/react-slot": "^1.2.4", "@issue/shared": "workspace:*",
"@tailwindcss/vite": "^4.1.18", "@radix-ui/react-slot": "^1.2.4",
"@tauri-apps/api": "^2", "@tailwindcss/vite": "^4.1.18",
"@tauri-apps/plugin-opener": "^2", "@tauri-apps/api": "^2",
"class-variance-authority": "^0.7.1", "@tauri-apps/plugin-opener": "^2",
"clsx": "^2.1.1", "class-variance-authority": "^0.7.1",
"lucide-react": "^0.561.0", "clsx": "^2.1.1",
"react": "^19.1.0", "lucide-react": "^0.561.0",
"react-dom": "^19.1.0", "react": "^19.1.0",
"react-router-dom": "^7.10.1", "react-dom": "^19.1.0",
"tailwind-merge": "^3.4.0", "react-router-dom": "^7.10.1",
"tailwindcss": "^4.1.18" "tailwind-merge": "^3.4.0",
}, "tailwindcss": "^4.1.18"
"devDependencies": { },
"@tauri-apps/cli": "^2", "devDependencies": {
"@types/node": "^25.0.1", "@tauri-apps/cli": "^2",
"@types/react": "^19.1.8", "@types/node": "^25.0.1",
"@types/react-dom": "^19.1.6", "@types/react": "^19.1.8",
"@vitejs/plugin-react": "^4.6.0", "@types/react-dom": "^19.1.6",
"tw-animate-css": "^1.4.0", "@vitejs/plugin-react": "^4.6.0",
"typescript": "~5.8.3", "tw-animate-css": "^1.4.0",
"vite": "^7.0.4" "typescript": "~5.8.3",
} "vite": "^7.0.4"
}
} }

View File

@@ -1,17 +1,18 @@
import { CloudSync, RefreshCw } from "lucide-react"; import { CloudSync, RefreshCw } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { IssueRecord } from "@issue/shared";
function Issue({ issue }: { issue: any }) { function Issue({ issue }: { issue: IssueRecord }) {
return ( return (
<div className="w-sm p-4 border"> <div className="w-sm p-4 border">
import {Button} from "@/components/ui/button"; [{issue.id}] {issue.title} [{issue.id}] {issue.title}
</div> </div>
); );
} }
function Index() { function Index() {
const [issues, setIssues] = useState([]); const [issues, setIssues] = useState<IssueRecord[]>([]);
const serverURL = import.meta.env.SERVER_URL?.trim() || "http://localhost:3000"; const serverURL = import.meta.env.SERVER_URL?.trim() || "http://localhost:3000";
@@ -45,14 +46,9 @@ function Index() {
</div> </div>
{issues.length > 0 && ( {issues.length > 0 && (
<> <pre className="w-2xl max-h-96 overflow-auto p-4 border bg-">
{issues.map((issue: any) => ( {JSON.stringify(issues, null, 2)}
<Issue key={issue.id} issue={issue} /> </pre>
))}
<pre className="w-2xl max-h-96 overflow-auto p-4 border bg-">
{JSON.stringify(issues, null, 2)}
</pre>
</>
)} )}
</main> </main>
); );

2
packages/shared/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
dist

View File

@@ -1,13 +1,24 @@
{ {
"name": "@issue/shared", "name": "@issue/shared",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "Shared schemas and types for the issue monorepo",
"main": "index.js", "type": "module",
"scripts": { "main": "dist/index.js",
"test": "echo \"Error: no test specified\" && exit 1" "types": "dist/index.d.ts",
}, "scripts": {
"keywords": [], "build": "tsc",
"author": "", "dev": "tsc --watch"
"license": "ISC", },
"packageManager": "pnpm@10.17.1" "keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.17.1",
"devDependencies": {
"typescript": "^5.8.3"
},
"dependencies": {
"drizzle-orm": "^0.45.0",
"drizzle-zod": "^0.5.1",
"zod": "^3.23.8"
}
} }

View File

@@ -0,0 +1,22 @@
// Drizzle tables
export { User, Project, Issue } from "./schema";
// Types
export type {
UserRecord,
UserInsert,
ProjectRecord,
ProjectInsert,
IssueRecord,
IssueInsert,
} from "./schema";
// Zod schemas
export {
UserSelectSchema,
UserInsertSchema,
ProjectSelectSchema,
ProjectInsertSchema,
IssueSelectSchema,
IssueInsertSchema,
} from "./schema";

View File

@@ -1,4 +1,6 @@
import { integer, pgTable, uniqueIndex, varchar } from "drizzle-orm/pg-core"; import { integer, pgTable, uniqueIndex, varchar } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const User = pgTable("User", { export const User = pgTable("User", {
id: integer().primaryKey().generatedAlwaysAsIdentity(), id: integer().primaryKey().generatedAlwaysAsIdentity(),
@@ -34,3 +36,23 @@ export const Issue = pgTable(
uniqueIndex("unique_project_issue_number").on(t.projectId, t.number), uniqueIndex("unique_project_issue_number").on(t.projectId, t.number),
], ],
); );
// Zod schemas
export const UserSelectSchema = createSelectSchema(User);
export const UserInsertSchema = createInsertSchema(User);
export const ProjectSelectSchema = createSelectSchema(Project);
export const ProjectInsertSchema = createInsertSchema(Project);
export const IssueSelectSchema = createSelectSchema(Issue);
export const IssueInsertSchema = createInsertSchema(Issue);
// Types
export type UserRecord = z.infer<typeof UserSelectSchema>;
export type UserInsert = z.infer<typeof UserInsertSchema>;
export type ProjectRecord = z.infer<typeof ProjectSelectSchema>;
export type ProjectInsert = z.infer<typeof ProjectInsertSchema>;
export type IssueRecord = z.infer<typeof IssueSelectSchema>;
export type IssueInsert = z.infer<typeof IssueInsertSchema>;

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

3052
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff