Class: Sequel::Model::Associations::EagerGraphLoader
- Defined in:
- lib/sequel/model/associations.rb
Overview
This class is the internal implementation of eager_graph. It is responsible for taking an array of plain hashes and returning an array of model objects with all eager_graphed associations already set in the association cache.
Instance Attribute Summary collapse
-
#alias_map ⇒ Object
readonly
Hash with table alias symbol keys and association name values.
-
#column_maps ⇒ Object
readonly
Hash with table alias symbol keys and subhash values mapping column_alias symbols to the symbol of the real name of the column.
-
#dependency_map ⇒ Object
readonly
Recursive hash with table alias symbol keys mapping to hashes with dependent table alias symbol keys.
-
#master ⇒ Object
readonly
The table alias symbol for the primary model.
-
#primary_keys ⇒ Object
readonly
Hash with table alias symbol keys and primary key symbol values (or arrays of primary key symbols for composite key tables).
-
#reciprocal_map ⇒ Object
readonly
Hash with table alias symbol keys and reciprocal association symbol values, used for setting reciprocals for one_to_many associations.
-
#records_map ⇒ Object
readonly
Hash with table alias symbol keys and subhash values mapping primary key symbols (or array of symbols) to model instances.
-
#row_procs ⇒ Object
readonly
Hash with table alias symbol keys and callable values used to create model instances.
-
#type_map ⇒ Object
readonly
Hash with table alias symbol keys and true/false values, where true means the association represented by the table alias uses an array of values instead of a single value (i.e. true => *_many, false => *_to_one).
Instance Method Summary collapse
-
#initialize(dataset) ⇒ EagerGraphLoader
constructor
Initialize all of the data structures used during loading.
-
#load(hashes) ⇒ Object
Return an array of primary model instances with the associations cache prepopulated for all model objects (both primary and associated).
Constructor Details
#initialize(dataset) ⇒ EagerGraphLoader
Initialize all of the data structures used during loading.
1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 |
# File 'lib/sequel/model/associations.rb', line 1719 def initialize(dataset) opts = dataset.opts eager_graph = opts[:eager_graph] @master = eager_graph[:master] requirements = eager_graph[:requirements] alias_map = @alias_map = eager_graph[:alias_association_name_map] type_map = @type_map = eager_graph[:alias_association_type_map] reciprocal_map = @reciprocal_map = eager_graph[:reciprocals] @unique = eager_graph[:cartesian_product_number] > 1 # Make dependency map hash out of requirements array for each association. # This builds a tree of dependencies that will be used for recursion # to ensure that all parts of the object graph are loaded into the # appropriate subordinate association. @dependency_map = {} # Sort the associations by requirements length, so that # requirements are added to the dependency hash before their # dependencies. requirements.sort_by{|a| a[1].length}.each do |ta, deps| if deps.empty? dependency_map[ta] = {} else deps = deps.dup hash = dependency_map[deps.shift] deps.each do |dep| hash = hash[dep] end hash[ta] = {} end end # This mapping is used to make sure that duplicate entries in the # result set are mapped to a single record. For example, using a # single one_to_many association with 10 associated records, # the main object column values appear in the object graph 10 times. # We map by primary key, if available, or by the object's entire values, # if not. The mapping must be per table, so create sub maps for each table # alias. records_map = {@master=>{}} alias_map.keys.each{|ta| records_map[ta] = {}} @records_map = records_map datasets = opts[:graph][:table_aliases].to_a.reject{|ta,ds| ds.nil?} column_aliases = opts[:graph_aliases] || opts[:graph][:column_aliases] primary_keys = {} column_maps = {} models = {} row_procs = {} datasets.each do |ta, ds| models[ta] = ds.model primary_keys[ta] = [] column_maps[ta] = {} row_procs[ta] = ds.row_proc end column_aliases.each do |col_alias, tc| ta, column = tc column_maps[ta][col_alias] = column end column_maps.each do |ta, h| pk = models[ta].primary_key if pk.is_a?(Array) primary_keys[ta] = [] h.select{|ca, c| primary_keys[ta] << ca if pk.include?(c)} else h.select{|ca, c| primary_keys[ta] = ca if pk == c} end end @column_maps = column_maps @primary_keys = primary_keys @row_procs = row_procs # For performance, create two special maps for the master table, # so you can skip a hash lookup. @master_column_map = column_maps[master] @master_primary_keys = primary_keys[master] # Add a special hash mapping table alias symbols to 5 element arrays that just # contain the data in other data structures for that table alias. This is # used for performance, to get all values in one hash lookup instead of # separate hash lookups for each data structure. ta_map = {} alias_map.keys.each do |ta| ta_map[ta] = [records_map[ta], row_procs[ta], alias_map[ta], type_map[ta], reciprocal_map[ta]] end @ta_map = ta_map end |
Instance Attribute Details
#alias_map ⇒ Object (readonly)
Hash with table alias symbol keys and association name values
1686 1687 1688 |
# File 'lib/sequel/model/associations.rb', line 1686 def alias_map @alias_map end |
#column_maps ⇒ Object (readonly)
Hash with table alias symbol keys and subhash values mapping column_alias symbols to the symbol of the real name of the column
1690 1691 1692 |
# File 'lib/sequel/model/associations.rb', line 1690 def column_maps @column_maps end |
#dependency_map ⇒ Object (readonly)
Recursive hash with table alias symbol keys mapping to hashes with dependent table alias symbol keys.
1693 1694 1695 |
# File 'lib/sequel/model/associations.rb', line 1693 def dependency_map @dependency_map end |
#master ⇒ Object (readonly)
The table alias symbol for the primary model
1696 1697 1698 |
# File 'lib/sequel/model/associations.rb', line 1696 def master @master end |
#primary_keys ⇒ Object (readonly)
Hash with table alias symbol keys and primary key symbol values (or arrays of primary key symbols for composite key tables)
1700 1701 1702 |
# File 'lib/sequel/model/associations.rb', line 1700 def primary_keys @primary_keys end |
#reciprocal_map ⇒ Object (readonly)
Hash with table alias symbol keys and reciprocal association symbol values, used for setting reciprocals for one_to_many associations.
1704 1705 1706 |
# File 'lib/sequel/model/associations.rb', line 1704 def reciprocal_map @reciprocal_map end |
#records_map ⇒ Object (readonly)
Hash with table alias symbol keys and subhash values mapping primary key symbols (or array of symbols) to model instances. Used so that only a single model instance is created for each object.
1708 1709 1710 |
# File 'lib/sequel/model/associations.rb', line 1708 def records_map @records_map end |
#row_procs ⇒ Object (readonly)
Hash with table alias symbol keys and callable values used to create model instances
1711 1712 1713 |
# File 'lib/sequel/model/associations.rb', line 1711 def row_procs @row_procs end |
#type_map ⇒ Object (readonly)
Hash with table alias symbol keys and true/false values, where true means the association represented by the table alias uses an array of values instead of a single value (i.e. true => *_many, false => *_to_one).
1716 1717 1718 |
# File 'lib/sequel/model/associations.rb', line 1716 def type_map @type_map end |
Instance Method Details
#load(hashes) ⇒ Object
Return an array of primary model instances with the associations cache prepopulated for all model objects (both primary and associated).
1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 |
# File 'lib/sequel/model/associations.rb', line 1808 def load(hashes) master = master() # Assign to local variables for speed increase rp = row_procs[master] rm = records_map[master] dm = dependency_map # This will hold the final record set that we will be replacing the object graph with. records = [] hashes.each do |h| unless key = master_pk(h) key = hkey(master_hfor(h)) end unless primary_record = rm[key] primary_record = rm[key] = rp.call(master_hfor(h)) # Only add it to the list of records to return if it is a new record records.push(primary_record) end # Build all associations for the current object and it's dependencies _load(dm, primary_record, h) end # Remove duplicate records from all associations if this graph could possibly be a cartesian product unique(records, dm) if @unique records end |