SERVER / DATABASE
Database
Database is Dowe's Dowe-owned server data contract. One query syntax can target PostgreSQL, Cloudflare D1, or Dowe Database, while handles and credentials stay server-only.
1 / MENTAL MODEL
Declare a handle, then bind results
database declares the provider connection and query executes one operation. The HTTP request is already available as req inside the handler, just like env references; the binding returned by query is available to later server statements and can be projected into a response.
handler getBlog
database db1 provider:"dowe" host:env.DOWE_HOST port:env.DOWE_PORT account:env.DOWE_USER secret:env.DOWE_PASSWORD name:"content"
query blog conn:db1.read table:"blogs" where:{ id:req.params.id } required:true
return json:{ ok:true data:blog }Part | Example | Meaning |
|---|---|---|
No dataThere are no records to display | ||
2 / OPERATIONS
Choose the data flow
Use list, read, insert, update, and delete for predictable record access. Use query for the supported SQL-like read grammar. The operation syntax stays the same when the provider changes.
Operation | Use it for | Documentation route |
|---|---|---|
No dataThere are no records to display | ||
3 / PROVIDERS
Three adapters, one server contract
The provider selects the Dowe adapter used in production. host, port, account, secret, and name are server-only props; Dowe never sends them to a View.
Provider | Connection contract |
|---|---|
No dataThere are no records to display | |
The same query against each provider
database appDb provider:"postgres"
host:env.POSTGRES_HOST
port:env.POSTGRES_PORT
account:env.POSTGRES_USER
secret:env.POSTGRES_PASSWORD
name:env.POSTGRES_DATABASE
entities:[Users Blogs]
seeders:[Bootstrap]
query blogs conn:appDb.list table:"blogs"Cloudflare D1
database appDb provider:"d1"
account:env.ACCOUNT_ID
secret:env.CLOUDFLARE_API_TOKEN
name:env.DATABASE_ID
entities:[Users Blogs]
seeders:[Bootstrap]
query blogs conn:appDb.list table:"blogs"Dowe Database
database appDb provider:"dowe"
host:env.DOWE_HOST
port:env.DOWE_PORT
account:env.DOWE_USER
secret:env.DOWE_PASSWORD
name:env.DOWE_DATABASE
entities:[Users Blogs]
seeders:[Bootstrap]
query blogs conn:appDb.list table:"blogs"3 / PROJECT REGISTRY
Register handles in main.dowe
A Database declaration can live in any server configuration module. Import the handle into main.dowe and list it under server.databases so migrate and seeders receive one deterministic project catalog, even before a route uses that handle.
import IconDb from "@/server/config/database"
main
server port:8081
databases:[IconDb]The registry accepts only imported Database handles. It does not copy provider credentials, open connections, or expose server-only values to Views.
4 / ENTITIES AND SEEDERS
Describe shape once, seed it deterministically
entity and seeder are importable server bindings. Run dowe database migrate after entity changes: Postgres and D1 append provider SQL, while Dowe records a dynamic no-SQL head. Production applies pending migrations and seeders automatically; local development applies seeders with dowe database seeders.
entity Users
id:string primary:true
name:string required:true
email:string required:true unique:true
entity Blogs
id:string primary:true
title:string required:true
ownerId:string required:true index:true
seeder Bootstrap
insert entity:Users value:{ id:"01H00000000000000000000000" name:"Admin" email:"admin@example.com" }Part | Responsibility |
|---|---|
No dataThere are no records to display | |
5 / DEVELOPMENT AND PRODUCTION
The same source behaves predictably in both environments
During dowe dev, all three providers use the embedded local Database under .dowe/db/<name> and resolve only name. Seeders are not loaded or executed automatically; run dowe database seeders when local records are needed. No account, secret, external network, Wrangler process, or second D1 port is used.
During production, Dowe validates the maintained migration graph, applies pending Postgres or D1 nodes atomically, runs pending seeders atomically, and only then starts accepting traffic. Dowe Database uses authenticated WebSocket operations and does not require SQL migrations.
query appointments conn:appDb.list table:"appointments"
query appointment conn:appDb.read table:"appointments" where:{ id:req.params.id } required:true