Crystal ORM using ActiveRecord pattern with flexible query DSL
It has been a long time since previous release but expectation is worth it. 0.8.0 release brings a lot of new features such as:
Model.new
now respects after_initialize
callbacksCTE
Also a lot of bugs were fixed and performance enhancements were made.
API documentation is hugely increased so now almost all places are covered.
General
db:migrate
task outputs information about executed migrationsdb:create
command doesn't fail if database already existsQueryBuilder
Criteria#similar
which is loaded with postgres
adapterQuery#insert
and Query#upsert
ExpressionBuilder#values
and Values
to reference to VALUES
statement in upsert.find_by_sql
and .to_a
of ModelQuery(T)
use T.new
instead of T.build
CommonTableExpression
to present SQL CTEEagerLoading#with
to #with_relation
#last!
and #last
assigns old limit value back after request instead of additional #reverse_order
callQuery
allocation by making all query part containers nilableQuery#union
setting union to be UNION ALL
Query#with
presents API for registering common table expressionQuery#merge
Query#where
yields expression builderQuery
's #join
, #right_join
, #left_join
and #lateral_join
yield expression builders of a main query and joined contextcount
, sum
, avg
, min
, max
, coalesce
and concat_ws
sql functionsround
function now accepts second optional argument specifying precisionFunction
's #operands_to_sql
and #operand_sql
now are publicFunction.define
macro accepts comment
key to specify function class documentation commentFunction.define
macro arity
argument by default is 0
(instead of -1
)ExpressionBuilder#cast
Criteria#in
LIMIT
in query generated by #first!
Executables#exists?
query method to Bool
(thanks @skloibi)Executables#explain
Model
Base.new
now calls after_initialize
hooks and supports STIBase.build
now is alias for Base.new
Mapping.mapping
now is parsed before main mapping macro is executed#append_{{relation_name}}
methods of RelationDefinition
now use .new
to build a related objectResource::Supportable
alias is removedResource.search_by_sql
is removed in favour of Resource.all.find_by_sql
type
field without default valuecolumn
that defines a custom column name that is mapped to this field (thank @skloibi)Base#table_name
is moved to Resource
Mapping
module now can be included by another module with mapping definitionSTIMapping
now doesn't convert result set to hash and use same logic as Mapping
:auto
mapping option to specify whether primary key is autoincrementableValidation
Validations::Uniqueness
to consider field mappings when validating properties (thank @skloibi).validates_uniqueness
to validate combination uniqueness (thank @skloibi)View
Mapping
instead of ExperimentalMapping
; new mapping heavily reuse Model::Mapping
column
option (cf. Model) (thank @skloibi)Model
'sAdapter
Base::ArgType
aliasBase#upsert
Postgres::Adapter#data_type_exists?
is renamed to #enum_exists?
postgres
adapterTableBuilderBuilders
- now Migration::Base
creates commands by its own#exists?
query method to Bool
for Base
and Postgres
adapters (thanks @skloibi)Base#explain
abstract method and implementations for Mysql
and Postgres
Config
verbose_migrations
to hide or show migration details during db:migrate
command invocationSqlGenerator
.insert_on_duplicate
and .values_expression
to BaseSQLGenerator
as abstract methods and implementations to Postgres
and Mysql
BaseSQLGenerator.from_clause
accepts 2 arguments (instead of 2..3) accepting table name as 2nd argumentBaseSQLGenerator.with_clause
which generates CTEBaseSQLGenerator.explain
Migration
Base#tinyint
(not all adapter support it)Base
instance method signature:
#foreign_key_exists?(from_table, to_table = nil, column = nil, name : String? = nil)
#add_index(table_name : String | Symbol, field : Symbol, type : Symbol? = nil, name : String? = nil, length : Int32? = nil, order : Symbol? = nil)
(same for TableBuilder::CreateTable#index
and TableBuilder::ChangeTable#add_index
)#drop_index(table : String | Symbol, fields : Array(Symbol) = [] of Symbol, name : String? = nil)
(same for TableBuilder::ChangeTable#drop_index
)#drop_foreign_key(to_table : String | Symbol, column = nil, name = nil)
(same for TableBuilder::ChangeTable#drop_foreign_key
)TableBuilder::CreateTable#column
as alias to TableBuilder::CreateTable#field
TableBuilder::CreateTable#reference
- #reference(name, type : Symbol = :integer, options : Hash(Symbol, AAllowedTypes) = DB_OPTIONS.new)
Record
BaseException
exception is raised instead of KeyError
QueryBuilder
#pluck
, #update
, #db_results
, #results
. #each_result_set
and #find_in_batches
of Query
respects #none
(returns empty result if it has being called)QueryObject
constructor accepting array of options and #params
Model
Generic
s are assumed as unions (#208)Validation
.validates_uniqueness
to validate combination uniquenessAdapter
Mysql::SchemaProcessor
now respects false
as column default valuePostgres::SchemaProcessor
now respects false
as column default valueConfig
pool_size
which sets max_idle_pool_size = max_pool_size = initial_pool_size
to the given value; getter #pool_size
returns #max_pool_size
postgres
is no more default adapterMigration
TableBuilder::Base::AllowedTypes
alias includes Float64
and JSON::Any
This release was hard and pretty long. As a result we've got a set of very important features (like polymorphic relations and complex query update mechanism). Also as a side effect bunch of side-shards were appeared to fill gaps in missing functionality (like form parsing).
Also you can find 3 sample application describing possible way of integrating web frameworks/libraries with Jennifer:
General
sam
to "~> 0.3.0"
generate:model
to generate model and related migrationJennifer::Generators
spacedb:seed
task as a placeholder seeding taskdb:setup
now invokes db:seed
after db:migrate
QueryBuilder
#and
, #or
and #xor
shortcut methods to ExpressionBuilder
Criteria#in
now accepts SQLNode
as wellStatement
module with base abstract functionality needed for query string generatingExpressionBuilder#g
and #group
now has no argument type restrictionGrouping#condition
now can be of Statement
typeQuery
includes Statement
Query#to_sql
now is #as_sql
, #select_args
- #sql_args
Condition
includes Statement
Executables#update
accepts block expecting Hash(Symbol, Statement)
to be returnedExecutables#modify
is removed in favor of new #update
method accepting blockLogicOperator
is inherited from SQLNode
#delete
and exists?
of Executables
do nothing when #do_nothing?
is true
Query#do_nothing?
Query.null
which returns Query.new.none
Join
accepts Grouping
for ON
conditionModel
Base.build_params
, Base.parameter_converter
methodsParameterConverter
classMapping.mapping
when at least one field has default value and all others are nilablestringified_type
option is removed from the COLUMNS_METADATA
STIMapping#arguments_to_save
& STIMapping#arguments_to_insert
now respect field converterTranslation
model now is includeable moduleTranslation
are moved to Translation::ClassMethods
which is automatically extended by target class using included
macro#lookup_ancestors
and #human_attribute_name
methods of Translation
are addedErrors#base
now is type of Translation
instead of Base
Base#persisted?
Resource#inspect
is generated by .mapping
has_one
, has_many
and belongs_to
relations:nodoc:
for almost all generated relation methods (except #association
)Relation::Base
methodsRelation::IPolymorphicBelongsTo
, Relation::PolymorphicHasMany
and Relation::PolymorphicHasOne
@new_record
, @destroyed
, @errors
, changeset and relation attributes now is ignored by JSON::Serializable
skip_validation
argument to Authentication.with_authentication
macro to specify whether validation should be added#{{attribute}}?
for boolean attributeJennifer::Model::Base#attribute=
to accept not only defined type but also Jennifer::DBAny
Base#update_attributes
to Base#set_attributes
Validation
:if
key; the value may be both Symbol
name of a method to be called or expressionValidations::Absence
, Validations::Acceptance
, Validations::Confirmation
, Validations::Exclusion
, Validations::Format
, Validations::Inclusion
, Validations::Length
, Validations::Numericality
, Validations::Presence
, Validations::Uniqueness
Jennifer::Validator
in favour of Jennifer::Valdiations::Validator
Jennifer::Validations::Macros
View
Resource#inspect
is generated by .mapping
#{{attribute}}?
for boolean attributeAdapter
Adapter#foreign_key_exists?
Mysql::SchameProcessor
Base#schema_processor
is abstractPostgres::SchemaProcessor#rename_table
SchemaProcessor
now is abstract classSchemaProcessor
class to TableBuilderBuilders
moduleSchemaProcessor#drop_foreign_key
_query
arguments in Base
methods are renamed to query
Base.extract_arguments
is removed.delete
, .exists
and .count
of BaseSQLGenerator
now returns stringPostgres.bulk_insert
is removedTransaction#with_connection
ensure to release connectionConfig
migration_failure_handler_method
property from being globalmodel_files_path
representing model directory (is used in a scope of model generating)skip_dumping_schema_sql
configSqlGenerator
.select_clause
now doesn't invoke .from_clause
under the hood.lock_clause
adds whitespaces around lock statement automaticallyMigration
Runner.generate
and Runner::MIGRATION_DATE_FORMAT
TableBuilder::CreateTable#reference
triggers #foreign_key
and accepts polymorphic
bool argument presenting whether additional type column should be added; for polymorphic reference foreign key isn't addedExceptions
QueryBuilder::Query#first!
and QueryBuilder::Query#last!
includes detailed parsed queryThis is an intermediate release before the breaking 0.7.0
.
General
:nodoc:
to all internal constants and generated methods (implementing standard ORM methods) from the macrosQueryBuilder
Query
isn't extended by Ifrit
OrderItem
to describe order directionCriteria#order
, Criteria#asc
and Criteria#desc
to create OrderItem
Condition#eql?
to compare with other condition or SQLNode
(returns false
)Criteria#eql?
, Grouping#eql?
, LogicOperator#eql?
Query#order
and Query#reorder
with accepting OrderItem
Query#order
with block to expect a OrderItem
CriteriaContainer
QueryObject
now is an abstract classArgumentError
in #max
, #min
, #sum
, #avg
methods of Aggregation
to "Cannot be used with grouping"Query#from(_from : String | Query)
signature to Query#from(from : String | Query)
Model
#save
and #update
will return true
when is called on an object with no changed fields (all before callbacks are invoked)Base
methods become abstract: .primary_auto_incrementable?
, .build_params
, #destroy
, #arguments_to_save
, #arguments_to_insert
Base#_extract_attributes
and Base#_sti_extract_attributes
become private
Resource
methods become abstract: .primary
, .field_count
, .field_names
, .columns_tuple
, #to_h
, #to_str_h
Resource
isn't extended by Ifrit
.build_params
for STI modelsScoping.scope(Symbol,QueryObject)
now checks in runtime whether T
of Jennifer::QueryBuilder::ModelQuery(T)
responds to method named after the scopeView
Base#_after_initialize_callback
becomes protected
Base#_extract_attributes
becomes private
Adapter
Migration
TableBuilder::Base
isn't extended by Ifrit
TableBuilder::ChangeTable#new_table_rename
getter to #new_table_name
TableBuilder::ChangeTable#rename_table
TableBuilder::ChangeTable#change_column
has next changes:
old_name
argument renamed to name
new_name
argument is replaced with option in options
arguemnt hashArgumentError
if both type
and options[:sql_type]
are nil
TableBuilder::ChangeTable#change_column
raises ArgumentError
if both type
and options[:sql_type]
are nil
TableBuilder::CreateTable#field
data_type
argument renamed to type
TableBuilder::CreateTable#timestamps
creates fields with null: false
by defaultTableBuilder::CreateTable#add_index
is removed in favour of #index
.pending_versions
, .assert_outdated_pending_migrations
and .default_adapter
methods of Runner
become privateRunner.config
is removedGeneral
Time::Span
to supported typesQueryBuilder
SQLNode
instance in SELECT clause (like raw sql or functions)SQLNode#sql_args_count
SQLNode#filterable?
function which presents if node has filterable sql parameterCondition#sql_arg
Function
base abstract class for defining custom sql functionslower
, upper
, current_timestamp
, current_date
, current_time
, now
, concat
, abs
, ceil
, floor
, round
Join#filterable?
and Query#filterable?
AmbiguousSQL
when %
symbol is found in the raw SQL (except %s
)Model
numeric_converter
with new converter
NumericToFloat64Converter
and JSONConverter
#to_h
and #to_str_h
use field getter methodsputs
from JSONConverter#from_db
Adapter
DB::Error
instead of wrapping it into BadQuery
Config
max_pool_size
to 1 and warn about danger of setting different max_pool_size
, max_idle_pool_size
and initial_pool_size
Migration
Migration::TableBuilder::CreateForeignKey
& Migration::TableBuilder::DropForeignKey
Migration::Base#add_foreign_key
& Migration::Base#drop_foreign_key
Migration::TableBuilder::ChangeTable#add_foreign_key
& Migration::TableBuilder::ChangeTable#drop_foreign_key
Exceptions
AmbiguousSQL
- is raised when forbidden %
symbol is used in the raw SQLThis release brings a lot of features that are useful for the web-based applications. Enjoy :smile: :balloon: :tada:
General
0.25.0
time_zone
dependency"inflector/string"
Time::Location
& Time::Location::Zone
Ifrit.typed_hash
and Ifrit.typed_array
usagePrimary32
and Primary64
are mapping types (not aliases of Int32
and Int64
)accord
dependencyQueryBuilder
ModelQuery(T)#eager_load
and ModelQuery(T)#include
QueryBuilder::EagerLoading
which is included in QueryBuilder::IModelQuery
Model
Mapping.build_params
and ParameterConverter
class for converting Hash(String, String)
parameters to acceptable by modelBase::RELATIONS
Jennifer::Model::Authentication
module with authentication logicIRelation
when app has no belongs-to relation definedInt64
primary key#inspect
numeric_converter
mapping option for numeric postgres fieldJennifer::Model::Errors
class replacing Accord::ErrorList
which mimics analogic rails one a lot;Translation::human_error
method functionality to introduced Errors
instance levelResource
static methods are abstract: actual_table_field_count
, primary_field_name
, build
, all
, superclass
Resource#inspect
returns simplified version (only class name and object id)Resource.all
now is a macro methodModel::Transaltion.lookup_ancestors
from breaking at compilation timeView
ExperimentalMapping#attributes_hash
, ExperimentalMapping.strict_mapping?
Config
local_time_zone
now is a Time::Location
Time::Location.local
as default valueSqlGenerator
\n
with whitespace character as query part separatorMigration
Jennifer::Migration::Base.migrations
returns a hash of version number => migration class instead of array of classesThis is a temporary release before the 0.6.0.
All changes could be found in CHANGELOG.md
file.
This is an anniversary release - 1 year ago the very first commit has been made. A lot of work have been done and a lot of will be but for now this it is the most powerful ORM for crystal - with flexible query dsl, mapping declaration, callbacks, validation, internationalization, migrating mechanism, materialized and non materialized view
i18n
shardtime_zone
- any time object is converted from local time to UTC during storing it to the db and vise versaMore complite list of changes could be found in CHANGELOG.md file. Also documentation .md
files has got new information - check it out.
Have an awesome coding and happy Valentine's day :heart:
Adapter
Jennifer::Adapter::TICKS_PER_MICROSECOND
Jennifer::Adapter::Mysql#table_column_count
bugModel
Primary32
and Primary64
shortcuts for primary key mapping (view mapping respects this as well)::create!
& ::create
with splatted named tuple argumentsJennifer::Mode::build
method to %mapping
macro#reload
method for sti recordQueryBuilder
Criteria#not
Criteria#ilike
View
View::Materialized
superclass for materialized viewsCOLUMNS_METADATA
constant::columns_tuple
which retrns COLUMNS_METADATA
::children_classes
after_initialize
callback respect inheritance::adapter
Exceptions
AbstractMethod
exception which represents expectation of overriding current method by parents (is usefull when method can't be real abstract one)UnknownSTIType
SqlGenerator
#trancate
to #truncate
Migration
rename TableBuilder::DropInde
to TableBuilder::DropIndex
remove printing out redundand execution information during db drop and create
remove Migration::Base::TABLE_NAME
constant
allow to pass QueryBuilder::Query
as source to the CreateMaterializedView
(postgres only)
Model
move Base#build
method witout arguments to Mapping
module under the %mapping
added validates_presence_of
validation macros
fixed callback invokation from parent classes
add allow_blank
key to validates_inclusion
, validates_exclusion
, validates_format
add ValidationMessages
module which includes methods generating validation error messages
add Primary32
and Primary64
shortcuts for Int32
and Int64
primary field declarations for model and view
allow use nil usions instead of null: true
named tuple option
QueryBuilder
#count
method is moved from Executables
module to the Aggregations
one
changed method signature of #find_in_batches
add #find_each
- works same way as #find_in_batches
but yields each record instead of array
add #ordered?
method to Ordering
module
switch Criteria#hash
to use object_id
as seed
add Query#eql?
add Query#clone
and all related methods
add Query#except
- creates clone except given clauses
make IModelQuery
class as new superclass of ModelQuery(T)
; move all methods no depending on T
to the new class