better_auth-mongo-adapter 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8422b43a0fc6310519286bca03295aecb91752ae5c4cd5997ff5be64486af7c9
4
- data.tar.gz: ed65ca011f7f4a5913ae03830c049b8fcc023200c47ad9da125e55f6569272ba
3
+ metadata.gz: 86afd33544ccb8e9fff5ccfa4e055cd31007086648c7985f1e9b64f40176f68e
4
+ data.tar.gz: 953a82389a1bbc913d702396fe0c4a66abcf79f042d4a5fb6bcd36eecaf233b3
5
5
  SHA512:
6
- metadata.gz: 285006c97e41014ba65eb450e520bd9ac82848a0d796894ba526f1427a605808d51e25d174cd35d4f11884e235b4cc9465017a91c874b6aed5b6e45b41c8550a
7
- data.tar.gz: 16029924074e406bb142a50936b4b77a1a90367c5aaf8a390ecfb8723f051a1e2c98c770bea4bab1daa7784c7a9763946c46b5a55c9fc3d5a5620dfc5e830d16
6
+ metadata.gz: c67b4588a64b8fbb648ee5ec5fe029a67a6cd56c8c7ef35a48aacad33abecdff31f91eef0c2d110295c622cd877cbdb783a6583337c6bad0ce77985c2bdae34b
7
+ data.tar.gz: 86ab56e50db549d6ad11e28b06282376581651ecbdc540f15c5e2c114fab2a55ae8c21c9a7b11178826b78d9edce7a69875459c8be77a096dafec831405e6998
data/CHANGELOG.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - Deprecated this package in favor of `better_auth-mongodb`.
6
+ - Kept `require "better_auth/mongo_adapter"` as a compatibility entrypoint.
7
+
5
8
  ## 0.7.0 - 2026-05-05
6
9
 
7
10
  - Added explicit `ensure_indexes!` setup helper for Mongo indexes derived from Better Auth schema metadata.
data/README.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # better_auth-mongo-adapter
2
2
 
3
- MongoDB database adapter package for Better Auth Ruby.
3
+ Deprecated compatibility package for Better Auth Ruby MongoDB support.
4
+
5
+ New applications should use `better_auth-mongodb`:
6
+
7
+ ```ruby
8
+ gem "better_auth-mongodb"
9
+ ```
10
+
11
+ ```ruby
12
+ require "better_auth/mongodb"
13
+ ```
14
+
15
+ This package remains available so existing applications that install
16
+ `better_auth-mongo-adapter` and require `better_auth/mongo_adapter` continue to
17
+ load the same adapter.
4
18
 
5
19
  ## Installation
6
20
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module BetterAuth
4
4
  module MongoAdapter
5
- VERSION = "0.7.0"
5
+ VERSION = "0.8.0"
6
6
  end
7
7
  end
@@ -1,679 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "better_auth"
4
- require "mongo"
5
- require "securerandom"
6
- require "time"
3
+ warn "The better_auth-mongo-adapter gem is deprecated; use better_auth-mongodb and require \"better_auth/mongodb\" instead.", uplevel: 1
7
4
 
