Class: Vanity::Adapters::MongodbAdapter

Inherits:
AbstractAdapter show all
Defined in:
lib/vanity/adapters/mongodb_adapter.rb

Overview

MongoDB adapter.

Since:

  • 1.4.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ MongodbAdapter

rubocop:todo Lint/MissingSuper

Since:

  • 1.4.0


20
21
22
23
24
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 20

def initialize(options) # rubocop:todo Lint/MissingSuper
  @options = options.clone
  @options[:database] ||= (@options[:path] && @options[:path].split("/")[1]) || "vanity"
  connect!
end

Instance Attribute Details

#mongoObject (readonly)

Since:

  • 1.4.0


18
19
20
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 18

def mongo
  @mongo
end

Instance Method Details

#ab_add_conversion(experiment, alternative, identity, count = 1, implicit = false) ⇒ Object

Since:

  • 1.4.0


220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 220

def ab_add_conversion(experiment, alternative, identity, count = 1, implicit = false)
  if implicit
    @participants.find(experiment: experiment, identity: identity).find_one_and_replace(
      {
        "$push" => { seen: alternative },
      },
      upsert: true
    )
  else
    participating = @participants.find(experiment: experiment, identity: identity, seen: alternative).limit(1).first
  end

  if implicit || participating
    @participants.find(experiment: experiment, identity: identity).find_one_and_replace(
      {
        "$push" => { converted: alternative },
      },
      upsert: true
    )
  end

  @experiments.find(_id: experiment).find_one_and_replace(
    {
      "$inc" => { "conversions.#{alternative}" => count },
    },
    upsert: true
  )
end

#ab_add_participant(experiment, alternative, identity) ⇒ Object

Since:

  • 1.4.0


197
198
199
200
201
202
203
204
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 197

def ab_add_participant(experiment, alternative, identity)
  @participants.find(experiment: experiment, identity: identity).find_one_and_replace(
    {
      "$push" => { seen: alternative },
    },
    upsert: true
  )
end

#ab_assigned(experiment, identity) ⇒ Object

Returns the participant's seen alternative in this experiment, if it exists

Since:

  • 1.4.0


215
216
217
218
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 215

def ab_assigned(experiment, identity)
  participant = @participants.find(experiment: experiment, identity: identity).limit(1).projection(seen: 1).first
  participant && participant["seen"].first
end

#ab_counts(experiment, alternative) ⇒ Object

Since:

  • 1.4.0


166
167
168
169
170
171
172
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 166

def ab_counts(experiment, alternative)
  record = @experiments.find(_id: experiment).limit(1).projection(conversions: 1).first
  conversions = record && record["conversions"]
  { participants: @participants.find({ experiment: experiment, seen: alternative }).count,
    converted: @participants.find({ experiment: experiment, converted: alternative }).count,
    conversions: (conversions && conversions[alternative.to_s]) || 0 }
end

#ab_get_outcome(experiment) ⇒ Object

Since:

  • 1.4.0


249
250
251
252
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 249

def ab_get_outcome(experiment)
  experiment = @experiments.find(_id: experiment).limit(1).projection(outcome: 1).first
  experiment && experiment["outcome"]
end

#ab_not_showing(experiment, identity) ⇒ Object

Since:

  • 1.4.0


188
189
190
191
192
193
194
195
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 188

def ab_not_showing(experiment, identity)
  @participants.find(experiment: experiment, identity: identity).find_one_and_replace(
    {
      "$unset" => { show: "" },
    },
    upsert: true
  )
end

#ab_seen(experiment, identity, alternative_or_id) ⇒ Object

Determines if a participant already has seen this alternative in this experiment.

Since:

  • 1.4.0


207
208
209
210
211
212
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 207

def ab_seen(experiment, identity, alternative_or_id)
  with_ab_seen_deprecation(experiment, identity, alternative_or_id) do |expt, ident, alt_id|
    participant = @participants.find(experiment: expt, identity: ident).limit(1).projection(seen: 1).first
    participant && participant["seen"].first == alt_id
  end
end

#ab_set_outcome(experiment, alternative = 0) ⇒ Object

Since:

  • 1.4.0


254
255
256
257
258
259
260
261
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 254

def ab_set_outcome(experiment, alternative = 0)
  @experiments.find(_id: experiment).find_one_and_replace(
    {
      "$set" => { outcome: alternative },
    },
    upsert: true
  )
end

#ab_show(experiment, identity, alternative) ⇒ Object

Since:

  • 1.4.0


174
175
176
177
178
179
180
181
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 174

def ab_show(experiment, identity, alternative)
  @participants.find(experiment: experiment, identity: identity).find_one_and_replace(
    {
      "$set" => { show: alternative },
    },
    upsert: true
  )
end

#ab_showing(experiment, identity) ⇒ Object

Since:

  • 1.4.0


183
184
185
186
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 183

def ab_showing(experiment, identity)
  participant = @participants.find(experiment: experiment, identity: identity).limit(1).projection(show: 1).first
  participant && participant["show"]
end

#active?Boolean

Returns:

  • (Boolean)

Since:

  • 1.4.0


26
27
28
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 26

def active?
  !!@mongo
end

#connect!Object

Since:

  • 1.4.0


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 47

def connect!
  Mongo::Logger.logger = Vanity.logger
  setup_connection(@options)

  @metrics = @mongo["vanity.metrics"]
  @metrics.create unless @mongo.database.collection_names.include?("vanity.metrics")
  @experiments = @mongo["vanity.experiments"]
  @experiments.create unless @mongo.database.collection_names.include?("vanity.experiments")
  @participants = @mongo["vanity.participants"]
  @participants.create unless @mongo.database.collection_names.include?("vanity.participants")
  @participants.indexes.create_many(
    { key: { experiment: 1, identity: 1 }, unique: true },
    { key: { experiment: 1, seen: 1 } },
    { key: { experiment: 1, converted: 1 } }
  )

  @mongo
