cool_id 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d44c3207248595af232a200cf0e809224d74033d97d3cac52c6d06d5416b682
4
- data.tar.gz: d221baeb8e79ea8ea8ca2b9503685e4bfa7cb8d57b53a3ba0e4d301138a08300
3
+ metadata.gz: a13030502ed2121afaaa78cd0443dc8c199c8ac0608080400ad5624947ed4a5a
4
+ data.tar.gz: a626eeead1ca380bebf7a172eb46bc2e683073f8fd353c5ad9ecfe6721589e46
5
5
  SHA512:
6
- metadata.gz: 9ed700560671d811b0678c4fbe8f9e086c3ca0c9e8d04a54b7d40d586b20864e2add65adb9e5e53feb7915e472974dbfa6b31313dd6a64f4008aaf3f31503f70
7
- data.tar.gz: df1cdc3098d9b4761a220fedeca362eeaeb5677d92ca7da594dc946223d814c81bb59db757ff08292fe72e3ce499dd95e1cc002ccf27c436aa097617bd14f2a9
6
+ metadata.gz: b22b2cd792877343af3f1e9b3aa51fcf8e5f6920fc1fa79407e9149c4b43acbea3c9bbd10959c46810f2cb4fc0a25c5d538211d274f10adc18ee8c5583f1040e
7
+ data.tar.gz: 44d27992a9c89ba415db43cc31ee3c590037107135a5bc58dcf542f0b7fda702ae965798c39b01448c8a74fad3b43618b64ae1545a53ad85c85386770ce954fd
data/.aider.conf.yml ADDED
@@ -0,0 +1,9 @@
1
+ # https://aider.chat/docs/config/aider_conf.html
2
+
3
+ lint-cmd: bundle exec standardrb --fix
4
+ auto-lint: true
5
+
6
+ test-cmd: bundle exec rspec --format progress --no-profile --no-color --fail-fast
7
+ auto-test: true
8
+
9
+ read: cool_id.gemspec
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # cool_id
1
+ # cool id
2
2
 
