-
Notifications
You must be signed in to change notification settings - Fork 4
The low_card_tables
API is non-intrusive — it does not override existing methods to mean different things, and it prefixes all its methods with low_card_
. The API is also fundamentally bulk-oriented: methods all work in a constant number of database statements. If you have a low-card table with 1,000 possible combinations of values in it and zero rows currently, and you call, for example, low_card_find_or_create_ids_for
asking for IDs for every possible combination of values, all at once, then only a handful of SQL statements will be run — and your table will now have 1,000 rows in it, and you'll have your return values.
In general, you will never make calls directly to any of the classes in the LowCardTables::
namespace. Rather, declaring a model as is_low_card_table
or has_low_card_table
gives it additional API.
(You may discover methods on classes that start with _low_card_
— i.e., with an underscore, then low_card
. These are methods that should be considered private to the low_card_tables
system; do not invoke them.)
Here's what the API adds:
-
MyModel.is_low_card_table?
returns true if this model has been declared as a low-card table (usingis_low_card_table
), and false otherwise. This will work for any class that inherits fromActiveRecord::Base
. -
MyModel.has_any_low_card_tables?
returns true if this model has been declared to have a low-card table (usinghas_low_card_table
) and false otherwise. This will work for any class that inherits fromActiveRecord::Base
. -
ActiveRecord::Base.low_card_cache_expiration=
lets you set the low-card caching policy for all low-card tables (that don't have their own policy explicitly set). See Caching for more information.
-
MyModel.low_card_update_foreign_keys!
will look at all references this model has to any low-card tables, compute the correct low-card IDs to go in its columns, and update those columns on this model instance, without saving it. Generally you will never need to call this method, because it is automatically called for you just before saving the object. However, it's there if you need it — for example, if you're preparing a lot of model instances for a call to theactiverecord-import
bulk-import gem, calling this on each instance will set its referring columns properly without impacting performance too much. (This call will touch the database only if it needs to create a new row for the particular combination of attributes on your model.)
Retrieving rows directly:
-
MyLowCardTable.low_card_all_rows
: Returns all rows on the model, as a simpleArray
of model objects, from cache. This is equivalent to simply callingMyLowCardTable.all
, but this comes from the cache, while the latter will (as it would on any ActiveRecord table) run a database query. -
MyLowCardTable.low_card_row_for_id
: Given a single ID, returns the row for that ID as a model object, from cache. RaisesLowCardTables::Errors::LowCardIdNotFoundError
if passed an ID that doesn't exist in the table. -
MyLowCardTable.low_card_rows_for_ids
: If given an array containing multiple IDs, returns aHash
mapping each of them to a model object representing that row, from cache. If given a single ID (not an array), simply returns that model object. RaisesLowCardTables::Errors::LowCardIdNotFoundError
if passed an ID that doesn't exist in the table.
Retrieving rows that partially match a Hash
, or a block:
-
MyLowCardTable.low_card_rows_matching
: Given a block (but no input), returns anArray
of all model objects that match that block. Given a singleHash
as input, returns anArray
of all model objects that match the constraints in thatHash
— for example, given{ :deleted => false, :gender => 'female' }
, you will get anArray
of all rows that havedeleted == false
andgender == 'female'
, no matter what other data they have. Given an array ofHash
es as input, returns aHash
mapping each of thoseHash
es to anArray
of model objects that match the constraints in each of thoseHash
es. -
MyLowCardTable.low_card_ids_matching
: Behaves identically tolow_card_rows_matching
, but returns simple integer IDs, not entire model objects.
Retrieving rows that match an exact set of data:
-
MyLowCardTable.low_card_find_rows_for
: Given a single instance of the model class, returns the canonical instance of the model class whose attributes match that model's attributes. (This may appear to be pointless, but you can pass it a model instance with attributes set, but no ID, and you'll get back a model instance with an ID set, so you can store that ID in an appropriate referring model.) Given a singleHash
that must contain keys for exactly all of the attributes of the low-card model, returns the canonical instance of the model class whose attributes match thatHash
. Given an array of model instances or an array ofHash
es, returns aHash
that maps each of those input values to the canonical instance of the model class that matches that model instance orHash
. This method will returnnil
(or bind the input tonil
in the the returnedHash
) if there is no row in the table for that combination of attributes currently. -
MyLowCardTable.low_card_find_ids_for
: Exactly likelow_card_find_rows_for
, except that simple integer IDs are returned, rather than entire model objects.
Retrieving or creating rows that match an exact set of data:
-
MyLowCardTable.low_card_find_or_create_rows_for
: Behaves identically tolow_card_find_rows_for
, except that rows will be created as necessary for sets of attributes that aren't in the table yet. This happens in a constant number of SQL statements. -
MyLowCardTAble.low_card_find_or_create_ids_for
: Behaves identically tolow_card_find_or_create_rows_for
, except that simple integer IDs are returned, rather than entire model objects.
Manipulating the cache:
-
MyLowCardTable.low_card_flush_cache!
: Flushes the cache for this table. See Caching for why you might want to do that manually.
Finding referring models:
-
MyLowCardTable.low_card_referring_models
: Returns anArray
of allActiveRecord::Base
subclasses that have declared that they refer to this low-card table. (e.g., in our examples,UserStatus.low_card_referring_models
will return[ User ]
.)
Collapsing rows in migrations:
-
MyLowCardTable.low_card_collapse_rows_and_update_referrers!
: Called with no arguments (or a simple optionsHash
); primarily used during migrations, and automatically called for you — you only need to call it yourself if you've toldlow_card_tables
explicitly not to call it in certain situations. If you remove a column from a low-card table, there will suddenly be duplicate rows; this breaks the contract oflow_card_tables
. This method will iterate through the table, detect duplicate rows, pick a 'winner' for each combination of values, delete the 'losers', and then update all referring columns in all referring tables to point to only winners, not losers. As options, you can pass:low_card_update_referring_models => false
if you want to skip the update behavior; you can also pass:low_card_referrers => [ ... ]
(passing an array ofActiveRecord::Base
subclasses) in case, for some reason, it doesn't update columns in one or more referring models properly.