8
- module BetterAuth
9
- module Adapters
10
- class MongoDB < Base
11
- class MongoAdapterError < Error
12
- attr_reader :code
13
-
14
- def initialize(code, message)
15
- @code = code
16
- super(message)
17
- end
18
- end
19
-
20
- attr_reader :database, :client, :use_plural
21
-
22
- def initialize(options = nil, database:, client: nil, transaction: nil, use_plural: false, session: nil)
23
- require "mongo" unless database
24
-
25
- super(options || Configuration.new(secret: Configuration::DEFAULT_SECRET, database: :memory))
26
- @database = database
27
- @client = client
28
- @transaction_enabled = transaction.nil? ? !client.nil? : !!transaction
29
- @use_plural = !!use_plural
30
- @session = session
31
- end
32
-
33
- def create(model:, data:, force_allow_id: false)
34
- model = model.to_s
35
- record = transform_input(model, data, "create", force_allow_id)
36
- document = to_document(model, record)
37
- collection_for(model).insert_one(document, session_options)
38
- from_document(model, document)
39
- end
40
-
41
- def find_one(model:, where: [], select: nil, join: nil)
42
- find_many(model: model, where: where, select: select, join: join, limit: 1).first
43
- end
44
-
45
- def find_many(model:, where: [], sort_by: nil, limit: nil, offset: nil, select: nil, join: nil)
46
- model = model.to_s
47
- pipeline = [{"$match" => mongo_filter(model, where || [])}]
48
- pipeline.concat(join_stages(model, join)) if join
49
- pipeline << {"$project" => projection_for(model, select, join)} if select && !select.empty?
50
- pipeline << {"$sort" => {sort_field(model, sort_by) => sort_direction(sort_by)}} if sort_by
51
- pipeline << {"$skip" => offset.to_i} if offset
52
- effective_limit = limit.nil? ? default_find_many_limit : limit.to_i
53
- pipeline << {"$limit" => effective_limit} if effective_limit.positive?
54
-
55
- collection_for(model)
56
- .aggregate(pipeline, session_options)
57
- .to_a
58
- .map { |document| from_document(model, stringify_document(document), join: join) }
59
- end
60
-
61
- def update(model:, where:, update:)
62
- model = model.to_s
63
- data = transform_input(model, update, "update", true)
64
- document = to_document(model, data)
65
- document.delete("_id")
66
- result = collection_for(model).find_one_and_update(
67
- mongo_filter(model, where || []),
68
- {"$set" => document},
69
- session_options.merge(return_document: :after)
70
- )
71
- result = unwrap_update_result(result)
72
- result ? from_document(model, stringify_document(result)) : nil
73
- end
74
-
75
- def update_many(model:, where:, update:)
76
- model = model.to_s
77
- data = transform_input(model, update, "update", true)
78
- document = to_document(model, data)
79
- document.delete("_id")
80
- result = collection_for(model).update_many(
81
- mongo_filter(model, where || []),
82
- {"$set" => document},
83
- session_options
84
- )
85
- result.respond_to?(:modified_count) ? result.modified_count : result.to_i
86
- end
87
-
88
- def delete(model:, where:)
89
- collection_for(model.to_s).delete_one(mongo_filter(model.to_s, where || []), session_options)
90
- nil
91
- end
92
-
93
- def delete_many(model:, where:)
94
- result = collection_for(model.to_s).delete_many(mongo_filter(model.to_s, where || []), session_options)
95
- result.respond_to?(:deleted_count) ? result.deleted_count : result.to_i
96
- end
97
-
98
- def count(model:, where: nil)
99
- pipeline = [
100
- {"$match" => mongo_filter(model.to_s, where || [])},
101
- {"$count" => "total"}
102
- ]
103
- row = collection_for(model.to_s).aggregate(pipeline, session_options).to_a.first
104
- return 0 unless row
105
-
106
- (row["total"] || row[:total] || 0).to_i
107
- end
108
-
109
- def ensure_indexes!
110
- Schema.auth_tables(options).flat_map do |model, table|
111
- table.fetch(:fields).filter_map do |field, attributes|
112
- next if field == "id"
113
- next unless attributes[:unique] || attributes[:index]
114
-
115
- collection = collection_for(model)
116
- key = storage_field(model, field)
117
- index_options = attributes[:unique] ? {unique: true} : {}
118
- collection.indexes.create_one({key => 1}, index_options)
119
- {
120
- collection: collection_name(model),
121
- field: field,
122
- keys: {key => 1},
123
- unique: attributes[:unique] == true
124
- }
125
- end
126
- end
127
- end
128
-
129
- def transaction
130
- return yield self unless client && @transaction_enabled && client.respond_to?(:start_session)
131
-
132
- session = client.start_session
133
- begin
134
- session.start_transaction
135
- adapter = self.class.new(options, database: database, client: client, transaction: @transaction_enabled, use_plural: use_plural, session: session)
136
- result = yield adapter
137
- session.commit_transaction
138
- result
139
- rescue
140
- session.abort_transaction
141
- raise
142
- ensure
143
- session.end_session
144
- end
145
- end
146
-
147
- private
148
-
149
- def transform_input(model, data, action, force_allow_id)
150
- fields = fields_for(model)
151
- input = stringify_keys(data)
152
- output = {}
153
-
154
- fields.each do |field, attributes|
155
- next if field == "id" && input.key?(field) && !force_allow_id
156
-
157
- value_provided = input.key?(field)
158
- value = input[field]
159
- if value_provided && attributes[:input] == false && value && !force_allow_id
160
- raise APIError.new("BAD_REQUEST", message: "#{field} is not allowed to be set")
161
- end
162
-
163
- if !value_provided && action == "create" && attributes.key?(:default_value)
164
- value = resolve_default(attributes[:default_value])
165
- value_provided = true
166
- elsif !value_provided && action == "update" && attributes[:on_update]
167
- value = resolve_default(attributes[:on_update])
168
- value_provided = true
169
- end
170
-
171
- if !value_provided && action == "create" && attributes[:required]
172
- raise APIError.new("BAD_REQUEST", message: "#{field} is required") unless field == "id"
173
- end
174
- output[field] = coerce_value(value, attributes) if value_provided
175
- end
176
-
177
- output["id"] = generated_id if action == "create" && !output.key?("id")
178
- output
179
- end
180
-
181
- def mongo_filter(model, where)
182
- clauses = Array(where)
183
- return {} if clauses.empty?
184
-
185
- conditions = clauses.map do |clause|
186
- connector = if fetch_key(clause, :connector).to_s.upcase == "OR"
187
- "OR"
188
- else
189
- "AND"
190
- end
191
- {condition: condition_for(model, clause), connector: connector}
192
- end
193
- return conditions.first.fetch(:condition) if conditions.one?
194
-
195
- result = {}
196
- and_conditions = conditions.select { |entry| entry.fetch(:connector) == "AND" }.map { |entry| entry.fetch(:condition) }
197
- or_conditions = conditions.select { |entry| entry.fetch(:connector) == "OR" }.map { |entry| entry.fetch(:condition) }
198
- result["$and"] = and_conditions if and_conditions.any?
199
- result["$or"] = or_conditions if or_conditions.any?
200
- result
201
- end
202
-
203
- def default_find_many_limit
204
- value = options.advanced.dig(:database, :default_find_many_limit)
205
- return 100 if value.nil?
206
-
207
- Integer(value)
208
- rescue ArgumentError, TypeError
209
- 100
210
- end
211
-
212
- def array_operator_values(value)
213
- value.is_a?(Array) ? value : [value]
214
- end
215
-
216
- def condition_for(model, clause)
217
- operator = (fetch_key(clause, :operator) || "eq").to_s.downcase
218
- value = fetch_key(clause, :value)
219
-
220
- field = resolve_field(model, fetch_key(clause, :field))
221
- attributes = fields_for(model).fetch(field)
222
- key = (field == "id") ? "_id" : storage_field(model, field)
223
- mode = (fetch_key(clause, :mode) || "sensitive").to_s
224
- id_field = id_field?(field, attributes)
225
- insensitive = !id_field && mode == "insensitive" && insensitive_value?(value)
226
- value = coerce_where_value(value, attributes)
227
-
228
- case operator
229
- when "eq"
230
- (insensitive && value.is_a?(String)) ? regex_condition(key, value, :eq, insensitive: true) : {key => store_value(field, value, attributes, strict_id: true)}
231
- when "in"
232
- (insensitive && value.is_a?(Array)) ? insensitive_in_condition(key, value) : {key => {"$in" => array_operator_values(value).map { |entry| store_value(field, entry, attributes, strict_id: true) }}}
233
- when "not_in"
234
- (insensitive && value.is_a?(Array)) ? insensitive_not_in_condition(key, value) : {key => {"$nin" => array_operator_values(value).map { |entry| store_value(field, entry, attributes, strict_id: true) }}}
235
- when "ne"
236
- (insensitive && value.is_a?(String)) ? {key => {"$not" => regex_for(value, :eq, insensitive: true)}} : {key => {"$ne" => store_value(field, value, attributes, strict_id: true)}}
237
- when "gt", "gte", "lt", "lte"
238
- {key => {"$#{operator}" => store_value(field, value, attributes, strict_id: true)}}
239
- when "contains", "starts_with", "ends_with"
240
- regex_condition(key, value.to_s, operator.to_sym, insensitive: insensitive)
241
- else
242
- raise MongoAdapterError.new("UNSUPPORTED_OPERATOR", "Unsupported operator: #{operator}")
243
- end
244
- end
245
-
246
- def insensitive_value?(value)
247
- value.is_a?(String) || (value.is_a?(Array) && value.all? { |entry| entry.is_a?(String) })
248
- end
249
-
250
- def insensitive_in_condition(key, values)
251
- return {"$expr" => {"$eq" => [1, 0]}} if values.empty?
252
-
253
- {"$or" => values.map { |value| regex_condition(key, value, :eq, insensitive: true) }}
254
- end
255
-
256
- def insensitive_not_in_condition(key, values)
257
- return {} if values.empty?
258
-
259
- {"$nor" => values.map { |value| regex_condition(key, value, :eq, insensitive: true) }}
260
- end
261
-
262
- def regex_condition(key, value, operator, insensitive:)
263
- {key => regex_for(value, operator, insensitive: insensitive)}
264
- end
265
-
266
- def regex_for(value, operator, insensitive:)
267
- escaped = Regexp.escape(value.to_s[0, 256])
268
- pattern = case operator.to_s
269
- when "eq" then "\\A#{escaped}\\z"
270
- when "starts_with" then "\\A#{escaped}"
271
- when "ends_with" then "#{escaped}\\z"
272
- else escaped
273
- end
274
- Regexp.new(pattern, insensitive ? Regexp::IGNORECASE : nil)
275
- end
276
-
277
- def join_stages(model, join)
278
- normalized_join(model, join).flat_map do |join_model, config|
279
- local_field = storage_field_for_join(model, config.fetch(:from))
280
- foreign_field = storage_field_for_join(join_model, config.fetch(:to))
281
- relation = config[:relation]
282
- limit = config.key?(:limit) ? config[:limit] : nil
283
- effective_limit = limit.nil? ? default_find_many_limit : limit.to_i
284
- unique = relation == "one-to-one" || config[:unique]
285
- should_limit = !unique && effective_limit.positive?
286
-
287
- lookup = if should_limit
288
- {
289
- "$lookup" => {
290
- "from" => collection_name(join_model),
291
- "let" => {"localFieldValue" => "$#{local_field}"},
292
- "pipeline" => [
293
- {"$match" => {"$expr" => {"$eq" => ["$#{foreign_field}", "$$localFieldValue"]}}},
294
- {"$limit" => effective_limit}
295
- ],
296
- "as" => join_model
297
- }
298
- }
299
- else
300
- {
301
- "$lookup" => {
302
- "from" => collection_name(join_model),
303
- "localField" => local_field,
304
- "foreignField" => foreign_field,
305
- "as" => join_model
306
- }
307
- }
308
- end
309
-
310
- unique ? [lookup, {"$unwind" => {"path" => "$#{join_model}", "preserveNullAndEmptyArrays" => true}}] : [lookup]
311
- end
312
- end
313
-
314
- def normalized_join(model, join)
315
- join.each_with_object({}) do |(join_model, config), result|
316
- join_model = join_model.to_s
317
- result[join_model] = normalize_join_config(model, join_model, config)
318
- end
319
- end
320
-
321
- def normalize_join_config(model, join_model, config)
322
- if config.is_a?(Hash) && (config.key?(:on) || config.key?("on"))
323
- on = config[:on] || config["on"]
324
- relation = config[:relation] || config["relation"]
325
- limit = config[:limit] || config["limit"]
326
- from = fetch_key(on, :from)
327
- to = fetch_key(on, :to)
328
- return {from: Schema.storage_key(from), to: Schema.storage_key(to), relation: relation, limit: limit, unique: unique_join_field?(join_model, to)}
329
- end
330
-
331
- inferred = inferred_join_config(model, join_model)
332
- if config.is_a?(Hash)
333
- limit = config[:limit] || config["limit"]
334
- relation = config[:relation] || config["relation"]
335
- inferred = inferred.merge(limit: limit) if limit
336
- inferred = inferred.merge(relation: relation) if relation
337
- end
338
- inferred
339
- end
340
-
341
- def inferred_join_config(model, join_model)
342
- base_model = default_model_name(model)
343
- target_model = default_model_name(join_model)
344
- foreign_keys = fields_for(target_model).select do |_field, attributes|
345
- reference_model_matches?(attributes, base_model)
346
- end
347
- forward_join = true
348
-
349
- if foreign_keys.empty?
350
- foreign_keys = fields_for(base_model).select do |_field, attributes|
351
- reference_model_matches?(attributes, target_model)
352
- end
353
- forward_join = false
354
- end
355
-
356
- if foreign_keys.empty?
357
- raise Error, "No foreign key found for model #{join_model} and base model #{model} while performing join operation."
358
- end
359
- if foreign_keys.length > 1
360
- raise Error, "Multiple foreign keys found for model #{join_model} and base model #{model} while performing join operation. Only one foreign key is supported."
361
- end
362
-
363
- foreign_key, attributes = foreign_keys.first
364
- reference = attributes.fetch(:references)
365
- if forward_join
366
- unique = attributes[:unique] == true
367
- {from: reference.fetch(:field).to_s, to: foreign_key, relation: unique ? "one-to-one" : "one-to-many", unique: unique}
368
- else
369
- {from: foreign_key, to: reference.fetch(:field).to_s, relation: "one-to-one", unique: true}
370
- end
371
- end
372
-
373
- def reference_model_matches?(attributes, model)
374
- reference = attributes[:references]
375
- return false unless reference
376
-
377
- default_model_name(reference[:model] || reference["model"]) == model
378
- end
379
-
380
- def unique_join_field?(model, field)
381
- field = resolve_field(model, field)
382
- field == "id" || fields_for(model).dig(field, :unique) == true
383
- end
384
-
385
- def storage_field_for_join(model, field)
386
- field = resolve_field(model, field)
387
- (field == "id") ? "_id" : storage_field(model, field)
388
- end
389
-
390
- def projection_for(model, select, join)
391
- selected_fields = Array(select).map { |field| storage_field_for_join(model, field) }
392
- Array(select).each_with_object({}) do |field, projection|
393
- projection[storage_field_for_join(model, field)] = 1
394
- end.tap do |projection|
395
- projection["_id"] = 0 unless selected_fields.include?("_id")
396
- normalized_join(model, join).each_key { |join_model| projection[join_model] = 1 } if join
397
- end
398
- end
399
-
400
- def sort_field(model, sort_by)
401
- field = resolve_field(model, fetch_key(sort_by, :field))
402
- storage_field_for_join(model, field)
403
- end
404
-
405
- def sort_direction(sort_by)
406
- (fetch_key(sort_by, :direction).to_s == "desc") ? -1 : 1
407
- end
408
-
409
- def collection_for(model)
410
- database.collection(collection_name(model))
411
- end
5
+ require "better_auth/mongodb"
412
6
 
