class Lustra::Reflection::Table

Overview

Reflection of the tables using information_schema in postgreSQL.

TODO Usage of view instead of model

Included Modules

Extended Modules

Defined in:

lustra/model/reflection/table.cr

Constant Summary

COLUMNS = {"table_catalog" => {type: String, primary: false, converter: "String", db_column_name: "table_catalog", crystal_variable_name: table_catalog, presence: true, mass_assign: true}, "table_schema" => {type: String, primary: false, converter: "String", db_column_name: "table_schema", crystal_variable_name: table_schema, presence: true, mass_assign: true}, "table_name" => {type: String, primary: true, converter: "String", db_column_name: "table_name", crystal_variable_name: table_name, presence: true, mass_assign: true}, "table_type" => {type: String, primary: false, converter: "String", db_column_name: "table_type", crystal_variable_name: table_type, presence: true, mass_assign: true}} of Nil => Nil
POLYMORPHISM_SETTINGS = {} of Nil => Nil

Constructors

Class Method Summary

Instance Method Summary

Instance methods inherited from module Lustra::Model

__pkey__ __pkey__, cache : Lustra::Model::QueryCache | Nil cache

Macros inherited from module Lustra::Model

default_scope(&block) default_scope, scope(name, &block) scope

Class methods inherited from module Lustra::Model::FullTextSearchable

to_tsq(text) to_tsq

Macros inherited from module Lustra::Model::FullTextSearchable

full_text_searchable(through = "full_text_vector", catalog = "pg_catalog.english", scope_name = "search") full_text_searchable

Macros inherited from module Lustra::Model::HasFactory

polymorphic(through = "type") polymorphic

Macros inherited from module Lustra::Model::HasRelations

belongs_to(name, foreign_key = nil, no_cache = false, primary = false, foreign_key_type = Int64, touch = nil, counter_cache = nil) belongs_to, has_many(name, through = nil, foreign_key = nil, own_key = nil, primary_key = nil, no_cache = false, polymorphic = false, foreign_key_type = nil, autosave = false) has_many, has_one(name, foreign_key = nil, primary_key = nil, no_cache = false, polymorphic = false, foreign_key_type = nil, autosave = false) has_one

Instance methods inherited from module Lustra::Model::HasValidation

add_error(column, reason)
add_error(reason)
add_error
, clear_errors clear_errors, error? error?, errors : Array(Error) errors, print_errors print_errors, valid! valid!, valid? valid?, validate validate

Macros inherited from module Lustra::Validation::Helper

ensure_than(field, message, &block) ensure_than, on_presence(*fields, &block) on_presence

Instance methods inherited from module Lustra::Model::HasSaving

decrement(column : Symbol | String, by = 1) decrement, decrement!(column : Symbol | String, by = 1) decrement!, delete delete, destroy destroy, increment(column : Symbol | String, by = 1) increment, increment!(column : Symbol | String, by = 1) increment!, persisted? : Bool persisted?, reload : self reload, save(on_conflict : Lustra::SQL::InsertQuery -> | Nil = nil)
save(&block)
save
, save!(on_conflict : Lustra::SQL::InsertQuery -> | Nil = nil)
save!(&block : Lustra::SQL::InsertQuery -> )
save!
, save_with_associations(on_conflict : Lustra::SQL::InsertQuery -> | Nil = nil) save_with_associations, update(**args) update, update!(**args) update!, update_column(column : Symbol | String, value) update_column, update_columns(columns : NamedTuple)
update_columns(columns : Hash(String, Lustra::SQL::Any))
update_columns(**columns)
update_columns

Macros inherited from module Lustra::Model::HasSerialPkey

add_pkey_type(type, &block) add_pkey_type, primary_key(name = "id", type = :bigserial) primary_key

Macros inherited from module Lustra::Model::HasTimestamps

timestamps timestamps

Instance methods inherited from module Lustra::Model::HasColumns

