SERVER / DATABASE / RELATIONS

Relations

Dowe models relations explicitly with identifier fields and server queries. The current DSL does not add an automatic ORM graph, belongsTo helpers, or declarative foreign keys.

1 / MENTAL MODEL

Store the link, then query the related records

A relation is a normal field containing another record's id. Mark that field index:true when it is used for filtering or joining. The compiler validates the field type and constraints, while the server owns the relationship workflow.

dowe
entity Users
  id:string primary:true
  name:string required:true

entity Posts
  id:string primary:true
  authorId:string required:true index:true
  title:string required:true
Pattern
Identifier link
Implementation

No data

There are no records to display

2 / ONE-TO-MANY

Keep the related id on the many side

Each post stores its author's id. The index makes the common list-by-author path efficient, but it does not prove that the user exists. Check that authority in the server workflow before inserting or updating a post.

dowe
handler listUserPosts
  query rows conn:appDb.query sql:"SELECT posts.id, posts.title, users.name AS authorName FROM posts JOIN users ON posts.authorId = users.id WHERE posts.authorId = ?1" params:[req.params.userId]
  return json:{ ok:true data:rows }

The query result is ordinary server data. Return only the projection required by the endpoint instead of exposing the Database handle to a View.

3 / ONE-TO-ONE

Use a unique parent id

A unique userId allows one profile for each user. unique:true is a field constraint, so it prevents duplicate values for that column but does not create a foreign-key reference or cascade behavior.

dowe
entity Profiles
  id:string primary:true
  userId:string required:true unique:true index:true
  bio:string
Use a server read before the write when the related user must exist. A unique field is the one-to-one limit; relationship existence remains application logic.

4 / MANY-TO-MANY

Create an explicit join entity

For users and roles, UserRoles stores one userId and one roleId per membership. Index both fields for reverse lookups. The current entity contract does not provide composite unique constraints, so duplicate memberships need a server check.

dowe
entity UserRoles
  id:string primary:true
  userId:string required:true index:true
  roleId:string required:true index:true

query rows conn:appDb.query sql:"SELECT users.name, roles.name AS roleName FROM users JOIN user_roles ON user_roles.userId = users.id JOIN roles ON user_roles.roleId = roles.id WHERE users.id = ?1" params:[req.params.userId]

5 / CONTRACT BOUNDARIES

Know what Dowe enforces

Relationships work across the shared Database providers through explicit fields and parameterized queries. The server remains responsible for authorization, existence checks, cleanup, and response shape.

Boundary
Current contract

No data

There are no records to display