413
- def collection_name(model)
414
- model = default_model_name(model)
415
- configured = configured_model_name(model)
416
- return "#{configured}s" if configured && use_plural
417
- return configured if configured
418
- return schema_for(model).fetch(:model_name) if use_plural
419
-
420
- model.to_s
421
- end
422
-
423
- def to_document(model, record)
424
- fields_for(model).each_with_object({}) do |(field, attributes), document|
425
- next unless record.key?(field)
426
-
427
- key = (field == "id") ? "_id" : storage_field(model, field)
428
- document[key] = store_value(field, record[field], attributes)
429
- end
430
- end
431
-
432
- def from_document(model, document, join: nil)
433
- fields = fields_for(model)
434
- record = fields.each_with_object({}) do |(field, attributes), output|
435
- key = (field == "id") ? "_id" : storage_field(model, field)
436
- output[field] = output_value(field, fetch_document(document, key), attributes) if document_key?(document, key)
437
- end
438
-
439
- if join
440
- normalized_join(model, join).each do |join_model, config|
441
- next unless document_key?(document, join_model)
442
-
443
- joined_value = fetch_document(document, join_model)
444
- record[join_model] = if joined_value.is_a?(Array)
445
- joined_value.map { |entry| from_document(join_model, stringify_document(entry)) }
446
- elsif joined_value
447
- from_document(join_model, stringify_document(joined_value))
448
- elsif config[:relation] == "one-to-one"
449
- nil
450
- else
451
- []
452
- end
453
- end
454
- end
455
-
456
- record
457
- end
458
-
459
- def stringify_document(document)
460
- document.each_with_object({}) { |(key, value), result| result[key.to_s] = value }
461
- end
462
-
463
- def unwrap_update_result(result)
464
- return result unless result.is_a?(Hash)
465
- return result if document_key?(result, "_id")
466
-
467
- if result.key?("value") && (result.key?("ok") || result.key?("lastErrorObject"))
468
- return result["value"]
469
- end
470
- if result.key?(:value) && (result.key?(:ok) || result.key?(:last_error_object))
471
- return result[:value]
472
- end
473
-
474
- result
475
- end
476
-
477
- def store_value(field, value, attributes, strict_id: false)
478
- return nil if value.nil?
479
- return Array(value).map { |entry| store_value(field, entry, attributes, strict_id: strict_id) } if value.is_a?(Array)
480
-
481
- if id_field?(field, attributes)
482
- return value if custom_id_generator?
483
- return bson_id(value, strict: strict_id)
484
- end
485
-
486
- input_value(value, attributes)
487
- end
488
-
489
- def output_value(field, value, attributes)
490
- return nil if value.nil?
491
- if id_field?(field, attributes)
492
- return value.to_uuid if bson_uuid?(value)
493
- return value.to_s if value.is_a?(BSON::ObjectId)
494
- return value.map { |entry| output_value(field, entry, attributes) } if value.is_a?(Array)
495
- return value
496
- end
497
-
498
- output_scalar_value(value, attributes)
499
- end
500
-
501
- def id_field?(field, attributes)
502
- field.to_s == "id" || attributes.dig(:references, :field) == "id"
503
- end
504
-
505
- def bson_id(value, strict:)
506
- if use_uuid_ids?
507
- return value if bson_uuid?(value)
508
- return BSON::Binary.from_uuid(value.to_s) if value.is_a?(String)
509
- raise MongoAdapterError.new("INVALID_ID", "Invalid id value") if strict
510
-
511
- return value
512
- end
513
-
514
- return value if value.is_a?(BSON::ObjectId)
515
- return BSON::ObjectId.from_string(value.to_s) if value.is_a?(String)
516
- raise MongoAdapterError.new("INVALID_ID", "Invalid id value") if strict
517
-
518
- value
519
- rescue BSON::Error::InvalidObjectId, ArgumentError
520
- value
521
- end
522
-
523
- def bson_uuid?(value)
524
- defined?(BSON::Binary) && value.is_a?(BSON::Binary) && value.respond_to?(:to_uuid) && value.type == :uuid
525
- end
526
-
527
- def generated_id
528
- generator = options.advanced.dig(:database, :generate_id)
529
- return generator.call if generator.respond_to?(:call)
530
- return SecureRandom.uuid if use_uuid_ids?
531
- return BSON::ObjectId.new.to_s if defined?(BSON::ObjectId)
532
-
533
- SecureRandom.hex(12)
534
- end
535
-
536
- def use_uuid_ids?
537
- options.advanced.dig(:database, :generate_id) == "uuid"
538
- end
539
-
540
- def custom_id_generator?
541
- options.advanced.dig(:database, :generate_id).respond_to?(:call)
542
- end
543
-
544
- def resolve_default(default)
545
- default.respond_to?(:call) ? default.call : default
546
- end
547
-
548
- def coerce_value(value, attributes)
549
- return value if value.nil?
550
- return Time.parse(value) if attributes[:type] == "date" && value.is_a?(String)
551
-
552
- value
553
- end
554
-
555
- def input_value(value, attributes)
556
- value = coerce_value(value, attributes)
557
- return JSON.generate(value) if attributes[:type] == "json" && (value.is_a?(Hash) || value.is_a?(Array))
558
-
559
- value
560
- end
561
-
562
- def output_scalar_value(value, attributes)
563
- return JSON.parse(value) if attributes[:type] == "json" && value.is_a?(String)
564
-
565
- coerce_value(value, attributes)
566
- rescue JSON::ParserError
567
- value
568
- end
569
-
570
- def coerce_where_value(value, attributes)
571
- return value.map { |entry| coerce_where_value(entry, attributes) } if value.is_a?(Array)
572
- return value == "true" if attributes[:type] == "boolean" && value.is_a?(String)
573
- if attributes[:type] == "number" && value.is_a?(String) && !value.strip.empty?
574
- parsed = Float(value)
575
- return parsed.to_i if parsed.to_i == parsed
576
-
577
- return parsed
578
- end
579
- return JSON.generate(value) if attributes[:type] == "json" && (value.is_a?(Hash) || value.is_a?(Array))
580
-
581
- value
582
- rescue ArgumentError
583
- value
584
- end
585
-
586
- def session_options
587
- @session ? {session: @session} : {}
588
- end
589
-
590
- def document_key?(document, key)
591
- document.key?(key) || document.key?(key.to_sym)
592
- end
593
-
594
- def fetch_document(document, key)
595
- return document[key] if document.key?(key)
596
-
597
- document[key.to_sym]
598
- end
599
-
600
- def stringify_keys(data)
601
- data.each_with_object({}) do |(key, value), result|
602
- result[Schema.storage_key(key)] = value
603
- end
604
- end
605
-
606
- def fetch_key(hash, key)
607
- [key, key.to_s, Schema.storage_key(key), Schema.storage_key(key).to_sym].each do |candidate|
608
- return hash[candidate] if hash.key?(candidate)
609
- end
610
- nil
611
- end
612
-
613
- def schema_for(model)
614
- Schema.auth_tables(options).fetch(default_model_name(model))
615
- end
616
-
617
- def fields_for(model)
618
- schema_for(model).fetch(:fields).merge("id" => {type: "string", required: true})
619
- end
620
-
621
- def default_model_name(model)
622
- model = model.to_s
623
- tables = Schema.auth_tables(options)
624
- return model if tables.key?(model)
625
-
626
- pluraless = model.end_with?("s") ? model[0...-1] : nil
627
- return pluraless if pluraless && tables.key?(pluraless)
628
-
629
- matched = tables.find { |_key, table| table[:model_name].to_s == model }
630
- return matched.first if matched
631
-
632
- raise Error, "Model \"#{model}\" not found in schema"
633
- end
634
-
635
- def configured_model_name(model)
636
- configured = configured_model_option(model, :model_name)
637
- return configured.to_s if configured
638
-
639
- return nil if core_model?(model)
640
-
641
- table_model_name = schema_for(model).fetch(:model_name).to_s
642
- (table_model_name == physical_name(model)) ? nil : table_model_name
643
- end
644
-
645
- def configured_model_option(model, key)
646
- data = options.respond_to?(model.to_sym) ? options.public_send(model.to_sym) : nil
647
- data[key] || data[key.to_s] if data.respond_to?(:[])
648
- end
649
-
650
- def core_model?(model)
651
- ["user", "session", "account", "verification", "rateLimit"].include?(model.to_s)
652
- end
653
-
654
- def resolve_field(model, field)
655
- field = Schema.storage_key(field)
656
- return "id" if field == "id" || field == "_id"
657
-
658
- fields = fields_for(model)
659
- return field if fields.key?(field)
660
-
661
- matched = fields.find { |_key, attributes| attributes[:field_name].to_s == field.to_s }
662
- return matched.first if matched
663
-
664
- raise Error, "Field #{field} not found in model #{model}"
665
- end
666
-
667
- def storage_field(model, field)
668
- fields_for(model).fetch(field.to_s).fetch(:field_name, physical_name(field))
669
- end
670
-
671
- def physical_name(value)
672
- value.to_s
673
- .gsub(/([a-z\d])([A-Z])/, "\\1_\\2")
674
- .tr("-", "_")
675
- .downcase
676
- end
677
- end
678
- end
7
+ module BetterAuth
8
+ MongoAdapter = MongoDB unless const_defined?(:MongoAdapter, false)
679
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_auth-mongo-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Sala
@@ -10,73 +10,19 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: better_auth
13
+ name: better_auth-mongodb
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '0.1'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '0.1'
26
- - !ruby/object:Gem::Dependency
27
- name: bigdecimal
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '3.1'
33
- - - "<"
16
+ - - '='
34
17
  - !ruby/object:Gem::Version
