std.orm

Typed PostgreSQL models, queries, relations, and migrations.

Importuse std.orm

Types

struct OrmSql#

Inspectable ORM SQL with redacted parameter kinds.

text: string
params: [string]
unsafe: bool
struct MigrationStatus#

One immutable migration history status.

id: string
status: string
checksum: string
duration_ms: int
struct OrmColumn#

An immutable ORM column descriptor.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

use std.orm
use std.orm.Model
use std.sql.SqlPool

struct User {
  id: Optional<int>,
  email: string,
  active: bool,
  version: int,
}

fn user_model() -> Model<User> {
  orm.model<User>(
    "users",
    [
      orm.column("id").primary_key().generated(),
      orm.column("email").unique().indexed(),
      orm.column("active").default_sql("TRUE"),
      orm.column("version").version(),
    ],
  )
}

fn main() { println(user_model().field("email")) }
_handle: NativeHandle

The native resource.

struct OrmCodec#

A typed ORM codec pair.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

struct Model#

A typed ORM model descriptor.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

struct Field#

A typed ORM field descriptor.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

struct OrmPredicate#

A typed parameterized ORM predicate.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

struct OrmQuery#

A typed immutable ORM query.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

use std.orm
use std.orm.Model
use std.sql.SqlPool

struct User { id: Optional<int>, email: string, active: bool }

async fn active_users(pool: SqlPool, users: Model<User>) -> Result<[User], Error> {
  let active = users.field("active")
  let email = users.field("email")
  await orm
    .query(pool, users)
    .where(active.eq(true))
    .where(email.ilike("%@example.com"))
    .order_by(email, "asc")
    .limit(100)
    .all()
}

fn main() {}
_handle: NativeHandle

The native resource.

struct OrmRows#

A bounded ORM row stream.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

struct Changes#

A typed immutable ORM partial update.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

use std.orm
use std.orm.Model
use std.sql.SqlPool

struct User { id: Optional<int>, email: string, active: bool }

async fn write_users(pool: SqlPool, users: Model<User>) -> Result<int, Error> {
  let created = await orm.insert(
    pool,
    users,
    User { id: none, email: "moon@example.com", active: true },
  )?
  let email = users.field("email")
  let active = users.field("active")
  let changed = await orm
    .query(pool, users)
    .where(email.eq(created.email))
    .update(orm.changes(users).set(active, false))?
  let _found = await orm.find(pool, users, created.id.unwrap())?
  let _removed = await orm.delete(pool, users, created)?
  ok(changed)
}

fn main() {}
_handle: NativeHandle

The native resource.

struct Relation#

An explicit typed ORM relation.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

use std.orm
use std.orm.Model
use std.sql.SqlPool

struct User { id: Optional<int>, email: string }
struct Post { id: Optional<int>, user_id: Optional<int>, title: string }

fn relation(pool: SqlPool, users: Model<User>, posts: Model<Post>) {
  let posts_for_user = orm.has_many(
    users,
    posts,
    users.field("id"),
    posts.field("user_id"),
  )
  let joined = orm
    .query(pool, users)
    .left_join(posts, users.field("id"), posts.field("user_id"))
    .select_pair(users, posts)
  println(posts_for_user)
  println(joined)
}

fn main() {}
_handle: NativeHandle

The native resource.

struct OrmJoin#

A typed ORM inner join.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

struct OrmLeftJoin#

A typed ORM left join.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

struct OrmPairQuery#

A typed ORM two-model projection.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

struct Migration#

An immutable checksum-protected migration.

An opaque handle: only std.orm can produce one, and its contents are not reachable from moon source.

use std.orm
use std.orm.Model
use std.sql
use std.sql.SqlPool

struct User { id: Optional<int>, email: string }

async fn migrate(pool: SqlPool, users: Model<User>) -> Result<int, Error> {
  let up = [orm.create_table(users)]
  for index in orm.create_indexes(users) { up.push(index) }
  let migration = orm.migration(
    "001_users",
    up,
    [sql.raw("DROP TABLE users", [])],
  )
  println(orm.migration_dry_run([migration], "up"))
  let applied = await orm.migrate(pool, [migration])?
  let status = await orm.migration_status(pool, [migration])?
  println(status[0].status)
  ok(applied.len())
}

fn main() {}
_handle: NativeHandle

The native resource.

Functions

