Initial commit
This commit is contained in:
178
assets/drizzle-schema.ts
Normal file
178
assets/drizzle-schema.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Complete Drizzle Schema Template for Neon/Vercel Postgres
|
||||
*
|
||||
* Usage:
|
||||
* 1. Copy this file to your project: cp assets/drizzle-schema.ts db/schema.ts
|
||||
* 2. Customize tables to match your app's data model
|
||||
* 3. Generate migrations: npx drizzle-kit generate
|
||||
* 4. Apply migrations: npx drizzle-kit migrate
|
||||
*/
|
||||
|
||||
import { pgTable, serial, text, timestamp, integer, boolean, jsonb, index, unique } from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
|
||||
// ============================================================================
|
||||
// USERS TABLE
|
||||
// ============================================================================
|
||||
|
||||
export const users = pgTable('users', {
|
||||
id: serial('id').primaryKey(),
|
||||
email: text('email').notNull().unique(),
|
||||
name: text('name').notNull(),
|
||||
avatar: text('avatar'),
|
||||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
||||
}, (table) => ({
|
||||
// Indexes for common queries
|
||||
emailIdx: index('users_email_idx').on(table.email),
|
||||
}));
|
||||
|
||||
// ============================================================================
|
||||
// POSTS TABLE
|
||||
// ============================================================================
|
||||
|
||||
export const posts = pgTable('posts', {
|
||||
id: serial('id').primaryKey(),
|
||||
userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
|
||||
title: text('title').notNull(),
|
||||
content: text('content'),
|
||||
published: boolean('published').default(false).notNull(),
|
||||
slug: text('slug').notNull().unique(),
|
||||
metadata: jsonb('metadata').$type<{
|
||||
views?: number;
|
||||
likes?: number;
|
||||
tags?: string[];
|
||||
}>(),
|
||||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
||||
}, (table) => ({
|
||||
// Indexes for common queries
|
||||
userIdIdx: index('posts_user_id_idx').on(table.userId),
|
||||
slugIdx: index('posts_slug_idx').on(table.slug),
|
||||
publishedIdx: index('posts_published_idx').on(table.published),
|
||||
}));
|
||||
|
||||
// ============================================================================
|
||||
// COMMENTS TABLE
|
||||
// ============================================================================
|
||||
|
||||
export const comments = pgTable('comments', {
|
||||
id: serial('id').primaryKey(),
|
||||
postId: integer('post_id').notNull().references(() => posts.id, { onDelete: 'cascade' }),
|
||||
userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
|
||||
content: text('content').notNull(),
|
||||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
||||
}, (table) => ({
|
||||
// Indexes for common queries
|
||||
postIdIdx: index('comments_post_id_idx').on(table.postId),
|
||||
userIdIdx: index('comments_user_id_idx').on(table.userId),
|
||||
}));
|
||||
|
||||
// ============================================================================
|
||||
// RELATIONS (for Drizzle query API)
|
||||
// ============================================================================
|
||||
|
||||
export const usersRelations = relations(users, ({ many }) => ({
|
||||
posts: many(posts),
|
||||
comments: many(comments),
|
||||
}));
|
||||
|
||||
export const postsRelations = relations(posts, ({ one, many }) => ({
|
||||
author: one(users, {
|
||||
fields: [posts.userId],
|
||||
references: [users.id],
|
||||
}),
|
||||
comments: many(comments),
|
||||
}));
|
||||
|
||||
export const commentsRelations = relations(comments, ({ one }) => ({
|
||||
post: one(posts, {
|
||||
fields: [comments.postId],
|
||||
references: [posts.id],
|
||||
}),
|
||||
author: one(users, {
|
||||
fields: [comments.userId],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
// ============================================================================
|
||||
// TYPE EXPORTS (for TypeScript)
|
||||
// ============================================================================
|
||||
|
||||
export type User = typeof users.$inferSelect;
|
||||
export type NewUser = typeof users.$inferInsert;
|
||||
|
||||
export type Post = typeof posts.$inferSelect;
|
||||
export type NewPost = typeof posts.$inferInsert;
|
||||
|
||||
export type Comment = typeof comments.$inferSelect;
|
||||
export type NewComment = typeof comments.$inferInsert;
|
||||
|
||||
// ============================================================================
|
||||
// USAGE EXAMPLE
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* db/index.ts:
|
||||
*
|
||||
* import { drizzle } from 'drizzle-orm/neon-http';
|
||||
* import { neon } from '@neondatabase/serverless';
|
||||
* import * as schema from './schema';
|
||||
*
|
||||
* const sql = neon(process.env.DATABASE_URL!);
|
||||
* export const db = drizzle(sql, { schema });
|
||||
*/
|
||||
|
||||
/**
|
||||
* drizzle.config.ts:
|
||||
*
|
||||
* import { defineConfig } from 'drizzle-kit';
|
||||
*
|
||||
* export default defineConfig({
|
||||
* schema: './db/schema.ts',
|
||||
* out: './db/migrations',
|
||||
* dialect: 'postgresql',
|
||||
* dbCredentials: {
|
||||
* url: process.env.DATABASE_URL!
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
|
||||
/**
|
||||
* Query Examples:
|
||||
*
|
||||
* // SELECT with joins
|
||||
* const postsWithAuthors = await db.query.posts.findMany({
|
||||
* with: {
|
||||
* author: true,
|
||||
* comments: {
|
||||
* with: {
|
||||
* author: true
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* // INSERT
|
||||
* const newUser = await db.insert(users).values({
|
||||
* email: 'alice@example.com',
|
||||
* name: 'Alice'
|
||||
* }).returning();
|
||||
*
|
||||
* // UPDATE
|
||||
* await db.update(posts).set({
|
||||
* published: true,
|
||||
* updatedAt: new Date()
|
||||
* }).where(eq(posts.id, postId));
|
||||
*
|
||||
* // DELETE
|
||||
* await db.delete(comments).where(eq(comments.id, commentId));
|
||||
*
|
||||
* // Transaction
|
||||
* await db.transaction(async (tx) => {
|
||||
* const [user] = await tx.insert(users).values({ email, name }).returning();
|
||||
* await tx.insert(posts).values({ userId: user.id, title, content });
|
||||
* });
|
||||
*/
|
||||
14
assets/example-template.txt
Normal file
14
assets/example-template.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
[TODO: Example Template File]
|
||||
|
||||
[TODO: This directory contains files that will be used in the OUTPUT that Claude produces.]
|
||||
|
||||
[TODO: Examples:]
|
||||
- Templates (.html, .tsx, .md)
|
||||
- Images (.png, .svg)
|
||||
- Fonts (.ttf, .woff)
|
||||
- Boilerplate code
|
||||
- Configuration file templates
|
||||
|
||||
[TODO: Delete this file and add your actual assets]
|
||||
|
||||
These files are NOT loaded into context. They are copied or used directly in the final output.
|
||||
Reference in New Issue
Block a user