Crystal ORM using ActiveRecord pattern with flexible query DSL
General
1.5.0
warning (for full list see MR)0.14.0
0.26.0
jsonb
type support for model and migration generatorsphoffer/inflector.cr
inflector library with luckyframework/wordsmith
QueryBuilder
Query.count
returns Int64
instead of Int32
Query.offset
accepts Int32
or Int64
as input instead of only Int32
#group
, #select
raise an ArgumentError
if block returns anything except array#having
, #reorder
, #order
raises ExpressionBuilder
as a block argument#where
accepts hash with string keys as well#find_or_create_by
, #find_or_create_by!
, #find_or_initialize_by
to create/instantiate a record if nothing was found in the DB#find_by
and #find_by!
as a shortcut for .where().first
and .where().first!
Model
id
attribute type from Int32
to Int64
Int64
attribute that calls #to_i64
on Int32
valuenull: true
if null
property is missing and field is primary.ids
to Array(Int64)
Model.count
returns Int64
instead of Int32
JSON::PullParser
attribute class#here
, #select
, #from
, #union
, #distinct
, #order
, #group
, #with
, #merge
, #limit
, #offset
, #lock
, #reorder
, #count
, #max
, #min
, #sum
, #avg
, #group_count
, #group_max
, #group_min
, #group_sum
, #group_avg
, #with_relation
, #includes
, #preload
, #eager_load
, #last
, #last!
, #first
, #first!
, #find_by
, #find_by!
, #pluck
, #exists?
, #increment
, #decrement
, #ids
, #find_records_by_sql
, #find_in_batches
, #find_each
, #join
, #right_join
, #left_join
, #lateral_join
.create
and .create!
that accepts blockAdapter::Base.coerce_database_value
in constructors accepting a hash or named tuple to coerce values for columns that don't have specified converterJennifer::Model::OptimisticLocking#reset_lock_version
decreasing lock version column when it's not changedValidation
jennifer.errors.messages.required
message in locale yaml fileJennifer::Model::Errors#add
accepts String | Symbol | Proc(Translation, String, String)
for message
argumentvalidates_inclusion
, validates_exclusion
, validates_format
, validates_length
, validates_uniqueness
, validates_presence
, validates_absence
, validates_numericality
, validates_acceptance
& validates_confirmation
validation macros accepts message
option that allows to specify validation messageRelation
belongs_to
relation macro accepts required
option to validate existence of relation on saveView
#here
, #select
, #from
, #union
, #distinct
, #order
, #group
, #with
, #merge
, #limit
, #offset
, #lock
, #reorder
, #count
, #max
, #min
, #sum
, #avg
, #group_count
, #group_max
, #group_min
, #group_sum
, #group_avg
, #with_relation
, #includes
, #preload
, #eager_load
, #last
, #last!
, #first
, #first!
, #find_by
, #find_by!
, #pluck
, #exists?
, #increment
, #decrement
, #ids
, #find_records_by_sql
, #find_in_batches
, #find_each
, #join
, #right_join
, #left_join
, #lateral_join
Adapter
id
column from the versions
table schemaid
column type from int
to bigint
Base.coerce_database_value
method to provide interface to perform coercing from default database type used to read column to hash to a desired model attribute typeSqlGenerator
FROM
clause when string value is given for #from
Record
#foo_bar
method on a record that is missing raises ArgumentError
instead of KeyError
In memory of my father - even with very low understanding in programming, he was always interested in the current state of Jennifer and whether it was useful to people
General
QueryBuilder
#pluck
accepts splatted named tuple of desired attribute-type pairs and returns array of such tuples as a records#upsert
passes expression builder as a block argumentModel
with_optimistic_lock(column_name = lock_version)
updated_at
and created_at
fields aren't override on save if have been set manuallyupsert
class method to insert multiple models while ignoring conflicts on specified unique fieldsAdapter
RequestMethods
instead of including it by base adapter classupsert
overload that allows passing a collection of Jennifer::Model::Base
insert_on_duplicates
sql generation for postgres adapter if no unique fields givenSqlGenerator
INSERT
, UPDATE
, SELECT
and DELETE
requests uses quoted tables/columns if they are created by QueryBuilder::ExpressionBuilder
(raw SQL is placed as-is).select_clause
uses specified query attributes to select and fall back to custom fields only if there is no custom attribute to selectMigration
TableBuilder::ChangeTable
now performs DropForeignKey
, DropIndex
& DropReference
before any column manipulationTableBuilder::ChangeEnum
to use specified adapter to query effected tablesI'm happy to announce that the release supporting crystal >= 1.0.0
is published. Summarizing changelog below I'd like to emphasize next points:
#to_json
method to simplify serializationGeneral
>= 1.0.0
support#to_json
to the following structs: PG::Numeric
, PG::Geo::Point
, PG::Geo::Line
, PG::Geo::Circle
, PG::Geo::LineSegment
, PG::Geo::Box
, PG::Geo::Path
, PG::Geo::Polygon
, Char
, Time::Span
, Slice
, UUID
crystal-mysql: 0.13.0
supportcrystal-pg: 0.23.2
supportQueryBuilder
#to_json
to serialize retrieved collection#where
accepting Hash(Symbol, _)
Criteria#equal
and Criteria#not_equal
as original implementation of Criteria#==
and Criteria#!=
ExpressionBuilder
#and
, #or
and #xor
methods that accepts array of conditionsModel
Authentication#password
returns given unecrypted valueCoercer
module with static methods to localize all coercing logic for different types.coercer
method to return object responding to all coercing methods described in Coercer
mapping
generates .coerce_{{attribute}(value : String)
methods for every field to coerce string value to attribute
's typemapping
generates for every non-string attribute with a setter additional #{{attribute}}=(value : String)
setter.new
, .create
and .update
) to receive Hash(String, String)
and coerce values to expected types.column_name
to return all field names.field_names
from returning child's properties for parent class#to_json
.from_db(DB::ResultSet, NamedTuple)
, .from_db(DB::ResultSet, NamedTuple)
and .from_hash(Hash, String | Symbol, NamedTuple)
BigDecimalConverter(T)
converterCoercer.coerce(String, (BigDecimal?).class)
time_zone_aware
option for TimeZoneConverter
to specify whether field should respect time zone converting logicTimeZoneConverter
time_format
, date_time_format
and date_format
to customize time, date time and date formats respectivelyNumericToFloat64Converter
, BigDecimalConverter
, TimeZoneConverter
#from_hash
accepts string as field valueBigDecimalConverter#from_hash
accepts integer and float values as field valueErrors#inspect
bug using old UInt64#to_s
signatureTimestamp
module that now includes with_timestamps
macroupdated_at
and created_at
fields are set before save - now they are set explicitly without utilizing callbacksResource.where
accepting Hash(Symbol, _)
Validation
Validator#validate
abstract interface to #validate(record, **opts)
Validator
interfaceValidator.with_blank_validation
macro to accept arguments to reference record, field name, value and blank value acceptanceRelation
#condition_clause
& #condition_clause(a)
declarations from IRelation
View
#to_json
Adapter
#update
declaration from Base
BaseSQLGenerator#parse_query
converts Time
arguments to UTC only if Config.time_zone_aware_attributes
set to true
Mysql#read_column
calls super
if column isn't a tiny intResultParser#read_column
convert time to Config.local_time_zone
if Config.time_zone_aware_attributes
set to true
or just change time zone to it otherwiseConfig
.reset_config
creates new instance instead of executing #initialize
on existing objectConfig.time_zone_aware_attributes
to specify whether time zone converting logic should be globally disabledMigration
precision
and scale
options support for decimal
data typeRecord
#to_json
#inspect
General
QueryBuilder
Query
instances as nested queries for CTEsnil
assertion when eager load relations sequence with missing intermediate relation recordsIModelQuery#find(id)
to retrieve record by primary keyIModelQuery#find!(id)
to retrieve record by primary key or raise Jennifer::RecordNotFound
exceptionModelQuery(T)#to_a
and ModelQuery(T)#find_by_sql
ensure T
has loaded actual table field count before making a requestModel
Hash(String, Jennifer::DBany)
to Hash(String, AttrType)
(same for Symbol
keys)CommonMapping#attribute
uses attribute getterCommonMapping#attribute
raises Jennifer::UnknownAttribute
exception if model has no requested attribute and raise_exception = true
CommonMapping#attribute_before_typecast
which returns given attribute in database format using attribute converterMapping#{{attribute}}_will_change!
to mark {{attribute}}
as changed one#primary
uses getterMapping.mapping
invocation creates AttrType
alias to represent union of Jennifer::DBAny
and any arbitrary type from fields definitionMapping#update_columns
argument type to Hash(String | Symbol, AttrType)
Mapping#update_columns
raises Jennifer::UnknownAttribute
if key-value pairs include unknown attributeMapping#set_attribute
to accept AttrType
Mapping#set_attribute
raises Jennifer::UnknownAttribute
exception if model has no requested attributeMapping#update_columns
raises Jennifer::UnknownAttribute
if key-value pairs include unknown fieldMapping#arguments_to_insert
and Mapping#arguments_to_save
use #attribute_before_typecast
to collect attributes to store in a database#add_{{relation}}
accepts AttrType
as a hash value typeEnumConverter
to PgEnumConverter
EnumConverter(T)
to convert string to crystal enumJSONSerializableConverter(T)
to convert JSON field to objects of T
that support .from_json
and #to_json
methodsTimeZoneConverter
to convert time attributes from UTC to Jennife::Config.local_time_zone
Adapter
DBFormater
as a proposed default logger formatterLog::Metadata
with query
, args
and time
keys (as new crystal-db does)SqlGenerator
Adapter::BaseSQLGenerator
now produces valid SQL when using multiple recursive CTEs (.with(..., true)
) in a single queryMigration
TableBuilder::DB_OPTIONS
to TableBuilder::DbOptions
Exceptions
Jennifer::UnknownAttribute
to represent case when unknown attribute is tried to be read/writtenGeneral
0.34.0
supportJennifer::Presentable
with abstract methods declarations (#attribute
, #errors
, #human_attribute_name
, #attribute_metadata
, #class_name
)QueryBuilder
Query#initialize
now accept Adapter::Base
as a second (optional) argumentOrderItem
is renamed to OrderExpression
to avoid possible name collisionsModel
new_record
and destroyed
system variables by #to_json
Resource.table_prefix
now returns underscored namespace name (if any) by defaultBase
includes Jennifer::Presentable
Translation#class_name
method to return underscored class nameMapping#attribute_metadata
to return attribute metadata by it's nameBase::primary_field_type
Model
or Record
View
new_record
and destroyed
system variables by #to_json
Base::primary_field_type
Adapter
Adapter.adapter_class
raises BaseException
if no valid Config.adapter
is specified.command_interface
, .create_database
, .drop_database
, .generate_schema
, .load_schema
, .db_connection
, .connection_string
, .database_exists?
now are instance methodsBase#initialize
now excepts Config
instanceJennifer::Postgres::CommandInterface#database_exists?
Config#logger
now is Log
instead of Logger
.adapter
& .adapter_class
.query
, .exec
& .scalar
Config
.reset_config
invokes #initialize
instead of creating new instanceMigration
Base#schema_processor
is no more public apiRunner.create
and Runner.drop
now accept option Adapter::Base
instanceto_table
in TableBuilder::DropForeignKey#process
TableBuilder::CreateTable#reference
- now it takes into account given SQL type for the foreign key column#add_reference
, #drop_reference
, #add_timestamps
to TableBuilder::CHangeTable
TableBuilder::CHangeTable#drop_index
also accepts single column nameTableBuilder::CreateTable#index
overridesRecord
#initialize(DB::ResultSet)
is removedQueryBuilder
#read_column
in NestedRelationTree
RelationTree#adapter
Ordering#order(Hash(String | Symbol, String | Symbol))
Adapter
tinyint
mysql field as boolean
ResultParser#result_to_array
Mysql#read_column
Base.default_max_bind_vars_count
which returns default maximum count of bind variables that can be used in Base#bulk_insert
(default is 32766)Mysql.default_max_bind_vars_count
and Postgres.default_max_bind_vars_count
returns 32766
Base#bulk_insert
doesn't do table lock no moreBase#bulk_insert
exceed Base.max_bind_vars
all of them are quoted and put into a queryBaseSQLGenerator::ARRAY_ESCAPE
BaseSQLGenerator::ARGUMENT_ESCAPE_STRING
to Quoting
BaseSQLGenerator
.quote
, .escape_string
, .filter_out
to Quoting
postgres
adaptermysql
adapterBEGIN
instead of TRANSACTION START
, COMMIT
instead of TRANSACTION COMMIT
and ROLLBACK
instead of TRANSACTION ROLLBACK
on corresponding transaction commandsSchemaProcessor::FkEventActions
enum to validate on_delete
and on_update
action values; String | Symbol
still should be used as an argument type everywhereConfig
max_bind_vars_count
property to present maximum allowed count of bind variables to be used in bulk insert operationMigrationFailureHandler
enum to validate migration_failure_handler_method
value; Symbol | MigrationFailureHandler
should be used as an argument for itmigration_failure_handler_method
config - make it instance propertyGeneral
0.31.1
compatibility[email protected]
supportsam
from mandatory dependenciesModel
View
Adapter
date
SQL data typedate_time
field type maps to timestamp
SQL data type (postgres only)Migration
Runner.pending_migration?
to return whether there is pending (not invoked) migrationBase.with_transaction
method to disable automatic transaction wrapping around migration methodsBase.with_transaction?
to check whether migration is run under a transactionvar_string
field typeblob
field type for postgresTableBuilder::CreateIndex
TableBuilder::CreateTable#index
signatures (old ones are deprecated):
#index(fields : Array(Symbol), type : Symbol | ::Nil = nil, name : String | ::Nil = nil, lengths : Hash(Symbol, Int32) = {} of Symbol => Int32, orders : Hash(Symbol, Symbol) = {} of Symbol => Symbol)
#index(field : Symbol, type : Symbol | ::Nil = nil, name : String | ::Nil = nil, length : Int32 | ::Nil = nil, order : Symbol | ::Nil = nil)
varchar
length 254
(mysql only)Base#add_foreign_key
accepts on_delete
and on_update
keyword arguments to specify corresponding actionsTableBuilder::ChangeTable#add_foreign_key
accepts on_delete
and on_update
keyword arguments to specify corresponding actionsTableBuilder::CreateTable#reference
accepts on_delete
and on_update
options to specify corresponding actionsTableBuilder::CreateTable#foreign_key
accepts on_delete
and on_update
keyword arguments to specify corresponding actionsTiny release to update dependencies