- Support wrapping associations in resources for targets that do not explicitly contain the
Enumerable
module. For example,ActiveRecord::Associations::CollectionProxy
are actually not enumerable, yet they proxy the calls directly to the underlying objects when necessary.
- Fix
Resource
to not override association methods already defined - Migrate to FactoryBot
- Fix selector generator to properly handle composite key associations.
- Fix
default_selection
inQuery::Base
to accountt for models with composite identities. - Support
many_to_many
relationships without requiring the:through
annotations (for ORMs that can transparently load the intermediate relationships)
- Added a
:through
option toResource.property
to specify that the property effectively traverses the association(s) given so that it may continue to process additional subfield selections. - Fixed
SystemStackError
fromIdentityMap#add_selectors
if the provided field hashes are self-referencing. I.e.{author: {posts: {author: {...}}}}
- Fixed
SystemStackError
fromSelectorGenerator
for circularResource.property
definitions likeproperty :foo, dependencies: [:foo, :bar]
. - Fixed
Query::Sequel
not working with raw SQL queries. - Fixed SQL logging in
Query::Sequel
for query execution passing a dataset.
- Added
Resource.property
to specify the fields and associations from the underlying model that are needed by methods added to theResource
.- For example:
property :full_name, dependencies: [:first, :last]
specifies that thefull_name
method on the resource depends upon the values of thefirst
andlast
fields from the model.property :owner_name, dependencies: ['owner.first', 'owner.last']
defines a dependency on thefirst
andlast
fields from the associatedowner
.
- Dependencies must always be an array. Symbol values should be used for fields or associations from the same resource, and strings can be used for fields from associated resources.
:*
or'association.*'
may be used to specify a dependency on all of the fields of the resource (analagous to 'SELECT *').- Additionally, property dependencies may specify other properties on the same or related resources.
- For example:
- Added
IdentityMap#add_selectors(resource, field_selector)
to define fields toselect
and associations totrack
givenresource
andfield_selectors
.- For example:
identity_map#add_selectors(PersonResource, full_name: true)
would ensure any loads done for the model thePersonResource
describes will select any fields required by thefull_name
property (first
andlast
in the example above).identity_map#add_selectors(PersonResource, id: true, address: true)
could result in selecting theid
andaddress_id
fields ofPersonModel
, as well as tracking theaddress
association, for any queries involvingPersonModel
.
- For example:
- Added the ability to explicitly perform a "SELECT *" by specifying
select :*
orselect '*'
in a query. - Added
:through
option to many_to_many associations to define the series of associations necessary to resolve it. This is unused by Sequel, but is required by the SelectorGenerator to handle such associations. Specify it as an array of symbols.- For example:
many_to_many :commented_posts, through: [:comments, :post], ...
- For example:
- Remove finalizer from IdentityMap to fix memory leak that was preventing them from being GC'd properly.
- Fixed critical bug in
IdentityMap#finalize!
=
- Added instrumentation through
ActiveSupport::Notifications
- Use the 'praxis.mapper.load' to subscribe to
IdentityMap.load
calls - Use the 'praxis.mapper.finalize' to subscribe to
IdentityMap.finalize!
calls
- Use the 'praxis.mapper.load' to subscribe to
- Optimization on handling repeated ids (especially noticeable when using subloads)
- Refactored
ConnectionManager
repository handling to improve integration with other connection-pooling (specifically Sequel's at present). - Added two types of connection factory under
Praxis::Mapper::ConnectionFactories::
:Simple
: Takes aconnection:
option to specify the raw object to return for allcheckout
. Also, preserves current behavior with proc-based uses whenConnectionManager.repository
is given a block. This is the default factory type if one is not specified for the repository.Sequel
: Takesconnection:
option to specify aSequel::Database
, or hash of options to pass toSequel.connect
.
IdentityMap#finalize!
now callsConnectionManager#release
to ensure any connections are returned to their respective pools, if applicable.- Added
SequelCompat
module, which provides support for usingSequel::Model
objects with anIdentityMap
when included in model class.- This overrides the association accessors on instances associated with an
IdentityMap
(see below for more on this) to query the map instead of database. - See (spec/support/spec_sequel_models.rb) for example definition.
- This overrides the association accessors on instances associated with an
- Added prototype for write-path support to
IdentityMap
(forSequel::Model
models):IdentityMap#attach(record)
: adds the record to the identity map, saving it to the database first if it does not have a value for its primary key (or other identities).IdentityMap#detatch(record)
: removes the record from the identity mapIdentityMap#flush!(record_or_class=nil)
: depending on the value ofrecord_or_class
it:- with no argument, or nil, given it saves all modified records in the identity map.
- with an instance of a model, it saves just that record.
- with a model class, it saves all modified records for that class in the identity map.
IdentityMap#remove
: callsdetatch
with the record, and then callsrecord.delete
to delete it.
- Add preliminary Sequel-centric
Query::Sequel
class that exposes a a Sequel dataset with an interface compatible with otherQuery
types. - Removed
member_name
andcollection_name
methods fromResource
, as well as thetype
alias. - Fixed
IdentityMap#load
to return the records from the identity map corresponding to rows returned from the database. This fixes a bug where loading rows already existing in the identity map would return new record objects rather than the objects in the map.
- Tightened up handling of missing records in
IdentityMap#all
andResource.wrap
. They now will never returnnil
values.
- Add
Resource.decorate
for extending/overriding methods on Resource associations. SeePersonResource
in spec_resources.rb for usage.
- Fixed handling of loads where :staged, which could cause an incorrect underlying query using a "staged" column.
- Relaxed ActiveSupport version dependency from 4 to >=3
- Begin migration to Sequel for
Query::Sql
.#_execute
uses it for a database-agnostic adapter for running raw SQL.#_multi_get
uses it generate a datbase-agnostic where clause
- Added accessor generation for
one_to_many
associations in resources. - Imported
Model
extensions for FactoryGirl topraxis-mapper/support/factory_girl
. - This also adds
IdentityMap#persist!
to insert all rows in the identity map into the database. - Added
SchemaDumper
andSchemaLoader
for dumping and loading schema information inpraxis-mapper/support/schema_dumper
andpraxis-mapper/support/schema_loader
respectively. IdentityMap#all
now accepts non-identity keys as conditions, and will create a secondary index for the key the first time it's queried.- Added
Model#identities
to get a hash of identities and values for a record. - Auto-generated attribute accessors on
Blueprint
do not load (coerce) the value using the attribute. Ensure values passed in already have the appropriate types. Blueprint attributes will still be wrapped properly, however. - Performance and memory use optimizations.
IdentityMap#load
now supports eagerly-loading associated records in a query, and supports the full set of options on the inner query, including- Tracked
:one_to_many
associations now support where clauses. Usingwhere
clauses when tracking other association types is not supported and will raise an exception.
- Moved Blueprint inner attribute creation to finalize!
- Added :dsl_compiler and :identity as valid options for Blueprint.
Praxis::Mapper::Model
Model.context
allows named query parameters to be reused across queries. See documentation for details.Model#_query
references original query that loaded the record.Model.serialized_fields
returns hash of fields defined with eitherjson
oryaml
directives as serialized fields.- Fixed accessors will to raise
KeyError
if the record does not the field (i.e., if it was not loaded from the database), rather than silently returningnil
.
Praxis::Mapper::Query
:- Multiple
select
andtrack
calls within one query are now additive. track
option now takes a block that will be applied to the query used to load the tracked records.context
directive to apply the named context from the model to the query. See documentation for more.
- Multiple
Praxis::Mapper::IdentityMap
- Removed
:track
option from#add_records
in favor of usingModel#_query
to determine tracked associations.
- Removed
- Added
Praxis::Mapper::Support
withMemoryQuery
andMemoryRepository
for use in testing data loading without requiring a database.
The Model
accessor changes may break existing applications that (incorrectly) expect unloaded attributes to return nil
.
- Blueprint.validate now only accepts objects of the its type.
- Improved handling of Blueprints with circular relations.
- First pass at reworking model associations.
- Split
belongs_to
intomany_to_one
andarray_to_many
associations - Added
one_to_many
andmany_to_array
associations (the inverse of the above associations, aka: has_many) - Added association configuration DSL to replace previous hash-based configuration.
- Split
- Added support for code coverage
- Added support for 'guard' gem (use 'bundle exec guard')
- Fixed bug in Praxis::Mapper::Model.undefine_data_accessors when method doesn't exist.
- Safer version checking with Gem::Version class
- Cleaned up Gemfile
- Updated 'slop' gem
- identity map hotfix
- don't know what happened here, check git log I guess
- initial release