Class: EntityStore::MongoEntityStore

Inherits:
Object
  • Object
show all
Includes:
Logging, Mongo
Defined in:
lib/mongo_entity_store/mongo_entity_store.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.connect_timeout=(value) ⇒ Object (writeonly)

Sets the attribute connect_timeout

Parameters:

  • value

    the value to set the attribute connect_timeout to.



12
13
14
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 12

def connect_timeout=(value)
  @connect_timeout = value
end

.connection_profileObject

Returns the value of attribute connection_profile.



11
12
13
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 11

def connection_profile
  @connection_profile
end

Class Method Details

.connectionObject



14
15
16
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 14

def connection
  @_connection ||= Mongo::MongoClient.from_uri(MongoEntityStore.connection_profile, :connect_timeout => EntityStore::Config.connect_timeout, :refresh_mode => :sync)
end

.databaseObject



18
19
20
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 18

def database
  @_database ||= MongoEntityStore.connection_profile.split('/').last.split('?').first
end

Instance Method Details

#add_entity(entity, id = BSON::ObjectId.new) ⇒ Object



47
48
49
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 47

def add_entity(entity, id = BSON::ObjectId.new)
  entities.insert('_id' => id, '_type' => entity.class.name, 'version' => entity.version).to_s
end

#add_events(items) ⇒ Object



95
96
97
98
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 95

def add_events(items)
  events_with_id = items.map { |e| [ BSON::ObjectId.new, e ] }
  add_events_with_ids(events_with_id)
end

#add_events_with_ids(event_id_map) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 100

def add_events_with_ids(event_id_map)
  docs = event_id_map.map do |id, event|
    {
      '_id' => id,
      '_type' => event.class.name,
      '_entity_id' => BSON::ObjectId.from_string(event.entity_id)
    }.merge(event.attributes)
  end

  events.insert(docs)
end

#clearObject



35
36
37
38
39
40
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 35

def clear
  entities.drop
  @entities_collection = nil
  events.drop
  @events_collection = nil
end

#clear_entity_events(id, excluded_types) ⇒ Object



88
89
90
91
92
93
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 88

def clear_entity_events(id, excluded_types)
  events.remove({
    '_entity_id' => BSON::ObjectId.from_string(id),
    '_type' => { '$nin' => excluded_types },
  })
end

#ensure_indexesObject



42
43
44
45
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 42

def ensure_indexes
  events.ensure_index([['_entity_id', Mongo::ASCENDING], ['_id', Mongo::ASCENDING]])
  events.ensure_index([['_entity_id', Mongo::ASCENDING], ['entity_version', Mongo::ASCENDING], ['_id', Mongo::ASCENDING]])
end

#entitiesObject



27
28
29
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 27

def entities
  @entities_collection ||= open['entities']
end

#eventsObject



31
32
33
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 31

def events
  @events_collection ||= open['entity_events']
end

#get_entities(ids, options = {}) ⇒ Object

Public: loads the entity from the store, including any available snapshots then loads the events to complete the state

ids - Array of Strings representation of BSON::ObjectId options - Hash of options (default: {})

:raise_exception - Boolean (default: true)

Returns an array of entities



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 120

def get_entities(ids, options={})

  object_ids = ids.map do |id|
    begin
      BSON::ObjectId.from_string(id)
    rescue BSON::InvalidObjectId
      raise NotFound.new(id) if options.fetch(:raise_exception, true)
      nil
    end
  end

  entities.find('_id' => { '$in' => object_ids }).map do |attrs|
    begin
      entity_type = EntityStore::Config.load_type(attrs['_type'])

      # Check if there is a snapshot key in use
      if entity_type.respond_to? :entity_store_snapshot_key
        active_key = entity_type.entity_store_snapshot_key
        # Discard the snapshot if the keys don't match
        attrs.delete('snapshot') unless active_key == attrs['snapshot_key']
      end

      entity = entity_type.new(attrs['snapshot'] || {'id' => attrs['_id'].to_s })
    rescue => e
      log_error "Error loading type #{attrs['_type']}", e
      raise
    end

    entity
  end

end

#get_events(criteria) ⇒ Object

Public: get events for an array of criteria objects

because each entity could have a different reference
version this allows optional criteria to be specifed

criteria - Hash :id mandatory, :since_version optional

Examples

get_events_for_criteria([ { id: “23232323”}, { id: “2398429834”, since_version: 4 } ] )

Returns Hash with id as key and Array of Event instances as value



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 165

def get_events(criteria)
  return {} if criteria.empty?

  query_items = criteria.map do |item|
    raise ArgumentError.new(":id missing from criteria") unless item[:id]
    item_query = { '_entity_id' => BSON::ObjectId.from_string(item[:id]) }
    item_query['entity_version'] = { '$gt' => item[:since_version] } if item[:since_version]
    item_query
  end

  query = { '$or' => query_items }

  result = Hash[ criteria.map { |item| [ item[:id], [] ] } ]

  events.find(query).each do |attrs|
    result[attrs['_entity_id'].to_s] << attrs
  end

  result.each do |id, events|
    # Have to do the sort client side as otherwise the query will not use
    # indexes (http://docs.mongodb.org/manual/reference/operator/query/or/#or-and-sort-operations)
    events.sort_by! { |attrs| [attrs['entity_version'], attrs['_id'].to_s] }

    # Convert the attributes into event objects
    events.map! do |attrs|
      begin
        EntityStore::Config.load_type(attrs['_type']).new(attrs)
      rescue => e
        log_error "Error loading type #{attrs['_type']}", e
        nil
      end
    end

    events.compact!
  end

  result
end

#openObject



23
24
25
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 23

def open
  MongoEntityStore.connection.db(MongoEntityStore.database)
end

#remove_entity_snapshot(id) ⇒ Object

Public - remove the snapshot for an entity



74
75
76
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 74

def remove_entity_snapshot(id)
  entities.update({'_id' => BSON::ObjectId.from_string(id)}, { '$unset' => { 'snapshot' => 1}})
end

#remove_snapshots(type = nil) ⇒ Object

Public: remove all snapshots

type - String optional class name for the entity



82
83
84
85
86
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 82

def remove_snapshots type=nil
  query = {}
  query['_type'] = type if type
  entities.update(query, { '$unset' => { 'snapshot' => 1 } }, { multi: true })
end

#save_entity(entity) ⇒ Object



51
52
53
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 51

def save_entity(entity)
  entities.update({'_id' => BSON::ObjectId.from_string(entity.id)}, { '$set' => { 'version' => entity.version } })
end

#snapshot_entity(entity) ⇒ Object

Public: create a snapshot of the entity and store in the entities collection



57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/mongo_entity_store/mongo_entity_store.rb', line 57

def snapshot_entity(entity)
  query = {'_id' => BSON::ObjectId.from_string(entity.id)}
  updates = { '$set' => { 'snapshot' => entity.attributes } }

  if entity.class.respond_to? :entity_store_snapshot_key
    # If there is a snapshot key, store it too
    updates['$set']['snapshot_key'] = entity.class.entity_store_snapshot_key
  else
    # Otherwise, make sure there isn't one set
    updates['$unset'] = { 'snapshot_key' => '' }
  end

  entities.update(query, updates, { :upsert => true} )
end