3
- a gem for rails that generates string primary key ids for active record models with a per-model prefix followed by a nanoid. this lets you create stripe style ids in your own rails app, and they'll be the same ids you see in your database.
3
+ gem for rails apps to generates string ids with a prefix, followed by a [nanoid](https://zelark.github.io/nano-id-cc/). similar to the ids you see in stripe's api. also able to lookup any record by id, similar to rails' globalid.
4
4
 
5
5
  ```ruby
6
6
  class User < ActiveRecord::Base
@@ -12,7 +12,7 @@ User.create!(name: "...").id
12
12
  # => "usr_vktd1b5v84lr"
13
13
  ```
14
14
 
15
- it can also lookup records similar to global id:
15
+ lookup any record by its id
16
16
 
17
17
  ```ruby
18
18
  CoolId.locate("usr_vktd1b5v84lr")
@@ -72,7 +72,7 @@ bundle add cool_id
72
72
  gem "cool_id"
73
73
  ```
74
74
 
75
- ### using cool_id in one model
75
+ ### adding cool_id to a single model
76
76
 
77
77
  use string ids when creating a table
78
78
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CoolId
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.8"
5
5
  end
data/lib/cool_id.rb CHANGED
@@ -5,17 +5,20 @@ require "nanoid"
5
5
  require "active_support/concern"
6
6
 
7
7
  module CoolId
8
- class Error < StandardError; end
8
+ class NotConfiguredError < StandardError; end
9
+
10
+ class MaxRetriesExceededError < StandardError; end
9
11
 
10
12
  # defaults based on https://planetscale.com/blog/why-we-chose-nanoids-for-planetscales-api
11
13
  DEFAULT_SEPARATOR = "_"
12
14
  DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"
13
15
  DEFAULT_LENGTH = 12
16
+ DEFAULT_MAX_RETRIES = 1000
14
17
 
15
18
  Id = Struct.new(:key, :prefix, :id, :model_class)
16
19
 
17
20
  class << self
18
- attr_accessor :separator, :alphabet, :length
21
+ attr_accessor :separator, :alphabet, :length, :max_retries
19
22
 
20
23
  def configure
21
24
  yield self
@@ -25,6 +28,7 @@ module CoolId
25
28
  self.separator = DEFAULT_SEPARATOR
26
29
  self.alphabet = DEFAULT_ALPHABET
27
30
  self.length = DEFAULT_LENGTH
31
+ self.max_retries = DEFAULT_MAX_RETRIES
28
32
  end
29
33
 
30
34
  def registry
@@ -34,15 +38,28 @@ module CoolId
34
38
  def generate_id(config)
35
39
  alphabet = config.alphabet || @alphabet
36
40
  length = config.length || @length
37
- id = Nanoid.generate(size: length, alphabet: alphabet)
41
+ max_retries = config.max_retries || @max_retries
42
+
43
+ retries = 0
44
+ loop do
45
+ nano_id = Nanoid.generate(size: length, alphabet: alphabet)
46
+ full_id = "#{config.prefix}#{separator}#{nano_id}"
47
+ if !config.model_class.exists?(id: full_id)
48
+ return full_id
49
+ end
38
50
 
39
- "#{config.prefix}#{separator}#{id}"
51
+ retries += 1
52
+ if retries >= max_retries
53
+ raise MaxRetriesExceededError, "Failed to generate a unique ID after #{max_retries} attempts"
54
+ end
55
+ end
40
56
  end
41
57
  end
42
58
 
43
59
  self.separator = DEFAULT_SEPARATOR
44
60
  self.alphabet = DEFAULT_ALPHABET
45
61
  self.length = DEFAULT_LENGTH
62
+ self.max_retries = DEFAULT_MAX_RETRIES
46
63
 
47
64
  class Registry
48
65
  def initialize
@@ -67,12 +84,14 @@ module CoolId
67
84
  end
68
85
 
69
86
  class Config
70
- attr_reader :prefix, :length, :alphabet
87
+ attr_reader :prefix, :length, :alphabet, :max_retries, :model_class
71
88
 
72
- def initialize(prefix:, length: nil, alphabet: nil)
89
+ def initialize(prefix:, model_class:, length: nil, alphabet: nil, max_retries: nil)
73
90
  @length = length
74
91
  @prefix = validate_prefix(prefix)
75
92
  @alphabet = validate_alphabet(alphabet)
93
+ @max_retries = max_retries
94
+ @model_class = model_class
76
95
  end
77
96
 
78
97
  private
@@ -98,7 +117,7 @@ module CoolId
98
117
  attr_accessor :cool_id_setup_required
99
118
 
100
119
  def cool_id(options)
101
- @cool_id_config = Config.new(**options)
120
+ @cool_id_config = Config.new(**options, model_class: self)
102
121
  CoolId.registry.register(options[:prefix], self)
103
122
  end
104
123
 
@@ -110,7 +129,7 @@ module CoolId
110
129
  @cool_id_setup_required = true
111
130
  end
112
131
 
113
- def skip_enforce_cool_id_for_descendants
132
+ def skip_enforce_cool_id
114
133
  @cool_id_setup_required = false
115
134
  end
116
135
 
@@ -134,7 +153,8 @@ module CoolId
134
153
 
135
154
  def ensure_cool_id_configured
136
155
  if self.class.cool_id_setup_required && self.class.cool_id_config.nil?
137
- raise Error, "CoolId not configured for #{self.class}. Use 'cool_id' to configure or 'skip_enforce_cool_id_for_descendants' to opt out."
156
+ suggested_prefix = self.class.name.downcase[0..2]
157
+ raise NotConfiguredError, "CoolId not configured for #{self.class}. Use 'cool_id' to configure or 'skip_enforce_cool_id' to opt out.\n\ne.g.\n\nclass #{self.class} < ApplicationRecord\n cool_id prefix: \"#{suggested_prefix}\"\nend"
138
158
  end
139
159
  end
140
160
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cool_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Schilling
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-18 00:00:00.000000000 Z
11
+ date: 2024-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nanoid
@@ -73,6 +73,7 @@ executables: []
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
+ - ".aider.conf.yml"
76
77
  - ".rspec"
77
78
  - ".standard.yml"
78
79
  - CHANGELOG.md