Skip to content

Commit e16dc4c

Browse files
jherrWaryaWayne
andauthored
feat: Add drizzle (#207)
* (feat) project wide drizzle config This sets the drizzle instance for the project. * small + regular drizzle svg's added the drizzle svg's for demo. * inserts db url to the .env file add's example db url * add's the db + driver chosen by user they can choose, postgres, mysql and sqlite. Each has its own dependencies. * sample to do schema uses the user's chosen db and it's imports to create a todo db. * initialize db instance this creates a db instance to be used for queries throughout the project. It uses the user's chosen driver to set it up. * create info file added info file for drizzle db. let's user choose their db and driver. * example demo route used drizzle orm options to do the queries and test it out. * feat: adding Drizzle * fix: version bump --------- Co-authored-by: Abdullahi Mohamed <[email protected]>
1 parent ce9a597 commit e16dc4c

File tree

9 files changed

+324
-0
lines changed

9 files changed

+324
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<% if (addOnOption.drizzle.database === 'postgresql') { %>
2+
# Database URL for PostgreSQL
3+
DATABASE_URL="postgresql://username:password@localhost:5432/mydb"<% } else if (addOnOption.drizzle.database === 'mysql') { %>
4+
# Database URL for MySQL
5+
DATABASE_URL="mysql://username:password@localhost:3306/mydb"<% } else if (addOnOption.drizzle.database === 'sqlite') { %>
6+
# Database URL for SQLite
7+
DATABASE_URL="file:./dev.db"<% } %>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { config } from "dotenv";
2+
import { defineConfig } from 'drizzle-kit';
3+
4+
config();
5+
6+
export default defineConfig({
7+
out: "./drizzle",
8+
schema: "./src/db/schema.ts",
9+
dialect: '<%= addOnOption.drizzle.database %>',
10+
dbCredentials: {
11+
url: process.env.DATABASE_URL,
12+
},
13+
});
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { config } from 'dotenv'
2+
<% if (addOnOption.drizzle.database === 'postgresql') { %>
3+
import { drizzle } from 'drizzle-orm/node-postgres';
4+
import { Pool } from 'pg';
5+
<% } else if (addOnOption.drizzle.database === 'mysql') {%>
6+
import { drizzle } from 'drizzle-orm/mysql2';
7+
import mysql from 'mysql2/promise';
8+
<% } else if (addOnOption.drizzle.database === 'sqlite') {%>
9+
import { drizzle } from 'drizzle-orm/better-sqlite3';
10+
import Database from 'better-sqlite3';
11+
<% } %>
12+
import * as schema from './schema.ts'
13+
14+
config()
15+
16+
<% if (addOnOption.drizzle.database === 'sqlite') { %>
17+
const sqlite = new Database(process.env.DATABASE_URL!);
18+
export const db = drizzle(sqlite, { schema });
19+
<% } else if (addOnOption.drizzle.database === 'postgresql') { %>
20+
const pool = new Pool({
21+
connectionString: process.env.DATABASE_URL!,
22+
});
23+
export const db = drizzle(pool, { schema });
24+
<% } else if (addOnOption.drizzle.database === 'mysql') { %>
25+
const connection = await mysql.createConnection(process.env.DATABASE_URL!);
26+
export const db = drizzle(connection, { schema });
27+
<% } %>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<% if (addOnOption.drizzle.database === 'postgresql') { %>
2+
import { pgTable, serial, text, timestamp } from
3+
'drizzle-orm/pg-core';
4+
5+
export const todos = pgTable('todos', {
6+
id: serial('id').primaryKey(),
7+
title: text('title').notNull(),
8+
createdAt: timestamp('created_at').defaultNow(),
9+
});
10+
<% } else if (addOnOption.drizzle.database === 'mysql') {
11+
%>
12+
import { mysqlTable, int, text, timestamp } from
13+
'drizzle-orm/mysql-core';
14+
15+
export const todos = mysqlTable('todos', {
16+
id: int('id').primaryKey().autoincrement(),
17+
title: text('title').notNull(),
18+
createdAt: timestamp('created_at', { mode: 'date' }).defaultNow(),
19+
});
20+
<% } else if (addOnOption.drizzle.database === 'sqlite') {
21+
%>
22+
import { sqliteTable, integer, text } from
23+
'drizzle-orm/sqlite-core';
24+
import { sql } from 'drizzle-orm';
25+
26+
export const todos = sqliteTable('todos', {
27+
id: integer('id', { mode: 'number' }).primaryKey({
28+
autoIncrement: true }),
29+
title: text('title').notNull(),
30+
createdAt: integer('created_at', { mode: 'timestamp' }).default(sql`(unixepoch())`),
31+
});
32+
<% } %>
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import { createFileRoute, useRouter } from '@tanstack/react-router'
2+
import { createServerFn } from '@tanstack/react-start'
3+
import { db } from '@/db'
4+
import { desc } from 'drizzle-orm'
5+
import { todos } from '@/db/schema'
6+
7+
const getTodos = createServerFn({
8+
method: 'GET',
9+
}).handler(async () => {
10+
return await db.query.todos.findMany({
11+
orderBy: [desc(todos.createdAt)],
12+
})
13+
})
14+
15+
const createTodo = createServerFn({
16+
method: 'POST',
17+
})
18+
.inputValidator((data: { title: string }) => data)
19+
.handler(async ({ data }) => {
20+
await db.insert(todos).values({ title: data.title })
21+
return { success: true }
22+
})
23+
24+
export const Route = createFileRoute('/demo/drizzle')({
25+
component: DemoDrizzle,
26+
loader: async () => await getTodos(),
27+
})
28+
29+
function DemoDrizzle() {
30+
const router = useRouter()
31+
const todos = Route.useLoaderData()
32+
33+
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
34+
e.preventDefault()
35+
const formData = new FormData(e.target as HTMLFormElement)
36+
const title = formData.get('title') as string
37+
38+
if (!title) return
39+
40+
try {
41+
await createTodo({ data: { title } })
42+
router.invalidate()
43+
;(e.target as HTMLFormElement).reset()
44+
} catch (error) {
45+
console.error('Failed to create todo:', error)
46+
}
47+
}
48+
49+
return (
50+
<div
51+
className="flex items-center justify-center min-h-screen p-4 text-white"
52+
style={{
53+
background:
54+
'linear-gradient(135deg, #0c1a2b 0%, #1a2332 50%, #16202e 100%)',
55+
}}
56+
>
57+
<div
58+
className="w-full max-w-2xl p-8 rounded-xl shadow-2xl border border-white/10"
59+
style={{
60+
background:
61+
'linear-gradient(135deg, rgba(22, 32, 46, 0.95) 0%, rgba(12, 26, 43, 0.95) 100%)',
62+
backdropFilter: 'blur(10px)',
63+
}}
64+
>
65+
<div
66+
className="flex items-center justify-center gap-4 mb-8 p-4 rounded-lg"
67+
style={{
68+
background:
69+
'linear-gradient(90deg, rgba(93, 103, 227, 0.1) 0%, rgba(139, 92, 246, 0.1) 100%)',
70+
border: '1px solid rgba(93, 103, 227, 0.2)',
71+
}}
72+
>
73+
<div className="relative group">
74+
<div className="absolute -inset-2 bg-gradient-to-r from-indigo-500 via-purple-500 to-indigo-500 rounded-lg blur-lg opacity-60 group-hover:opacity-100 transition duration-500"></div>
75+
<div className="relative bg-gradient-to-br from-indigo-600 to-purple-600 p-3 rounded-lg">
76+
<img
77+
src="/drizzle.svg"
78+
alt="Drizzle Logo"
79+
className="w-8 h-8 transform group-hover:scale-110 transition-transform duration-300"
80+
/>
81+
</div>
82+
</div>
83+
<h1 className="text-3xl font-bold bg-gradient-to-r from-indigo-300 via-purple-300 to-indigo-300 text-transparent bg-clip-text">
84+
Drizzle Database Demo
85+
</h1>
86+
</div>
87+
88+
<h2 className="text-2xl font-bold mb-4 text-indigo-200">Todos</h2>
89+
90+
<ul className="space-y-3 mb-6">
91+
{todos.map((todo) => (
92+
<li
93+
key={todo.id}
94+
className="rounded-lg p-4 shadow-md border transition-all hover:scale-[1.02] cursor-pointer group"
95+
style={{
96+
background:
97+
'linear-gradient(135deg, rgba(93, 103, 227, 0.15) 0%, rgba(139, 92, 246, 0.15) 100%)',
98+
borderColor: 'rgba(93, 103, 227, 0.3)',
99+
}}
100+
>
101+
<div className="flex items-center justify-between">
102+
<span className="text-lg font-medium text-white group-hover:text-indigo-200 transition-colors">
103+
{todo.title}
104+
</span>
105+
<span className="text-xs text-indigo-300/70">#{todo.id}</span>
106+
</div>
107+
</li>
108+
))}
109+
{todos.length === 0 && (
110+
<li className="text-center py-8 text-indigo-300/70">
111+
No todos yet. Create one below!
112+
</li>
113+
)}
114+
</ul>
115+
116+
<form onSubmit={handleSubmit} className="flex gap-2">
117+
<input
118+
type="text"
119+
name="title"
120+
placeholder="Add a new todo..."
121+
className="flex-1 px-4 py-3 rounded-lg border focus:outline-none focus:ring-2 transition-all text-white placeholder-indigo-300/50"
122+
style={{
123+
background: 'rgba(93, 103, 227, 0.1)',
124+
borderColor: 'rgba(93, 103, 227, 0.3)',
125+
focusRing: 'rgba(93, 103, 227, 0.5)',
126+
}}
127+
/>
128+
<button
129+
type="submit"
130+
className="px-6 py-3 font-semibold rounded-lg shadow-lg transition-all duration-200 hover:shadow-xl hover:scale-105 active:scale-95 whitespace-nowrap"
131+
style={{
132+
background: 'linear-gradient(135deg, #5d67e3 0%, #8b5cf6 100%)',
133+
color: 'white',
134+
}}
135+
>
136+
Add Todo
137+
</button>
138+
</form>
139+
140+
<div
141+
className="mt-8 p-6 rounded-lg border"
142+
style={{
143+
background: 'rgba(93, 103, 227, 0.05)',
144+
borderColor: 'rgba(93, 103, 227, 0.2)',
145+
}}
146+
>
147+
<h3 className="text-lg font-semibold mb-2 text-indigo-200">
148+
Powered by Drizzle ORM
149+
</h3>
150+
<p className="text-sm text-indigo-300/80 mb-4">
151+
Next-generation ORM for Node.js & TypeScript with PostgreSQL
152+
</p>
153+
<div className="space-y-2 text-sm">
154+
<p className="text-indigo-200 font-medium">Setup Instructions:</p>
155+
<ol className="list-decimal list-inside space-y-2 text-indigo-300/80">
156+
<li>
157+
Configure your{' '}
158+
<code className="px-2 py-1 rounded bg-black/30 text-purple-300">
159+
DATABASE_URL
160+
</code>{' '}
161+
in .env.local
162+
</li>
163+
<li>
164+
Run:{' '}
165+
<code className="px-2 py-1 rounded bg-black/30 text-purple-300">
166+
npx drizzle-kit generate
167+
</code>
168+
</li>
169+
<li>
170+
Run:{' '}
171+
<code className="px-2 py-1 rounded bg-black/30 text-purple-300">
172+
npx drizzle-kit migrate
173+
</code>
174+
</li>
175+
<li>
176+
Optional:{' '}
177+
<code className="px-2 py-1 rounded bg-black/30 text-purple-300">
178+
npx drizzle-kit studio
179+
</code>
180+
</li>
181+
</ol>
182+
</div>
183+
</div>
184+
</div>
185+
</div>
186+
)
187+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "Drizzle",
3+
"description": "Add Drizzle ORM to your application.",
4+
"phase": "add-on",
5+
"type": "add-on",
6+
"priority": 48,
7+
"link": "https://orm.drizzle.team/",
8+
"modes": ["file-router"],
9+
"dependsOn": ["start"],
10+
"options": {
11+
"database": {
12+
"type": "select",
13+
"label": "Database Provider",
14+
"description": "Choose your database provider",
15+
"default": "postgresql",
16+
"options": [
17+
{ "value": "postgresql", "label": "PostgreSQL" },
18+
{ "value": "sqlite", "label": "SQLite" },
19+
{ "value": "mysql", "label": "MySQL" }
20+
]
21+
}
22+
},
23+
"routes": [
24+
{
25+
"icon": "Database",
26+
"url": "/demo/drizzle",
27+
"name": "Drizzle",
28+
"path": "src/routes/demo/drizzle.tsx",
29+
"jsName": "DemoDrizzle"
30+
}
31+
]
32+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"dependencies": {
3+
"drizzle-orm": "^0.39.0",
4+
"drizzle-kit": "^0.30.0"<% if (addOnOption.drizzle.database === 'postgresql') { %>,
5+
"pg": "^8.11.0"<% } %><% if (addOnOption.drizzle.database === 'mysql') { %>,
6+
"mysql2": "^3.6.0"<% } %><% if (addOnOption.drizzle.database === 'sqlite') { %>,
7+
"better-sqlite3": "^9.4.0"<% } %>
8+
},
9+
"devDependencies": {
10+
"dotenv": "^16.0.0",
11+
"tsx": "^4.0.0",
12+
<% if (addOnOption.drizzle.database === 'postgresql') { %>
13+
"@types/pg": "^8.10.0"<% } %><% if (addOnOption.drizzle.database === 'mysql') { %>
14+
"@types/mysql2": "^3.6.0"<% } %><% if (addOnOption.drizzle.database === 'sqlite') { %>
15+
"@types/better-sqlite3": "^7.6.0"<% } %>
16+
},
17+
"scripts": {
18+
"db:generate": "drizzle-kit generate",
19+
"db:migrate": "drizzle-kit migrate",
20+
"db:push": "drizzle-kit push",
21+
"db:pull": "drizzle-kit pull",
22+
"db:studio": "drizzle-kit studio"
23+
}
24+
}
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)