Class: Sqlx::Base

Inherits:
Object show all
Extended by:
Model, Query
Includes:
Row
Defined in:
runtime/sqlx/base.rb,
runtime/sqlx/adapter.rbs,
runtime/sqlx/base.rbs,
runtime/sqlx/adapter.rb

Overview

The raw-SQL model base — the class apps subclass. The query layer and the enum factory arrive by extend, the row-object layer by include; the subclass contract stubs stay in the class body.

Direct Known Subclasses

Snails::QueueJob, Snails::QueueOccurrence

Constant Summary collapse

TIMESTAMP_COLUMNS =

The built-in timestamp columns: the default datetime_columns pair and the names create!/update! stamp on write. A table without them stays legal — hydration passes them by instead of raising.

[ "created_at", "updated_at" ]

Class Method Summary collapse

Methods included from Query

count, create!, delete!, delete_all!, exists?, fetch_many, find, find_by, find_by!, find_by_sql, find_each, find_in_batches, projection, row_by_sql, rows_by_sql, update!, update_all!, upsert_all!, where_clause, write

Methods included from Model

enum

Methods included from Row

#initialize, #read_attribute

Class Method Details

.all ⇒ Array

every row of the model's table, in no implied order. SPEC-ONLY by decision: core owns the signature and the contract, not the SQL. Two call sites need it (a model's own all and one full-table read), and a public API is easier to add than to remove, so each model implements it over its own projection in the shape below.

Examples:

call

Model.all

standard implementation shape — the walk lives in

the model so the element type converges with the return,
and the projection is the model's own; a single-call body
is one line when the line fits
def self.all = find_by_sql("SELECT " + SELECT_COLUMNS + " FROM samples")

Returns:

  • (Array) —

    every row of the table — an empty array when the table has no rows (never nil); which row comes first is implementation-defined, so a caller that needs order writes its own SQL through find_by_sql

Raises:

  • (NotImplementedError) —

    always, on the base (spec-only)



202
# File 'runtime/sqlx/base.rb', line 202

def self.all: () -> Array[untyped]

.boolean_columns ⇒ Array[String]

the projected columns whose stored 1/0 is a boolean: another type exception of the default from_row.

Examples:

def self.boolean_columns = %w[verified]

Returns:

  • (Array[String]) —

    the boolean column names; [] when none



91
# File 'runtime/sqlx/base.rb', line 91

def self.boolean_columns: () -> Array[String]

.date_columns ⇒ Array[String]

the projected columns whose stored TEXT is a civil date: the type exception the default from_row converts through String#to_date. Defaults to none. A model with DATE columns declares them (the column generator emits the list). The date codec is opt-in — the generated file loads runtime/ext/date only for an app whose schema has a DATE column, because requiring the date package costs build time and binary size even when no value converts.

Examples:

def self.date_columns = %w[happens_on issued_on]

Returns:

  • (Array[String]) —

    the date column names; [] when none



81
# File 'runtime/sqlx/base.rb', line 81

def self.date_columns: () -> Array[String]

.datetime_columns ⇒ Array[String]

the projected columns whose stored TEXT is a time: the type exceptions the default from_row below converts through the stored-time codec. Defaults to the built-in timestamp pair; the option replaces the list wholesale, so a model with extra time columns spells the pair plus its extras, and a model that keeps time columns as raw storage text answers []. A declared name outside only_columns is a declaration error (the timestamp pair excepted — a table without them is legal).

Examples:

the default pair is replaced, so it is spelled out again

def self.datetime_columns = %w[created_at updated_at deleted_at]

Returns:

  • (Array[String]) —

    the datetime column names — the timestamp pair by default



66
# File 'runtime/sqlx/base.rb', line 66

def self.datetime_columns: () -> Array[String]

.from_row(row) ⇒ Object

the default hydration: one name-keyed row in, one record out. Every projected column is copied by name and the declared type exceptions are converted — datetime_columns through the stored-time codec, date_columns through String#to_date, boolean_columns from the stored 1/0, json_columns through Sqlx::Json (the same codec the write entries encode with, so the column round-trips). A model whose row needs more than the exceptions (value normalization) overrides this wholesale; the declaration stubs still make a bare base call loud.

