Rado GitHub

Views

A view is a stored query you can select from like a table. Rado supports plain views on every dialect and materialized views on PostgreSQL.

Defining a view from a query

Give view a name and a select query. The columns (and their types) are inferred from the selection:

import {eq, view} from 'rado'

const ActiveUsers = view('active_users').as(
  db
    .select({id: User.id, name: User.name})
    .from(User)
    .where(eq(User.active, true))
)

Create it, then query it like any table:

await db.create(ActiveUsers)

const actives = await db.select().from(ActiveUsers)
const one = await db
  .select(ActiveUsers.name)
  .from(ActiveUsers)
  .where(eq(ActiveUsers.id, 1))

Defining a view with explicit columns

When the body is raw SQL (or you want full control over types), declare the columns yourself:

import {sql, view} from 'rado'
import {integer, text} from 'rado/universal'

const UserNames = view('user_names', {
  id: integer(),
  name: text()
}).as(sql`select ${User.id}, ${User.name} from ${User}`)

Using an existing view

If the view already exists in the database (created by another tool or a migration), skip the body and mark it as existing:

const Reporting = view('reporting', {
  total: integer(),
  region: text()
}).existing()

// .existing() views are never created or dropped by rado, just queried
const rows = await db.select().from(Reporting)

Materialized views (PostgreSQL)

Materialized views store their results physically and must be refreshed:

import {pgMaterializedView} from 'rado/postgres'

const Stats = pgMaterializedView('stats').as(
  db
    .select({authorId: Post.authorId, posts: count()})
    .from(Post)
    .groupBy(Post.authorId)
)

await db.create(Stats)

// Data is frozen at creation/refresh time. Refresh when needed:
await db.refreshMaterializedView(Stats)

pgView is also exported from rado/postgres as the dialect-typed sibling of view.

Views inside a Postgres schema

Views can live inside a named schema via pgSchema:

import {pgSchema} from 'rado/postgres'

const reporting = pgSchema('reporting')
const Totals = reporting.view('totals').as(...)
const CachedTotals = reporting.materializedView('cached_totals').as(...)

See PostgreSQL schemas & enums.

Creating and dropping

Views participate in db.create and db.drop like tables. Order matters: create the tables a view depends on first, and drop the view before its tables:

await db.create(User, ActiveUsers)
// ...
await db.drop(ActiveUsers, User)