<html lang="en">
<head></head>
<body>

<form id="mainForm" method="post" action="https://stackblitz.com/run" target="_self">
<input type="hidden" name="project[files][README.md]" value="# SQLite Raw Example

This example demonstrates using the raw SQLite driver with RivetKit actors.

## Getting Started

```sh
git clone https://github.com/rivet-dev/rivet.git
cd rivet/examples/sqlite-raw
npm install
npm run dev
```


## Features

- **Raw SQLite API**: Direct SQL access using `@rivetkit/db/raw`
- **Migrations on Wake**: Uses `onMigrate` to create tables on actor wake
- **Todo List**: Simple CRUD operations with raw SQL queries

## Running the Example

```bash
pnpm install
pnpm dev
```

## Usage

The example creates a `todoList` actor with the following actions:

- `addTodo(title: string)` - Add a new todo
- `getTodos()` - Get all todos
- `toggleTodo(id: number)` - Toggle todo completion status
- `deleteTodo(id: number)` - Delete a todo

## Code Structure

- `src/registry.ts` - Actor definition with database configuration
- `src/server.ts` - Server entry point

## Database

The database uses the KV-backed SQLite VFS, which stores data in a key-value store. The schema is created using raw SQL in the `onMigrate` hook:

```typescript
db: db({
  onMigrate: async (db) =&gt; {
    await db.execute(`
      CREATE TABLE IF NOT EXISTS todos (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        completed INTEGER DEFAULT 0,
        created_at INTEGER NOT NULL
      )
    `);
  },
})
```

## License

MIT
">
<input type="hidden" name="project[files][package.json]" value="{&quot;name&quot;:&quot;example-sqlite-raw&quot;,&quot;version&quot;:&quot;2.0.21&quot;,&quot;private&quot;:true,&quot;type&quot;:&quot;module&quot;,&quot;scripts&quot;:{&quot;dev&quot;:&quot;tsx --watch src/server.ts&quot;,&quot;check-types&quot;:&quot;tsc --noEmit&quot;,&quot;build&quot;:&quot;tsc&quot;,&quot;client&quot;:&quot;tsx scripts/client.ts&quot;},&quot;devDependencies&quot;:{&quot;@types/node&quot;:&quot;^22.13.9&quot;,&quot;rivetkit&quot;:&quot;https://pkg.pr.new/rivet-dev/rivet/rivetkit@0e58cd14238160021017f05b930856e0bed07253&quot;,&quot;tsx&quot;:&quot;^3.12.7&quot;,&quot;typescript&quot;:&quot;^5.5.2&quot;},&quot;dependencies&quot;:{},&quot;stableVersion&quot;:&quot;0.8.0&quot;,&quot;license&quot;:&quot;MIT&quot;}">
<input type="hidden" name="project[files][tsconfig.json]" value="{
	&quot;extends&quot;: &quot;../../tsconfig.base.json&quot;,
	&quot;compilerOptions&quot;: {
		&quot;baseUrl&quot;: &quot;.&quot;,
		&quot;paths&quot;: {
			&quot;@/*&quot;: [&quot;./src/*&quot;]
		}
	},
	&quot;include&quot;: [&quot;src/**/*&quot;]
}
">
<input type="hidden" name="project[files][turbo.json]" value="{
	&quot;$schema&quot;: &quot;https://turbo.build/schema.json&quot;,
	&quot;extends&quot;: [&quot;//&quot;]
}
">
<input type="hidden" name="project[files][scripts/client.ts]" value="import { createClient } from &quot;rivetkit/client&quot;;
import type { registry } from &quot;../src/registry.js&quot;;

// Get endpoint from environment variable or default to localhost
const endpoint = process.env.RIVETKIT_ENDPOINT ?? &quot;http://localhost:8080&quot;;
console.log(&quot;🔗 Using endpoint:&quot;, endpoint);

// Create RivetKit client
const client = createClient&lt;typeof registry&gt;(endpoint);

