Class: DatastaxRails::DynamicModel
- Inherits:
-
WideStorageModel
- Object
- Base
- WideStorageModel
- DatastaxRails::DynamicModel
- Defined in:
- lib/datastax_rails/dynamic_model.rb
Overview
An extension to Wide Storage Models that let you index any arbitrary field that you want (given certain naming conventions).
Try to keep the group_by as sort as possible since it will get stored with every attribute. Static attributes are only supported if they are included on every dynamic model that uses the same column family.
Dynamic models have the following attributes:
-
strings
-
texts
-
booleans
-
dates
-
timestamps
-
integers
-
floats
-
uuids
Each of these is a map that let’s you store key/value pairs where the key is always a String and the value is a type that matches what would be stored in a static attribute of the same time. Everything will get typecasted, so you can safely store strings in it in all the same cases that you store strings in normal attributes.
The advantage here is that you don’t have to pre-define your schema ahead of time. The keys of any attributes added to this collection become fields in your Solr document.
NOTE: due to the way fields dynamically map between Solr and Cassandra, the field name in Solr will have a prefix prepended to it. With the exception of timestamps, it is simply the first letter of the type followed by an underscore (_). So s_ for strings. Timestamp has a ts_ prefix to differentiate it from texts.
class Item < DatastaxRails::DynamicModel
self.grouping = 'item'
end
class CoreMetadata < DatastaxRails::DynamicModel
self.grouping = 'core'
end
class TeamMetadata < DatastaxRails::DynamicModel
self.grouping = 'team'
end
item = Item.create(strings: {title: "Title"})
CoreMetadata.create(id: item.id, strings: {author: 'John'}, dates: {published_on: Date.today})
TeamMetadata.create(id: item.id, booleans: {reviewed: true})
CoreMetadata.where(s_author: 'John') #=> Finds the CoreMetadata record
Item.fulltext("Title") #=> Finds the Item record
Item.fulltext("John") #=> Doesn't find a record, but...
Item.fulltext("{!join from=id to=id}John") #=> Does find the record by doing a Solr join across the entire row
NOTE that the mapping of key names is happening automatically when you insert something into the collection so:
Item.first.strings #=> {s_title: "Title"}
If you would like to still define known attributes ahead of time, you can still do so:
class TeamMetadata < DatastaxRails::DynamicModel
self.grouping = 'team'
string :name
end
TeamMetadata.new(name: 'John').name #=> 'John'
TeamMetadata.new(name: 'John').strings #=> {'s_name' => 'John'}
Getters and setters are automatically created to map to the attribute stored in the hash. In addition, there is a helper method to map column names to the field name in solr to assist with search.
Constant Summary collapse
- PREFIXES =
{ string: :s_, text: :t_, boolean: :b_, date: :d_, timestamp: :ts_, integer: :i_, float: :f_, uuid: :u_ }.with_indifferent_access
Constants included from Callbacks
Instance Attribute Summary
Attributes inherited from Base
#attributes, #key, #loaded_attributes
Attributes included from AutosaveAssociation
#destroyed_by_association, #marked_for_destruction
Attributes included from Associations
Class Method Summary collapse
- ._attribute ⇒ Object
- .attribute(name, options) ⇒ Object
- .grouping=(group) ⇒ Object
- .inherited(child) ⇒ Object
- .solr_field_name(attr, type = nil) ⇒ Object
Instance Method Summary collapse
- #read_attribute(attr_name) ⇒ Object
- #solr_field_name(attr, type = nil) ⇒ Object
- #write_attribute(attr_name, val) ⇒ Object
Methods inherited from WideStorageModel
Methods inherited from Base
#==, attribute_names, #attribute_names, base_class, #column_names, columns, default_page_size, #eql?, find_by_id, #freeze, #frozen?, #hash, #init_changed_attributes, #init_internals, #init_with, #initialize, inspect, logger, models, payload_model?, search_ids, #to_param, #valid_consistency?, valid_consistency?, wide_storage_model?
Methods included from SolrRepair
Methods included from Serialization
#as_json, #serializable_hash, #to_xml
Methods included from Timestamps
Methods included from Scoping
#populate_with_current_scope_attributes
Methods included from AutosaveAssociation
#changed_for_autosave?, #mark_for_destruction, #reload
Methods included from Associations
#association, #clear_association_cache
Methods included from Callbacks
Methods included from Validations
Methods included from AttributeMethods
#attribute_exists?, #column_for_attribute, #method_missing, #respond_to?
Methods included from AttributeAssignment
Methods included from Batches
#find_each, #find_each_with_index, #find_in_batches
Methods included from FinderMethods
#find, #find_by, #find_by!, #first, #first!, #last, #last!
Methods included from Persistence
#destroy, #persisted?, #reload, #save, #save!, #toggle, #toggle!, #update_attribute, #update_attributes, #update_attributes!
Constructor Details
This class inherits a constructor from DatastaxRails::Base
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class DatastaxRails::AttributeMethods
Class Method Details
._attribute ⇒ Object
94 |
# File 'lib/datastax_rails/dynamic_model.rb', line 94 alias_method :_attribute, :attribute |
.attribute(name, options) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/datastax_rails/dynamic_model.rb', line 96 def attribute(name, ) .symbolize_keys! unless [:map, :list, :set].include?([:type].to_sym) # Only type supported for now .assert_valid_keys(:type) unless PREFIXES.key?([:type]) fail(ArgumentError, "Invalid type specified for dynamic attribute: '#{name}: #{[:type]}'") end virtual_attributes[name.to_s] = PREFIXES[[:type]].to_s + name.to_s end super end |
.grouping=(group) ⇒ Object
88 89 90 91 92 |
# File 'lib/datastax_rails/dynamic_model.rb', line 88 def grouping=(group) self.group_by_attribute = group attribute_definitions['group'].default = group default_scope -> { where('group' => group) } end |
.inherited(child) ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/datastax_rails/dynamic_model.rb', line 109 def inherited(child) super child.virtual_attributes = child.virtual_attributes.nil? ? {}.with_indifferent_access : child.virtual_attributes.dup child.column_family = 'dynamic_model' child.primary_key = 'id' child.cluster_by = 'group' child._attribute :id, type: :uuid child._attribute :group, type: :string PREFIXES.each do |k, v| child._attribute v, holds: k.to_sym, type: :map child.instance_eval { alias_attribute k.to_s.pluralize, v } end end |
.solr_field_name(attr, type = nil) ⇒ Object
124 125 126 127 128 129 |
# File 'lib/datastax_rails/dynamic_model.rb', line 124 def solr_field_name(attr, type = nil) type ||= attribute_definitions[attr].try(:type) fail(UnknownAttributeError, 'Collections cannot be mapped') if [:map, :list, :set].include?(type) fail(UnknownAttributeError, "Unknown attribute: #{attr}. You must specify a type.") unless type PREFIXES[type].to_s + attr.to_s end |
Instance Method Details
#read_attribute(attr_name) ⇒ Object
141 142 143 144 145 146 147 148 |
# File 'lib/datastax_rails/dynamic_model.rb', line 141 def read_attribute(attr_name) if virtual_attributes.include?(attr_name.to_s) type = self.class.attribute_definitions[attr_name].type send(PREFIXES[type])[attr_name] else super end end |
#solr_field_name(attr, type = nil) ⇒ Object
150 151 152 |
# File 'lib/datastax_rails/dynamic_model.rb', line 150 def solr_field_name(attr, type = nil) self.class.solr_field_name(attr, type) end |
#write_attribute(attr_name, val) ⇒ Object
132 133 134 135 136 137 138 139 |
# File 'lib/datastax_rails/dynamic_model.rb', line 132 def write_attribute(attr_name, val) if virtual_attributes.include?(attr_name.to_s) type = self.class.attribute_definitions[attr_name].type send(PREFIXES[type])[attr_name] = val else super end end |