end

#destroy_experiment(experiment) ⇒ Object

Since:

  • 1.4.0


263
264
265
266
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 263

def destroy_experiment(experiment)
  @experiments.find(_id: experiment).delete_one
  @participants.find(experiment: experiment).delete_many
end

#destroy_metric(metric) ⇒ Object

Since:

  • 1.4.0


104
105
106
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 104

def destroy_metric(metric)
  @metrics.find(_id: metric).delete_one
end

#disconnect!Object

Since:

  • 1.4.0


30
31
32
33
34
35
36
37
38
39
40
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 30

def disconnect!
  if @mongo
    begin
      @mongo.close
    rescue StandardError
      nil
    end
  end
  @metrics, @experiments = nil
  @mongo = nil
end

#experiment_persisted?(experiment) ⇒ Boolean

– Experiments –

Returns:

  • (Boolean)

Since:

  • 1.4.0


110
111
112
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 110

def experiment_persisted?(experiment)
  !!@experiments.find(_id: experiment).limit(1).first
end

#flushdbObject

Since:

  • 1.4.0


71
72
73
74
75
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 71

def flushdb
  @metrics.drop
  @experiments.drop
  @participants.drop
end

#get_experiment_completed_at(experiment) ⇒ Object

Since:

  • 1.4.0


139
140
141
142
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 139

def get_experiment_completed_at(experiment)
  record = @experiments.find(_id: experiment).limit(1).projection(completed_at: 1).first
  record && record["completed_at"]
end

#get_experiment_created_at(experiment) ⇒ Object

Since:

  • 1.4.0


124
125
126
127
128
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 124

def get_experiment_created_at(experiment)
  record = @experiments.find(_id: experiment).limit(1).projection(created_at: 1).first
  record && record["created_at"]
  # Returns nil if either the record or the field doesn't exist
end

#get_metric_last_update_at(metric) ⇒ Object

– Metrics –

Since:

  • 1.4.0


79
80
81
82
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 79

def get_metric_last_update_at(metric)
  record = @metrics.find(_id: metric).limit(1).first
  record && record["last_update_at"]
end

#is_experiment_completed?(experiment) ⇒ Boolean

rubocop:todo Naming/PredicateName

Returns:

  • (Boolean)

Since:

  • 1.4.0


144
145
146
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 144

def is_experiment_completed?(experiment) # rubocop:todo Naming/PredicateName
  !!@experiments.find(_id: experiment, completed_at: { "$exists" => true }).limit(1).first
end

#is_experiment_enabled?(experiment) ⇒ Boolean

rubocop:todo Naming/PredicateName

Returns:

  • (Boolean)

Since:

  • 1.4.0


157
158
159
160
161
162
163
164
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 157

def is_experiment_enabled?(experiment) # rubocop:todo Naming/PredicateName
  record = @experiments.find(_id: experiment).limit(1).projection(enabled: 1).first
  if Vanity.configuration.experiments_start_enabled
    record.nil? || record["enabled"] != false
  else
    record && record["enabled"] == true
  end
end

#metric_track(metric, timestamp, _identity, values) ⇒ Object

Since:

  • 1.4.0


84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 84

def metric_track(metric, timestamp, _identity, values)
  inc = {}
  values.each_with_index do |v, i|
    inc["data.#{timestamp.to_date}.#{i}"] = v
  end
  @metrics.find(_id: metric).find_one_and_replace(
    {
      "$inc" => inc,
      "$set" => { last_update_at: Time.now },
    },
    upsert: true
  )
end

#metric_values(metric, from, to) ⇒ Object

Since:

  • 1.4.0


98
99
100
101
102
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 98

def metric_values(metric, from, to)
  record = @metrics.find(_id: metric).limit(1).first
  data = (record && record["data"]) || {}
  (from.to_date..to.to_date).map { |date| (data[date.to_s] || {}).values }
end

#reconnect!Object

Since:

  • 1.4.0


42
43
44
45
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 42

def reconnect!
  disconnect!
  connect!
end

#set_experiment_completed_at(experiment, time) ⇒ Object

Since:

  • 1.4.0


130
131
132
133
134
135
136
137
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 130

def set_experiment_completed_at(experiment, time)
  @experiments.find(_id: experiment).find_one_and_replace(
    {
      "$set" => { completed_at: time },
    },
    upsert: true
  )
end

#set_experiment_created_at(experiment, time) ⇒ Object

Since:

  • 1.4.0


114
115
116
117
118
119
120
121
122
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 114

def set_experiment_created_at(experiment, time)
  # @experiments.insert_one(:_id=>experiment, :created_at=>time)
  @experiments.find(_id: experiment).find_one_and_replace(
    {
      "$setOnInsert" => { created_at: time },
    },
    upsert: true
  )
end

#set_experiment_enabled(experiment, enabled) ⇒ Object

Since:

  • 1.4.0


148
149
150
151
152
153
154
155
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 148

def set_experiment_enabled(experiment, enabled)
  @experiments.find(_id: experiment).find_one_and_replace(
    {
      "$set" => { enabled: enabled },
    },
    upsert: true
  )
end

#to_sObject

Since:

  • 1.4.0


66
67
68
69
# File 'lib/vanity/adapters/mongodb_adapter.rb', line 66

def to_s
  userinfo = @options.values_at(:username, :password).join(":") if @options[:username]
  URI::Generic.build(scheme: "mongodb", userinfo: userinfo, host: (@mongo.host || @options[:host]), port: (@mongo.port || @options[:port]), path: "/#{@options[:database]}").to_s
end