Class: Trifle::Stats::Driver::Mongo

Inherits:
Object
  • Object
show all
Includes:
Mixins::Packer
Defined in:
lib/trifle/stats/driver/mongo.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixins::Packer

included

Constructor Details

#initialize(client, collection_name: 'trifle_stats', joined_identifier: true, expire_after: nil) ⇒ Mongo

Returns a new instance of Mongo.



12
13
14
15
16
17
18
# File 'lib/trifle/stats/driver/mongo.rb', line 12

def initialize(client, collection_name: 'trifle_stats', joined_identifier: true, expire_after: nil)
  @client = client
  @collection_name = collection_name
  @joined_identifier = joined_identifier
  @expire_after = expire_after
  @separator = '::'
end

Instance Attribute Details

#clientObject

Returns the value of attribute client.



10
11
12
# File 'lib/trifle/stats/driver/mongo.rb', line 10

def client
  @client
end

#collection_nameObject

Returns the value of attribute collection_name.



10
11
12
# File 'lib/trifle/stats/driver/mongo.rb', line 10

def collection_name
  @collection_name
end

Class Method Details

.setup!(client, collection_name: 'trifle_stats', joined_identifier: true, expire_after: nil) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/trifle/stats/driver/mongo.rb', line 20

def self.setup!(client, collection_name: 'trifle_stats', joined_identifier: true, expire_after: nil)
  collection = client[collection_name]
  collection.create
  if joined_identifier
    collection.indexes.create_one({ key: 1 }, unique: true)
  else
    collection.indexes.create_one({ key: 1, range: 1, at: -1 }, unique: true)
  end
  collection.indexes.create_one({ expire_at: 1 }, expire_after_seconds: 0) if expire_after
end

Instance Method Details

#descriptionObject



31
32
33
# File 'lib/trifle/stats/driver/mongo.rb', line 31

def description
  "#{self.class.name}(#{@joined_identifier ? 'J' : 'S'})"
end

#get(keys:) ⇒ Object

rubocop:disable Metrics/AbcSize



90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/trifle/stats/driver/mongo.rb', line 90

def get(keys:) # rubocop:disable Metrics/AbcSize
  combinations = keys.map { |key| key.identifier(separator) }
  data = collection.find('$or' => combinations)
  map = data.inject({}) do |o, d|
    o.merge(
      Nocturnal::Key.new(
        key: d['key'], range: d['range'], at: d['at']
      ).identifier(separator) => d['data']
    )
  end

  combinations.map { |combination| map[combination] || {} }
end

#inc(keys:, **values) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/trifle/stats/driver/mongo.rb', line 39

def inc(keys:, **values)
  data = self.class.pack(hash: { data: values })

  operations = keys.map do |key|
    filter = key.identifier(separator)
    expire_at = @expire_after ? key.at + @expire_after : nil

    upsert_operation('$inc', filter: filter, data: data, expire_at: expire_at)
  end

  collection.bulk_write(operations)
end

#ping(key:, **values) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/trifle/stats/driver/mongo.rb', line 65

def ping(key:, **values)
  data = self.class.pack(hash: { data: values, at: key.at })
  identifier = key.identifier(separator)
  expire_at = @expire_after ? key.at + @expire_after : nil

  operations = [
    upsert_operation('$set', filter: identifier.slice(:key), data: data, expire_at: expire_at)
  ]

  collection.bulk_write(operations)
end

#scan(key:) ⇒ Object



104
105
106
107
108
109
110
111
112
113
# File 'lib/trifle/stats/driver/mongo.rb', line 104

def scan(key:)
  return [] if @joined_identifier

  data = collection.find(
    **key.identifier(separator)
  ).sort(at: -1).first # rubocop:disable Style/RedundantSort
  return [] if data.nil?

  [data['at'], data['data']]
end

#separatorObject



35
36
37
# File 'lib/trifle/stats/driver/mongo.rb', line 35

def separator
  @joined_identifier ? @separator : nil
end

#set(keys:, **values) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/trifle/stats/driver/mongo.rb', line 52

def set(keys:, **values)
  data = self.class.pack(hash: { data: values })

  operations = keys.map do |key|
    filter = key.identifier(separator)
    expire_at = @expire_after ? key.at + @expire_after : nil

    upsert_operation('$set', filter: filter, data: data, expire_at: expire_at)
  end

  collection.bulk_write(operations)
end

#upsert_operation(operation, filter:, data:, expire_at: nil) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/trifle/stats/driver/mongo.rb', line 77

def upsert_operation(operation, filter:, data:, expire_at: nil)
  # Merge if $set and $set
  update_data = operation == '$set' && expire_at ? data.merge(expire_at: expire_at) : data

  # Add if $inc and $set
  update = {
    operation => update_data,
    **(operation != '$set' && expire_at ? { '$set' => { expire_at: expire_at } } : {})
  }

  { update_many: { filter: filter, update: update, upsert: true } }
end