Skip to content

Commit 437df34

Browse files
committed
Add support for Sequel
1 parent 77fba2a commit 437df34

File tree

7 files changed

+374
-0
lines changed

7 files changed

+374
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
99
### Added
1010

1111
- The ability to configure the random generator for the gem via `KSUID.configure`. This allows you to set up random generation to the specifications you need, whether that is for speed or for security.
12+
- A plugin for Sequel to support KSUID fields. You can include the plugin via `plugin :ksuid` within a `Sequel::Model` class.
1213

1314
### Changed
1415

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,8 @@ group :ci do
3232
end
3333

3434
group :test do
35+
gem 'jdbc-sqlite3', platforms: %i[jruby]
3536
gem 'rspec', '~> 3.6'
37+
gem 'sequel'
38+
gem 'sqlite3', platforms: %i[mri mingw x64_mingw]
3639
end

config.reek

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
ManualDispatch:
33
exclude:
44
- "KSUID::Configuration#assert_generator_is_callable"
5+
- "Sequel::Plugins::Ksuid::InstanceMethods#set_ksuid"
56

67
UncommunicativeModuleName:
78
exclude:

lib/ksuid.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require_relative 'ksuid/configuration'
44
require_relative 'ksuid/type'
55
require_relative 'ksuid/version'
6+
require_relative 'sequel/plugins/ksuid' if defined?(Sequel)
67

78
# The K-Sortable Unique IDentifier (KSUID)
89
#

lib/sequel/plugins/ksuid.rb

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# frozen_string_literal: true
2+
3+
module Sequel # :nodoc:
4+
module Plugins # :nodoc:
5+
# Adds KSUID support to the Sequel ORM
6+
#
7+
# @api public
8+
#
9+
# @example Creates a model with a standard, string-based KSUID
10+
# connection_string = 'sqlite:/'
11+
# connection_string = 'jdbc:sqlite::memory:' if RUBY_ENGINE == 'jruby'
12+
# DB = Sequel.connect(connection_string)
13+
#
14+
# DB.create_table!(:events) do
15+
# Integer :id
16+
# String :ksuid
17+
# end
18+
#
19+
# class Event < Sequel::Model(:events)
20+
# plugin :ksuid
21+
# end
22+
#
23+
# @example Creates a model with a customized KSUID field
24+
# connection_string = 'sqlite:/'
25+
# connection_string = 'jdbc:sqlite::memory:' if RUBY_ENGINE == 'jruby'
26+
# DB = Sequel.connect(connection_string)
27+
#
28+
# DB.create_table!(:events) do
29+
# Integer :id
30+
# String :correlation_id
31+
# end
32+
#
33+
# class Event < Sequel::Model(:events)
34+
# plugin :ksuid, field: :correlation_id
35+
# end
36+
#
37+
# @example Creates a model that always overwrites the KSUID on save
38+
# connection_string = 'sqlite:/'
39+
# connection_string = 'jdbc:sqlite::memory:' if RUBY_ENGINE == 'jruby'
40+
# DB = Sequel.connect(connection_string)
41+
#
42+
# DB.create_table!(:events) do
43+
# Integer :id
44+
# String :ksuid
45+
# end
46+
#
47+
# class Event < Sequel::Model(:events)
48+
# plugin :ksuid, force: true
49+
# end
50+
#
51+
# @example Creates a model with a binary-encoded KSUID
52+
# connection_string = 'sqlite:/'
53+
# connection_string = 'jdbc:sqlite::memory:' if RUBY_ENGINE == 'jruby'
54+
# DB = Sequel.connect(connection_string)
55+
#
56+
# DB.create_table!(:events) do
57+
# Integer :id
58+
# blob :ksuid
59+
# end
60+
#
61+
# class Event < Sequel::Model(:events)
62+
# plugin :ksuid, binary: true
63+
# end
64+
module Ksuid
65+
# Configures the plugin by setting available options
66+
#
67+
# @api private
68+
#
69+
# @param model [Sequel::Model] the model to configure
70+
# @param options [Hash] the hash of available options
71+
# @option options [Boolean] :binary encode the KSUID as a binary string
72+
# @option options [Boolean] :field the field to use as a KSUID
73+
# @option options [Boolean] :force overwrite the field on save
74+
def self.configure(model, options = OPTS)
75+
model.instance_exec do
76+
@ksuid_binary = options.fetch(:binary, false)
77+
@ksuid_field = options.fetch(:field, :ksuid)
78+
@ksuid_overwrite = options.fetch(:force, false)
79+
end
80+
end
81+
82+
# Class methods that are extended onto an enabling model class
83+
#
84+
# @api private
85+
module ClassMethods
86+
# The field that is enabled with KSUID handling
87+
#
88+
# @api private
89+
#
90+
# @return [Symbol]
91+
attr_reader :ksuid_field
92+
93+
# Checks whether the KSUID should be binary encoded
94+
#
95+
# @api private
96+
#
97+
# @return [Boolean]
98+
def ksuid_binary?
99+
@ksuid_binary
100+
end
101+
102+
# Checks whether the KSUID should be overwritten upon save
103+
#
104+
# @api private
105+
#
106+
# @return [Boolean]
107+
def ksuid_overwrite?
108+
@ksuid_overwrite
109+
end
110+
111+
Plugins.inherited_instance_variables(
112+
self,
113+
:@ksuid_binary => nil,
114+
:@ksuid_field => nil,
115+
:@ksuid_overwrite => nil
116+
)
117+
end
118+
119+
# Instance methods that are included in an enabling model class
120+
#
121+
# @api private
122+
module InstanceMethods
123+
# Generates a KSUID for the field before validation
124+
#
125+
# @api private
126+
#
127+
# @return [void]
128+
def before_validation
129+
set_ksuid if new?
130+
super
131+
end
132+
133+
private
134+
135+
# A hook method for generating a new KSUID
136+
#
137+
# @api private
138+
#
139+
# @return [String] a binary or base 62-encoded string
140+
def create_ksuid
141+
ksuid = KSUID.new
142+
143+
if self.class.ksuid_binary?
144+
ksuid.to_bytes
145+
else
146+
ksuid.to_s
147+
end
148+
end
149+
150+
# Initializes the KSUID field when it is not set, or overwrites it if enabled
151+
#
152+
# Note: The disabled Rubocop rule is to allow the method to follow
153+
# Sequel conventions.
154+
#
155+
# @api private
156+
#
157+
# @param ksuid [String] the normal string or byte string of the KSUID
158+
# @return [void]
159+
# rubocop:disable Naming/AccessorMethodName
160+
def set_ksuid(ksuid = create_ksuid)
161+
field = model.ksuid_field
162+
setter = :"#{field}="
163+
164+
return unless respond_to?(field) &&
165+
respond_to?(setter) &&
166+
(model.ksuid_overwrite? || !get_column_value(field))
167+
168+
set_column_value(setter, ksuid)
169+
end
170+
end
171+
end
172+
end
173+
end

spec/doctest_helper.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# frozen_string_literal: true
22

3+
require 'sequel'
4+
require 'sqlite3' unless RUBY_ENGINE == 'jruby'
35
require 'ksuid'

0 commit comments

Comments
 (0)