[](x) : Lustra::SQL::Any [], []?(x) : Lustra::SQL::Any []?, reset(h : Hash(String, _))
reset(h : Hash(Symbol, _))
reset(**t : **T) forall T
reset
, set(h : Hash(String, _))
set(h : Hash(Symbol, _))
set(**t : **T) forall T
set
, to_h(full = false) to_h, update_h update_h

Macros inherited from module Lustra::Model::HasColumns

column(name, primary = false, converter = nil, column_name = nil, presence = true, mass_assign = true) column

Instance methods inherited from module Lustra::Model::HasHooks

trigger_after_events(event_name) trigger_after_events, trigger_before_events(event_name) trigger_before_events, with_triggers(event_name, &) with_triggers

Macros inherited from module Lustra::Model::HasHooks

after(event_name, method_name) after, before(event_name, method_name) before

Instance methods inherited from module Lustra::ErrorMessages

build_error_message(message : String, ways_to_resolve : Tuple | Array = Tuple.new) build_error_message, converter_error(from, to) converter_error, format_width(x, w = 80) format_width, illegal_setter_access_to_undefined_column(name) illegal_setter_access_to_undefined_column, lack_of_primary_key(model_name) lack_of_primary_key, migration_already_down(number) migration_already_down, migration_already_up(number) migration_already_up, migration_irreversible(name = nil, operation = nil) migration_irreversible, migration_not_found(number) migration_not_found, migration_not_unique(numbers) migration_not_unique, no_migration_yet(version) no_migration_yet, null_column_mapping_error(name, type) null_column_mapping_error, order_by_error_invalid_order(current_order) order_by_error_invalid_order, polymorphic_nil(through) polymorphic_nil, polymorphic_unknown_class(class_name) polymorphic_unknown_class, query_building_error(message) query_building_error, uid_not_found(class_name) uid_not_found, uninitialized_db_connection(connection) uninitialized_db_connection

Constructor Detail

def self.build(x : NamedTuple) : self #

Build a new empty model and fill the columns using the NamedTuple in argument.

Returns the new model


[View source]
def self.build(x : NamedTuple, &block : self -> Nil) : self #

Build a new empty model and fill the columns using the NamedTuple in argument.

Returns the new model


[View source]
def self.create(x : NamedTuple, &block : self -> Nil) : self #

Build and new model and save it. Returns the model.

The model may not be saved due to validation failure; check the returned model errors? and persisted? flags.


[View source]
def self.create(**tuple, &block : self -> Nil) : self #

Build and new model and save it. Returns the model.

The model may not be saved due to validation failure; check the returned model errors? and persisted? flags.


[View source]
def self.create(x : NamedTuple) : self #

Build and new model and save it. Returns the model.

The model may not be saved due to validation failure; check the returned model errors? and persisted? flags.


[View source]
def self.create(**tuple) : self #

Build and new model and save it. Returns the model.

The model may not be saved due to validation failure; check the returned model errors? and persisted? flags.


[View source]
def self.create!(x : NamedTuple, &block : self -> Nil) : self #

Build and new model and save it. Returns the model.

Returns the newly inserted model Raises an exception if validation failed during the saving process.


[View source]
def self.create!(**tuple, &block : self -> Nil) : self #

Build and new model and save it. Returns the model.

Returns the newly inserted model Raises an exception if validation failed during the saving process.


[View source]
def self.create!(x : NamedTuple) : self #

Build and new model and save it. Returns the model.

Returns the newly inserted model Raises an exception if validation failed during the saving process.


[View source]
def self.create!(**tuple) : self #

Build and new model and save it. Returns the model.

Returns the newly inserted model Raises an exception if validation failed during the saving process.


[View source]
def self.new(h : Hash(String, _), cache : Lustra::Model::QueryCache | Nil = nil, persisted = false, fetch_columns = false) #

[View source]
def self.new(json : JSON::Any, cache : Lustra::Model::QueryCache | Nil = nil, persisted = false) #