fn column(field: string) -> OrmColumn#
fn column_as(field: string, column: string) -> OrmColumn#
fn codec<T>(encode: fn(T) -> Result<SqlValue, Error>, decode: fn(SqlValue) -> Result<T, Error>) -> OrmCodec<T>#
fn model<T>(table: string, columns: [OrmColumn]) -> Model<T>#
fn try_model<T>(table: string, columns: [OrmColumn]) -> Result<Model<T>, Error>#
fn primary_key(self: OrmColumn) -> OrmColumn#
fn generated(self: OrmColumn) -> OrmColumn#
fn readonly(self: OrmColumn) -> OrmColumn#
fn unique(self: OrmColumn) -> OrmColumn#
fn indexed(self: OrmColumn) -> OrmColumn#
fn version(self: OrmColumn) -> OrmColumn#
fn soft_delete(self: OrmColumn) -> OrmColumn#
fn timestamp(self: OrmColumn) -> OrmColumn#
fn enum_text(self: OrmColumn) -> OrmColumn#
fn default_sql(self: OrmColumn, clause: string) -> OrmColumn#
fn check_sql(self: OrmColumn, clause: string) -> OrmColumn#
fn references(self: OrmColumn, table: string, column: string) -> OrmColumn#
fn sql_type(self: OrmColumn, type_sql: string) -> OrmColumn#
fn raw_clause(self: OrmColumn, clause: string) -> OrmColumn#
fn using_codec<T>(self: OrmColumn, codec: OrmCodec<T>) -> OrmColumn#
fn field<T,F>(self: Model<T>, name: string) -> Field<T,F>#
fn decode<T>(self: Model<T>, row: SqlRow) -> Result<T, Error>#
fn encode<T>(self: Model<T>, entity: T) -> Result<{string: SqlValue}, Error>#
fn to_sql_value<T,F>(self: Model<T>, field: string, value: F) -> Result<SqlValue, Error>#
fn query<T>(exec: SqlExecutor, model: Model<T>) -> OrmQuery<T>#
fn from_query<T>(exec: SqlExecutor, model: Model<T>, query: SqlQuery) -> OrmQuery<T>#
fn map_query<T>(exec: SqlExecutor, query: SqlQuery, mapper: fn(SqlRow) -> Result<T, Error>) -> Future<Result<[T], Error>>#
fn where<T>(self: OrmQuery<T>, predicate: OrmPredicate<T>) -> OrmQuery<T>#
fn or_where<T>(self: OrmQuery<T>, predicate: OrmPredicate<T>) -> OrmQuery<T>#
fn order_by<T,F>(self: OrmQuery<T>, field: Field<T,F>, direction: string) -> OrmQuery<T>#
fn limit<T>(self: OrmQuery<T>, count: int) -> OrmQuery<T>#
fn offset<T>(self: OrmQuery<T>, count: int) -> OrmQuery<T>#
fn materialization_limit<T>(self: OrmQuery<T>, count: int) -> OrmQuery<T>#
fn distinct<T>(self: OrmQuery<T>) -> OrmQuery<T>#
fn for_update<T>(self: OrmQuery<T>) -> OrmQuery<T>#
fn for_share<T>(self: OrmQuery<T>) -> OrmQuery<T>#
fn skip_locked<T>(self: OrmQuery<T>) -> OrmQuery<T>#
fn with_deleted<T>(self: OrmQuery<T>) -> OrmQuery<T>#
fn only_deleted<T>(self: OrmQuery<T>) -> OrmQuery<T>#
fn to_query<T>(self: OrmQuery<T>) -> SqlQuery#
fn to_sql<T>(self: OrmQuery<T>) -> OrmSql#
fn all<T>(self: OrmQuery<T>) -> Future<Result<[T], Error>>#
fn first<T>(self: OrmQuery<T>) -> Future<Result<Optional<T>, Error>>#
fn first_required<T>(self: OrmQuery<T>) -> Future<Result<T, Error>>#
fn count<T>(self: OrmQuery<T>) -> Future<Result<int, Error>>#
fn exists<T>(self: OrmQuery<T>) -> Future<Result<bool, Error>>#
fn pluck<T,F>(self: OrmQuery<T>, field: Field<T,F>) -> Future<Result<[F], Error>>#
fn stream<T>(self: OrmQuery<T>) -> Future<Result<OrmRows<T>, Error>>#
fn next<T>(self: OrmRows<T>) -> Future<Result<Optional<T>, Error>>#
fn close<T>(self: OrmRows<T>) -> Future<Result<void, Error>>#
fn eq<T,F>(self: Field<T,F>, value: F) -> OrmPredicate<T>#
fn ne<T,F>(self: Field<T,F>, value: F) -> OrmPredicate<T>#
fn lt<T,F>(self: Field<T,F>, value: F) -> OrmPredicate<T>#
fn lte<T,F>(self: Field<T,F>, value: F) -> OrmPredicate<T>#
fn gt<T,F>(self: Field<T,F>, value: F) -> OrmPredicate<T>#
fn gte<T,F>(self: Field<T,F>, value: F) -> OrmPredicate<T>#
fn between<T,F>(self: Field<T,F>, low: F, high: F) -> OrmPredicate<T>#
fn in_values<T,F>(self: Field<T,F>, values: [F]) -> OrmPredicate<T>#
fn not_in_values<T,F>(self: Field<T,F>, values: [F]) -> OrmPredicate<T>#
fn like<T>(self: Field<T,string>, value: string) -> OrmPredicate<T>#
fn ilike<T>(self: Field<T,string>, value: string) -> OrmPredicate<T>#
fn is_null<T,F>(self: Field<T,Optional<F>>) -> OrmPredicate<T>#
fn is_not_null<T,F>(self: Field<T,Optional<F>>) -> OrmPredicate<T>#
fn and<T>(self: OrmPredicate<T>, other: OrmPredicate<T>) -> OrmPredicate<T>#
fn or<T>(self: OrmPredicate<T>, other: OrmPredicate<T>) -> OrmPredicate<T>#
fn not<T>(self: OrmPredicate<T>) -> OrmPredicate<T>#
fn changes<T>(model: Model<T>) -> Changes<T>#
fn set<T,F>(self: Changes<T>, field: Field<T,F>, value: F) -> Changes<T>#
fn update<T>(self: OrmQuery<T>, changes: Changes<T>) -> Future<Result<int, Error>>#
fn delete_all<T>(self: OrmQuery<T>) -> Future<Result<int, Error>>#
fn delete<T>(exec: SqlExecutor, model: Model<T>, entity: T) -> Future<Result<bool, Error>>#
fn find<T,K>(exec: SqlExecutor, model: Model<T>, key: K) -> Future<Result<Optional<T>, Error>>#
fn find_required<T,K>(exec: SqlExecutor, model: Model<T>, key: K) -> Future<Result<T, Error>>#
fn insert<T>(exec: SqlExecutor, model: Model<T>, entity: T) -> Future<Result<T, Error>>#
fn insert_many<T>(exec: SqlExecutor, model: Model<T>, entities: [T]) -> Future<Result<[T], Error>>#
fn has_many<A,B,K>(source: Model<A>, target: Model<B>, source_key: Field<A,K>, target_key: Field<B,K>) -> Relation<A,B>#
fn has_one<A,B,K>(source: Model<A>, target: Model<B>, source_key: Field<A,K>, target_key: Field<B,K>) -> Relation<A,B>#
fn belongs_to<A,B,K>(source: Model<A>, target: Model<B>, source_key: Field<A,K>, target_key: Field<B,K>) -> Relation<A,B>#
fn load<A,B>(self: Relation<A,B>, exec: SqlExecutor, entity: A) -> Future<Result<[B], Error>>#
fn preload<A,B>(self: Relation<A,B>, exec: SqlExecutor, entities: [A]) -> Future<Result<{string: [B]}, Error>>#
fn inner_join<A,B,K>(self: OrmQuery<A>, model: Model<B>, left: Field<A,K>, right: Field<B,K>) -> OrmJoin<A,B>#
fn left_join<A,B,K>(self: OrmQuery<A>, model: Model<B>, left: Field<A,K>, right: Field<B,K>) -> OrmJoin<A,B>#
fn select_pair<A,B>(self: OrmJoin<A,B>, left: Model<A>, right: Model<B>) -> OrmPairQuery<A,B>#
fn transaction<T>(pool: SqlPool, callback: fn(SqlTransaction) -> Future<Result<T, Error>>) -> Future<Result<T, Error>>#
fn migration(id: string, up: [SqlQuery], down: [SqlQuery]) -> Migration#
fn non_transactional(self: Migration) -> Migration#
fn create_table<T>(model: Model<T>) -> SqlQuery#
fn create_indexes<T>(model: Model<T>) -> [SqlQuery]#
fn migrate(exec: SqlExecutor, migrations: [Migration], metadata_table: string = "_moon_migrations") -> Future<Result<[MigrationStatus], Error>>#
fn migration_status(exec: SqlExecutor, migrations: [Migration], metadata_table: string = "_moon_migrations") -> Future<Result<[MigrationStatus], Error>>#
fn migrate_up(exec: SqlExecutor, migrations: [Migration], metadata_table: string = "_moon_migrations") -> Future<Result<[MigrationStatus], Error>>#
fn migrate_down(exec: SqlExecutor, migrations: [Migration], count: int, metadata_table: string = "_moon_migrations") -> Future<Result<[MigrationStatus], Error>>#
fn migration_dry_run(migrations: [Migration], direction: string) -> [string]#