Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: experimental database layer #1351

Merged
merged 14 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ playground/firebase.json
.zeabur

test/fixture/functions
.data

.pnpm-store
.wrangler
File renamed without changes.
File renamed without changes.
11 changes: 8 additions & 3 deletions docs/1.guide/8.websocket.md β†’ docs/1.guide/3.websocket.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ Nitro natively supports runtime agnostic [WebSocket](https://developer.mozilla.o

:read-more{title="CrossWS" to="https://crossws.unjs.io/"}

## Opt-in to the experimental feature

> [!IMPORTANT]
> WebSockets support is currently experimental and available in [nightly channel](/guide/nightly).
> See [unjs/nitro#2171](https://github.com/unjs/nitro/issues/2171) for platform support status.

## Usage

Enable experimental flag first:
In order to enable database layer you need to enable experimental feature flag.

::code-group
```ts [nitro.config.ts]
Expand All @@ -40,8 +40,13 @@ export default defineNuxtConfig({
```
::

## Usage

Create a websocket handler in `routes/_ws.ts` (or `server/routes/_ws.ts` for Nuxt).

> [!TIP]
> You can use any route like `routes/chatroom.ts` to register upgrade handler on `/chatroom`.

<!-- automd:file code src="../../examples/websocket/routes/_ws.ts" -->

```ts [_ws.ts]
Expand Down
24 changes: 13 additions & 11 deletions docs/1.guide/4.storage.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
---
icon: ri:database-2-line
icon: carbon:datastore
---

# Storage
# KV Storage

> Nitro provides a built-in storage layer that can abstract filesystem or database or any other data source.

Nitro has built-in integration with [unjs/unstorage](https://unstorage.unjs.io) to provide a runtime agnostic persistent layer.

## Usage

To use the storage layer, you can use the `useStorage()` and call `getItem(key)` to retrieve an item and `setItem(key, value)` to set an item.

```ts
// Default storage is in memory
await useStorage().setItem('test:foo', { hello: 'world' })
await useStorage().getItem('test:foo')

// You can also specify the base in useStorage(base)
await useStorage('test').setItem('foo', { hello: 'world' })
// `useStorage` and chained functions support a generic type to infer the return type

// You can use data storage to write data to default .data/kv directory
const dataStorage = useStorage('data').setItem('test', 'works')
await useStorage().getItem('data:test') // Value persists

// You can use generics to define types
await useStorage<{ hello: string }>('test').getItem('foo')
await useStorage('test').getItem<{ hello: string }>('foo')
```

:read-more{to="https://unstorage.unjs.io"}

## Mount points

Storage root is in memory by default. Nitro also mounts `data:` using the platforms storage.

```js
const dataStorage = useStorage('data')
```
## Configuration

You can mount one or multiple custom storage drivers using the `storage` config.

The key is the mount point name, and the value is the driver name and configuration.

::code-group
Expand Down Expand Up @@ -142,7 +143,8 @@ const cacheStorage = useStorage('cache')
const buildStorage = useStorage('build')
```

You also can use the `devStorage` key to overwrite the storage configuration during development. This is very useful when you use a database in production and want to use the filesystem in development.
> [!TIP]
> You also can use the `devStorage` key to overwrite the storage configuration during development. This is very useful when you use a database in production and want to use the filesystem in development.

In order to use the `devStorage` key, you need to use the `nitro dev` command and the key in the `storage` option must be the same as the production one.

Expand Down
117 changes: 117 additions & 0 deletions docs/1.guide/5.database.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
icon: ri:database-2-line
---

# SQL Database

> Nitro provides a built-in and lightweight SQL database layer.

The default database connection is **preconfigured** with [SQLite](https://db0.unjs.io/connectors/sqlite) and works out of the box for development mode and any Node.js compatible production deployments. By default, data will be stored in `.data/db.sqlite3`.

> [!TIP]
> You can change default connection or define more connctions to any of the [supported databases](https://db0.unjs.io/connectors/sqlite).

> [!TIP]
> You can integrate database instance to any of the [supported ORMs](https://db0.unjs.io/integrations).

:read-more{to="https://db0.unjs.io" title="DB0 Documentation"}

## Opt-in to the experimental feature

> [!IMPORTANT]
> Database support is currently experimental and available in [nightly channel](/guide/nightly).
> Refer to the [db0 issues](https://github.com/unjs/db0/issues) for status and bug report.

In order to enable database layer you need to enable experimental feature flag.

::code-group
```ts [nitro.config.ts]
export default defineNitroConfig({
experimental: {
database: true
}
})
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
nitro: {
experimental: {
database: true
}
}
})
```
::

Also install `better-sqlite3` dependency:

:pm-install{name="-D better-sqlite3"}

## Usage

<!-- automd:file code src="../../examples/database/routes/index.ts" -->

```ts [index.ts]
export default defineEventHandler(async () => {
const db = useDatabase();

// Create users table
await db.sql`DROP TABLE IF EXISTS users`;
await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`;

// Add a new user
const userId = String(Math.round(Math.random() * 10_000));
await db.sql`INSERT INTO users VALUES (${userId}, 'John', 'Doe', '')`;

// Query for users
const { rows } = await db.sql`SELECT * FROM users WHERE id = ${userId}`;

return {
rows,
};
});

```

<!-- /automd -->

## Configuration

You can configure database connections using `database` config:

::code-group
```ts [nitro.config.ts]
export default defineNitroConfig({
database: {
default: {
driver: 'sqlite3',
options: { name: "db" }
},
users: {
driver: 'postgresql',
url: "postgresql://username:password@hostname:port/database_name"
}
}
})
```
```ts [nuxt.config.ts]
export default defineNuxtConfig({
nitro: {
database: {
default: {
driver: 'sqlite3',
options: { name: "db" }
},
users: {
driver: 'postgresql',
url: "postgresql://username:password@hostname:port/database_name"
}
}
}
})
```
::

> [!TIP]
> You can use the `devDatabase` config to overwrite the database configuration only for development mode.
File renamed without changes.
3 changes: 1 addition & 2 deletions docs/1.guide/6.fetch.md β†’ docs/1.guide/7.fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ icon: ri:global-line

# Fetch

Nitro provides a built-in fetch API that can be used to get data from server endpoints or from other sources. It's build on top of the [unjs/ofetch](https://ofetch.unjs.io).

> Nitro provides a built-in fetch API that can be used to get data from server endpoints or from other sources. It's build on top of the [unjs/ofetch](https://ofetch.unjs.io).

## Usage

Expand Down
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions examples/database/nitro.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default defineNitroConfig({
experimental: {
database: true,
},
});
12 changes: 12 additions & 0 deletions examples/database/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "example-database",
"private": true,
"scripts": {
"dev": "nitro dev",
"build": "nitro build"
},
"devDependencies": {
"better-sqlite3": "^8.4.0",
"nitropack": "latest"
}
}
18 changes: 18 additions & 0 deletions examples/database/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default defineEventHandler(async () => {
const db = useDatabase();

// Create users table
await db.sql`DROP TABLE IF EXISTS users`;
await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`;

// Add a new user
const userId = String(Math.round(Math.random() * 10_000));
await db.sql`INSERT INTO users VALUES (${userId}, 'John', 'Doe', '')`;

// Query for users
const { rows } = await db.sql`SELECT * FROM users WHERE id = ${userId}`;

return {
rows,
};
});
3 changes: 3 additions & 0 deletions examples/database/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "./.nitro/types/tsconfig.json"
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"citty": "^0.1.6",
"consola": "^3.2.3",
"cookie-es": "^1.0.0",
"db0": "^0.1.2",
"crossws": "^0.2.3",
"defu": "^6.1.4",
"destr": "^2.0.3",
Expand Down Expand Up @@ -125,6 +126,7 @@
"unwasm": "^0.3.7"
},
"devDependencies": {
"better-sqlite3": "^9.4.3",
"@azure/functions": "^3.5.1",
"@azure/static-web-apps-cli": "^1.1.6",
"@cloudflare/workers-types": "^4.20240222.0",
Expand Down
Loading