[View source]
def self.new(t : NamedTuple, persisted = false) #

[View source]
def self.new #

[View source]

Class Method Detail

def self.build(**tuple : **T) forall T #

Build a new empty model and fill the columns using the NamedTuple in argument.

Returns the new model


[View source]
def self.build(**tuple) #

Build a new empty model and fill the columns using the NamedTuple in argument.

Returns the new model


[View source]
def self.build(**tuple, &) #

Build a new empty model and fill the columns using the NamedTuple in argument.

Returns the new model


[View source]
def self.columns #

[View source]
def self.connection : String #

Define on which connection the model is living. Useful in case of models living in different databases.

Is set to "default" by default.

See Lustra::SQL#init(URI, *opts) for more information about multi-connections.

Example:

Lustra::SQL.init("postgres://postgres@localhost/database_1")
Lustra::SQL.init("secondary", "postgres://postgres@localhost/database_2")

class ModelA
  include Lustra::Model

  # Performs all the queries on `database_1`
  # self.connection = "default"
  column id : Int32, primary: true, presence: false
  column title : String
end

class ModelB
  include Lustra::Model

  # Performs all the queries on `database_2`
  self.connection = "secondary"

  column id : Int32, primary: true, presence: false
end

def self.connection=(connection : String) #

Define on which connection the model is living. Useful in case of models living in different databases.

Is set to "default" by default.

See Lustra::SQL#init(URI, *opts) for more information about multi-connections.

Example:

Lustra::SQL.init("postgres://postgres@localhost/database_1")
Lustra::SQL.init("secondary", "postgres://postgres@localhost/database_2")

class ModelA
  include Lustra::Model

  # Performs all the queries on `database_1`
  # self.connection = "default"
  column id : Int32, primary: true, presence: false
  column title : String
end

class ModelB
  include Lustra::Model

  # Performs all the queries on `database_2`
  self.connection = "secondary"

  column id : Int32, primary: true, presence: false
end

def self.create_from_json(string_or_io : String | IO, trusted : Bool = false) #

Create a new model from json and save it. Returns the model.

The model may not be saved due to validation failure; check the returned model errors? and persisted? flags. Trusted flag set to true will allow mass assignment without protection, FALSE by default


def self.create_from_json!(string_or_io : String | IO, trusted : Bool = false) #

Create a new model from json and save it. Returns the model.

Returns the newly inserted model Raises an exception if validation failed during the saving process. Trusted flag set to true will allow mass assignment without protection, FALSE by default


def self.find(ids : Array) #

Find multiple models by an array of primary keys. Returns an array of models (may be empty if none found).

users = User.find([1, 2, 3])
users.size # => 0..3 depending on how many were found

[View source]
def self.find(x) #

Returns a model using primary key equality Returns nil if not found.


[View source]
def self.find!(ids : Array) #

Find multiple models by an array of primary keys. Raises error if ANY of the IDs are not found.

users = User.find!([1, 2, 3]) # Raises if any ID is not found

[View source]
def self.find!(x) #

Returns a model using primary key equality. Raises error if the model is not found.


[View source]
def self.find_by(tuple : NamedTuple) #

Find a model by column values. Returns nil if not found. This is an alias for query.find(**tuple) with better naming.

user = User.find_by(email: "test@example.com")
user = User.find_by(first_name: "John", last_name: "Doe")

[View source]
def self.find_by(**tuple) #

Find a model by column values. Returns nil if not found. This is an alias for query.find(**tuple) with better naming.

user = User.find_by(email: "test@example.com")
user = User.find_by(first_name: "John", last_name: "Doe")

[View source]
def self.find_by!(tuple : NamedTuple) #

Find a model by column values. Raises error if not found. This is an alias for query.find!(**tuple) with better naming.

user = User.find_by!(email: "test@example.com")

[View source]
def self.find_by!(**tuple) #

Find a model by column values. Raises error if not found. This is an alias for query.find!(**tuple) with better naming.