35
- version: '5.0'
18
+ version: 0.8.0
36
19
  type: :runtime
37
20
  prerelease: false
38
21
  version_requirements: !ruby/object:Gem::Requirement
39
22
  requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: '3.1'
43
- - - "<"
44
- - !ruby/object:Gem::Version
45
- version: '5.0'
46
- - !ruby/object:Gem::Dependency
47
- name: logger
48
- requirement: !ruby/object:Gem::Requirement
49
- requirements:
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: '1.6'
53
- - - "<"
54
- - !ruby/object:Gem::Version
55
- version: '2.0'
56
- type: :runtime
57
- prerelease: false
58
- version_requirements: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: '1.6'
63
- - - "<"
64
- - !ruby/object:Gem::Version
65
- version: '2.0'
66
- - !ruby/object:Gem::Dependency
67
- name: mongo
68
- requirement: !ruby/object:Gem::Requirement
69
- requirements:
70
- - - "~>"
71
- - !ruby/object:Gem::Version
72
- version: '2.21'
73
- type: :runtime
74
- prerelease: false
75
- version_requirements: !ruby/object:Gem::Requirement
76
- requirements:
77
- - - "~>"
23
+ - - '='
78
24
  - !ruby/object:Gem::Version
79
- version: '2.21'
25
+ version: 0.8.0
80
26
  - !ruby/object:Gem::Dependency
81
27
  name: bundler
82
28
  requirement: !ruby/object:Gem::Requirement
@@ -147,8 +93,8 @@ dependencies:
147
93
  - - "~>"
148
94
  - !ruby/object:Gem::Version
149
95
  version: '0.22'
150
- description: Adds a MongoDB database adapter for Better Auth Ruby without requiring
151
- MongoDB dependencies in the core gem.
96
+ description: Deprecated compatibility package for Better Auth Ruby MongoDB support.
97
+ Use the better_auth-mongodb gem and require "better_auth/mongodb" instead.
152
98
  email:
153
99
  - sebastian.sala.tech@gmail.com
154
100
  executables: []