Examples:

declaration only — the model carries no method

class Widget < Sqlx::Base
  COLUMNS = %w[id name created_at].each { |n| define_method(n) { read_attribute(n) } }
  def self.table_name = "widgets"
  def self.only_columns = COLUMNS.map { |c| c.to_sym }
end

Parameters:

  • row (Hash{String => Object}) —

    one name-keyed row — the rows_by_sql shape: the projected column names as keys, the adapter's native values (Integer, Float, String, nil for NULL)

Returns:

  • (Object) —

    the hydrated record

Raises:

  • (NotImplementedError) —

    the model declared no only_columns (the declaration stub raises before any copy runs)

  • (ArgumentError) —

    a declared exception names a column outside only_columns — only the built-in timestamp pair may be absent, so a typo fails loud instead of staying raw silently; or a declared date column arrived without the date codec loaded



140
# File 'runtime/sqlx/base.rb', line 140

def self.from_row: (untyped row) -> untyped

.json_columns ⇒ Array[String]

the projected columns whose stored TEXT is JSON: a type exception that travels both ways. The default from_row below decodes each declared column through Sqlx::Json, and the write entries (create!·update!· update_all!·upsert_all!) encode each declared value on the way in, so a caller hands over the logical value (a Hash) and reads the logical value back — the codec call never appears in app code. A value JSON cannot represent raises at the write entry instead of being to_s-ed into the column, the codec's own contract. Defaults to no json columns: an undeclared column stores and reads exactly as raw text.

Examples:

def self.json_columns = %w[detail]

Returns:

  • (Array[String]) —

    the json column names; [] when none

Raises:

  • (ArgumentError) —

    the default from_row finds a declared name outside only_columns



110
# File 'runtime/sqlx/base.rb', line 110

def self.json_columns: () -> Array[String]

.only_columns ⇒ Array[Symbol, String]

the columns this model reads: the projection half of the find_by declaration pair, declared as a column-name array. It is a required declaration, not an optional filter — core assembles it into the SELECT list (every identifier quoted, so a reserved-word column like order is safe), and hydration reads the projected names out of the row, so the list's order binds no read. The base raises so a model that forgot the declaration fails loud instead of splicing nil into the SQL.

Examples:

def self.only_columns = [:id, :email, :created_at]

Returns:

  • (Array[Symbol, String]) —

    the projected column names — code, not input, and not validated: an unknown column surfaces as a loud SQL error from the driver, the rule where_clause applies to its keys. An empty list assembles a malformed SELECT that the driver rejects loud.

Raises:

  • (NotImplementedError) —

    on the base — the subclass has not declared it



45
# File 'runtime/sqlx/base.rb', line 45

def self.only_columns: () -> Array[Symbol | String]

.table_name ⇒ String

the table this model reads from: one of the two declarations the core find_by assembles its SELECT from. A subclass declares it as a literal one-liner (spinel has no metaprogramming for accessors); the base raises so a model that forgot the declaration fails loud instead of splicing nil into the SQL.

Examples:

def self.table_name = "widgets"

Returns:

  • (String) —

    the table name — code, not input, and not validated: an unknown table surfaces as a loud SQL error from the driver, the rule where_clause applies to its keys

Raises:

  • (NotImplementedError) —

    on the base — the subclass has not declared it



24
# File 'runtime/sqlx/base.rb', line 24

def self.table_name: () -> String

.transaction ⇒ Object

the block inside BEGIN/COMMIT, with ROLLBACK + re-raise on any exception. The rollback covers Exception, not just StandardError: a ScriptError or a signal escaping the block must not leave the transaction open on a pooled connection — the next lease would run inside it and keep its write lock. The ensure runs on every exit path, including a failing COMMIT. A lost connection has nothing left to roll back, so its ConnectionFailed must not replace the error that ended the block. Flat transactions only: a nested BEGIN would error in SQLite rather than silently join, which is the honest failure.

Returns:

  • (Object) —

    the block's value; an exception rolls the transaction back and is re-raised



61
# File 'runtime/sqlx/adapter.rb', line 61

def self.transaction: () { () -> untyped } -> untyped