user = User.find_by!(email: "test@example.com")

[View source]
def self.from_json(string_or_io : String | IO, trusted : Bool = false) #

Create a new empty model and fill the columns from json. Returns the new model

Trusted flag set to true will allow mass assignment without protection, FALSE by default


def self.full_table_name #

returns the fully qualified and escaped name for this table. add schema if schema is different from 'public' (default schema)

ex: "schema"."table"


[View source]
def self.import(array : Enumerable(self), on_conflict : Lustra::SQL::InsertQuery -> | Nil = nil) #

Import a bulk of models in one SQL insert query. Each model must be non-persisted.

on_conflict callback can be optionnaly turned on to manage constraints of the database.

Note: Old models are not modified. This method return a copy of the models as saved in the database.

Example:

users = [User.new(id: 1), User.new(id: 2), User.new(id: 3)]
users = User.import(users)

[View source]
def self.polymorphic? : Bool #

def self.public #

[View source]
def self.query #

Return a new query SELECT * FROM [my_model_table]. Can be refined after that. Automatically applies default_scope if defined.


[View source]
def self.read_only=(read_only : Bool) #

def self.read_only? : Bool #

def self.register_counter_cache(association_model : Class, counter_column : String, foreign_key : String) #

Register a counter cache for this model using model class


[View source]
def self.reset_counters(id, *counter_models) #

Reset counter cache columns to their correct values. This is useful when counter caches become out of sync due to direct SQL operations.

Example:

User.reset_counters(user.id, Post)
User.reset_counters(user.id, Post, Comment)

[View source]
def self.schema : Lustra::SQL::Symbolic | Nil #

Define the current schema used in PostgreSQL. The value is nil by default, which lead to non-specified schema during the querying, and usage of "public" by PostgreSQL.

This property can be redefined on initialization. Example:

class MyModel
  include Lustra::Model

  self.schema = "my_schema"
end
MyModel.query.to_sql # SELECT * FROM "my_schema"."my_models"

def self.schema=(schema : Lustra::SQL::Symbolic | Nil) #

Define the current schema used in PostgreSQL. The value is nil by default, which lead to non-specified schema during the querying, and usage of "public" by PostgreSQL.

This property can be redefined on initialization. Example:

class MyModel
  include Lustra::Model

  self.schema = "my_schema"
end
MyModel.query.to_sql # SELECT * FROM "my_schema"."my_models"

def self.table : Lustra::SQL::Symbolic #

Return the table name setup for this model. By convention, the class name is by default equals to the pluralized underscored string form of the model name. Example:

MyModel => "my_models"
Person => "people"
Project::Info => "project_infos"

The property can be updated at initialization to a custom table name:

class MyModel
  include Lustra::Model

  self.table = "another_table_name"
end
MyModel.query.to_sql # SELECT * FROM "another_table_name"

def self.table=(table : Lustra::SQL::Symbolic) #

Return the table name setup for this model. By convention, the class name is by default equals to the pluralized underscored string form of the model name. Example:

MyModel => "my_models"
Person => "people"
Project::Info => "project_infos"

The property can be updated at initialization to a custom table name:

class MyModel
  include Lustra::Model

  self.table = "another_table_name"
end
MyModel.query.to_sql # SELECT * FROM "another_table_name"

def self.tables_only #

[View source]
def self.views_only #

[View source]

Instance Method Detail

def add_built_association(association_name : String, model : Lustra::Model) #

Add a built association to track for autosave


[View source]
def attributes : Hash(String, Lustra::SQL::Any) #

Attributes, used when fetch_columns is true


def built_associations : Hash(String, Array(Lustra::Model)) #

Track built associations for autosave functionality


def built_associations=(built_associations : Hash(String, Array(Lustra::Model))) #

Track built associations for autosave functionality


def cache : Lustra::Model::QueryCache | Nil #

def changed : Array(String) #