async function main() {
	console.log(&quot;🚀 SQLite Raw Database Demo&quot;);

	try {
		// Create todo list instance
		const todoList = client.todoList.getOrCreate(&quot;my-todos&quot;);

		// Add some todos
		console.log(&quot;\n📝 Adding todos...&quot;);
		const todo1 = await todoList.addTodo(&quot;Buy groceries&quot;);
		console.log(&quot;Added:&quot;, todo1);

		const todo2 = await todoList.addTodo(&quot;Write documentation&quot;);
		console.log(&quot;Added:&quot;, todo2);

		const todo3 = await todoList.addTodo(&quot;Review pull requests&quot;);
		console.log(&quot;Added:&quot;, todo3);

		// Get all todos
		console.log(&quot;\n📋 Getting all todos...&quot;);
		const todos = await todoList.getTodos();
		console.log(&quot;Todos:&quot;, todos);

		// Toggle a todo (assuming first todo has id 1)
		console.log(&quot;\n✅ Toggling first todo...&quot;);
		const toggled = await todoList.toggleTodo(1);
		console.log(&quot;Toggled:&quot;, toggled);

		// Get todos again to see the change
		console.log(&quot;\n📋 Getting all todos after toggle...&quot;);
		const todosAfterToggle = await todoList.getTodos();
		console.log(&quot;Todos:&quot;, todosAfterToggle);

		// Delete a todo (assuming second todo has id 2)
		console.log(&quot;\n🗑️ Deleting second todo...&quot;);
		const deleted = await todoList.deleteTodo(2);
		console.log(&quot;Deleted:&quot;, deleted);

		// Get todos one more time
		console.log(&quot;\n📋 Final todos list...&quot;);
		const finalTodos = await todoList.getTodos();
		console.log(&quot;Todos:&quot;, finalTodos);

		console.log(&quot;\n✅ Demo completed!&quot;);
	} catch (error) {
		console.error(&quot;❌ Error:&quot;, error);
		process.exit(1);
	}
}

main().catch(console.error);
">
<input type="hidden" name="project[files][src/registry.js]" value="import { actor, setup } from &quot;rivetkit&quot;;
import { db } from &quot;rivetkit/db&quot;;
export const todoList = actor({
    db: db({
        onMigrate: async (db) =&gt; {
            // Run migrations on wake
            await db.execute(`
				CREATE TABLE IF NOT EXISTS todos (
					id INTEGER PRIMARY KEY AUTOINCREMENT,
					title TEXT NOT NULL,
					completed INTEGER DEFAULT 0,
					created_at INTEGER NOT NULL
				)
			`);
        },
    }),
    actions: {
        addTodo: async (c, title) =&gt; {
            const createdAt = Date.now();
            await c.db.execute(&quot;INSERT INTO todos (title, created_at) VALUES (?, ?)&quot;, title, createdAt);
            return { title, createdAt };
        },
        getTodos: async (c) =&gt; {
            const rows = await c.db.execute(&quot;SELECT * FROM todos ORDER BY created_at DESC&quot;);
            return rows;
        },
        toggleTodo: async (c, id) =&gt; {
            await c.db.execute(&quot;UPDATE todos SET completed = NOT completed WHERE id = ?&quot;, id);
            const rows = await c.db.execute(&quot;SELECT * FROM todos WHERE id = ?&quot;, id);
            return rows[0];
        },
        deleteTodo: async (c, id) =&gt; {
            await c.db.execute(&quot;DELETE FROM todos WHERE id = ?&quot;, id);
            return { id };
        },
    },
});
export const registry = setup({
    use: { todoList },
});
">
<input type="hidden" name="project[files][src/registry.ts]" value="import { actor, setup } from &quot;rivetkit&quot;;
import { db } from &quot;rivetkit/db&quot;;

export const todoList = actor({
	db: db({
		onMigrate: async (db) =&gt; {
			// Run migrations on wake
			await db.execute(`
				CREATE TABLE IF NOT EXISTS todos (
					id INTEGER PRIMARY KEY AUTOINCREMENT,
					title TEXT NOT NULL,
					completed INTEGER DEFAULT 0,
					created_at INTEGER NOT NULL
				)
			`);
		},
	}),
	actions: {
		addTodo: async (c, title: string) =&gt; {
			const createdAt = Date.now();
			await c.db.execute(
				&quot;INSERT INTO todos (title, created_at) VALUES (?, ?)&quot;,
				title,
				createdAt,
			);
			return { title, createdAt };
		},
		getTodos: async (c) =&gt; {
			const rows = await c.db.execute(&quot;SELECT * FROM todos ORDER BY created_at DESC&quot;);
			return rows;
		},
		toggleTodo: async (c, id: number) =&gt; {
			await c.db.execute(
				&quot;UPDATE todos SET completed = NOT completed WHERE id = ?&quot;,
				id,
			);
			const rows = await c.db.execute(&quot;SELECT * FROM todos WHERE id = ?&quot;, id);
			return rows[0];
		},
		deleteTodo: async (c, id: number) =&gt; {
			await c.db.execute(&quot;DELETE FROM todos WHERE id = ?&quot;, id);
			return { id };
		},
	},
});

export const registry = setup({
	use: { todoList },
});
">
<input type="hidden" name="project[files][src/server.js]" value="import { registry } from &quot;./registry&quot;;
registry.start();
">
<input type="hidden" name="project[files][src/server.ts]" value="import { registry } from &quot;./registry&quot;;

registry.start();
">
<input type="hidden" name="project[description]" value="generated by https://pkg.pr.new">
<input type="hidden" name="project[template]" value="node">
<input type="hidden" name="project[title]" value="example-sqlite-raw">
</form>
<script>document.getElementById("mainForm").submit();</script>

</body></html>