Returns an array of names of all changed attributes.

user.email = "new@test.com"
user.first_name = "John"
user.changed  # => ["email", "first_name"]

def changed? #

Return true if the model is dirty (e.g. one or more fields have been changed.). Return false otherwise.


def changes : Hash(String, Tuple(Lustra::SQL::Any, Lustra::SQL::Any)) #

Returns a hash of all changed attributes with their [old_value, new_value].

user.email = "new@test.com"
user.first_name = "John"
user.changes  # => {"email" => ["old@test.com", "new@test.com"], "first_name" => [nil, "John"]}

def clear_built_associations #

Clear all built associations (called after successful save)


[View source]
def clear_change_flags #

Reset the #changed? flag on all columns

The model behave like its not dirty anymore and call to save would apply no changes.

Returns self


The method columns is a has_many relation to Lustra::Reflection::Column


def has_built_associations? : Bool #

Check if there are any pending built associations


[View source]
def indexes : Hash(String, Array(String)) #

List all the indexes related to the current table. return an hash where the key is the name of the column and the value is an array containing all the indexes related to this specific field.


[View source]
def invalidate_caching : self #

Force to clean-up the caches for the relations connected to this model.


[View source]
def reset(h : Hash(Symbol, _)) #

Set the columns from hash


def reset(h : Hash(String, _)) #

Set the model fields from hash


def reset(t : NamedTuple) #

def reset(from_json : JSON::Any) #

def reset(**t : **T) forall T #

reset flavors


def reset_counters(*counter_models) #

Reset counter cache columns

Example:

user = User.find(1)
user.reset_counters(Post)
user.reset_counters(Post, Comment)

[View source]
def set(h : Hash(Symbol, _)) #

Set the columns from hash


def set(h : Hash(String, _)) #

Set the model fields from hash


def set(t : NamedTuple) #

def set(from_json : JSON::Any) #

def set(**t : **T) forall T #
Description copied from module Lustra::Model::HasColumns

Set one or multiple columns to a specific value This two are equivalents:

model.set(a: 1)
model.a = 1

def set_from_json(string_or_io : String | IO, trusted : Bool = false) #

Set the fields from json passed as argument Trusted flag set to true will allow mass assignment without protection, FALSE by default


def table_catalog : String #

Returns the value of #table_catalog column or throw an exception if the column is not defined.


def table_catalog=(x : String) #

Setter for #table_catalog column.


Returns the column object used to manage #table_catalog field

See Lustra::Model::Column


def table_name : String #

Returns the value of #table_name column or throw an exception if the column is not defined.


def table_name=(x : String) #

Setter for #table_name column.


Returns the column object used to manage #table_name field

See Lustra::Model::Column


def table_schema : String #

Returns the value of #table_schema column or throw an exception if the column is not defined.


def table_schema=(x : String) #

Setter for #table_schema column.


Returns the column object used to manage #table_schema field

See Lustra::Model::Column


def table_type : String #

Returns the value of #table_type column or throw an exception if the column is not defined.


def table_type=(x : String) #

Setter for #table_type column.


Returns the column object used to manage #table_type field

See Lustra::Model::Column


def to_h(full = false) : Hash(String, Lustra::SQL::Any) #

Return a hash version of the columns of this model.


def to_json(emit_nulls : Bool = false) #

def to_json(json, emit_nulls = false) #

def update_from_json(string_or_io : String | IO, trusted : Bool = false) #

Set the fields from json passed as argument and call save on the object Trusted flag set to true will allow mass assignment without protection, FALSE by default


def update_from_json!(string_or_io : String | IO, trusted : Bool = false) #

Set the fields from json passed as argument and call save! on the object Trusted flag set to true will allow mass assignment without protection, FALSE by default


def update_h : Hash(String, Lustra::SQL::Any) #

Generate the hash for update request (like during save)


def validate_fields_presence #

For each column, ensure than when needed the column has present information into it.

This method is called on validation.