sequel-tstzrange-fields 0.3.1 → 0.4.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: 8ce882832d62ea1342d7daaea5e30958d2bda7f52f02d6279d0f03b38b4b0a10
4
- data.tar.gz: 99d7b2e90fe4b6d050f9e4f856d709bab47a97cf658ecf12c57131705006a89e
3
+ metadata.gz: 7e2a319a52c24e4d5b48677374c28497e6e0b882bef5bb9c60a84533abc0ab91
4
+ data.tar.gz: 2414fced47bc4403dbe479090ef5bc55e892fc1e01a2e51eb37c41bc248e4dd5
5
5
  SHA512:
6
- metadata.gz: '0389be6b6156008e52eb8db931bd1b710aa444ec877a1971c7255cca008c9650e46d14ea107525ddae52447cbdc41dcb901425b1ebcf168a870ee2741272fca0'
7
- data.tar.gz: cd145bb21d5a9b24c260bcbf342bcc214dc7a1eac5adbb05f8ab64ed47b148921b7545866f1750dedc41d83f76113760457a882457f73517998968847223f9b4
6
+ metadata.gz: 3d1cc019a842fd64e2f71ecaa22a6b35e782394ff0e2e013264a02d76412e061cd3481f814f798da7b171cf34d9382fc83922e01d8a07c04a94c57f930bb7984
7
+ data.tar.gz: b6d5e965178b3e696b21578c5087a87925bbeb064d5faf270734c80088a8cee39f15172a31da786b007a7fac5e2082ab0e3af622ef428e0cfe4ed3ce10f6b9e7
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sequel"
4
+ require "sequel/model"
5
+
6
+ require_relative "../../sequel_tstzrange_fields/version"
7
+
8
+ # Plugin for adding methods for working with time ranges.
9
+ #
10
+ # == Example
11
+ #
12
+ # Defining a model class with a timestamptz multirange:
13
+ #
14
+ # class Reminder < Sequel::Model(:reminders)
15
+ # plugin :tstzmultirange_fields, :active_during
16
+ #
17
+ # And in the schema:
18
+ #
19
+ # create_table(:reminders) do
20
+ # primary_key :id
21
+ # tstzmultirange :active_during
22
+ # end
23
+ #
24
+ # You can use it as follows:
25
+ #
26
+ # r = Reminder.new
27
+ # reminder.active_during = [{begin: Time.now, end: 1.year.from_now}]
28
+ # reminder.active_during = [1.year.ago..1.year.from_now]
29
+ # reminder.active_during = [Time.now..]
30
+ # reminder.active_during = []
31
+ #
32
+ module Sequel
33
+ module Plugins
34
+ module TstzmultirangeFields
35
+ VERSION = SequelTstzrangeFields::VERSION
36
+
37
+ def self.apply(_model, _opts={})
38
+ Sequel.extension :pg_range_ops
39
+ end
40
+
41
+ def self.configure(model, *args)
42
+ SequelTstzrangeFields::Helpers.check_schema_type_available(model.db, :tstzmultirange, :pg_multirange)
43
+ args << :periods if args.empty?
44
+ args = args.flatten
45
+
46
+ setup_model(model)
47
+ model.tstzrange_columns = args
48
+ model.tstzrange_columns.each do |column|
49
+ create_accessors(model, column)
50
+ end
51
+ end
52
+
53
+ def self.setup_model(model)
54
+ model.extend(SequelTstzrangeFields::Helpers::ClassMethods)
55
+ end
56
+
57
+ def self.create_accessors(model, column)
58
+ get_column_method = column.to_sym
59
+ set_column_method = :"#{column}="
60
+
61
+ model.define_method(get_column_method) do
62
+ self[column]
63
+ end
64
+
65
+ model.define_method(set_column_method) do |values|
66
+ values = [values] unless values.respond_to?(:to_ary)
67
+ ranges = values.map { |v| self.class.value_to_tstzrange(v) }
68
+ multirange = Sequel.pg_multirange(ranges, :tstzmultirange)
69
+ self[column] = multirange
70
+ end
71
+ end
72
+
73
+ module ClassMethods
74
+ # The Array of fields which are tstzrange columns.
75
+ attr_accessor :tstzrange_columns
76
+ end
77
+
78
+ module DatasetMethods
79
+ # Limit the dataset to the rows where the tstzrange column contains the given value.
80
+ # val is cast into a timestamptz.
81
+ # column is the default/first tstzrange column if not given.
82
+ def tstzrange_contains(val, column: nil)
83
+ column ||= self.model.tstzrange_columns.first
84
+ self.where(Sequel.pg_range(column).contains(Sequel.cast(val, :timestamptz)))
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -4,6 +4,7 @@ require "sequel"
4
4
  require "sequel/model"
5
5
 
6
6
  require_relative "../../sequel_tstzrange_fields/version"
7
+ require_relative "../../sequel_tstzrange_fields/helpers"
7
8
 
8
9
  # Plugin for adding methods for working with time ranges.
9
10
  #
@@ -40,36 +41,19 @@ module Sequel
40
41
  end
41
42
 
42
43
  def self.configure(model, *args)
43
- unless model.db.schema_type_class(:tstzrange)
44
- msg = "tstzrange_fields plugin requires pg_range db extension to be installed. " \
45
- "Use db.extension(:pg_range) after the db = Sequel.connect call."
46
- raise msg
47
- end
44
+ SequelTstzrangeFields::Helpers.check_schema_type_available(model.db, :tstzrange, :pg_range)
48
45
  args << :period if args.empty?
49
46
  args = args.flatten
50
47
 
51
48
  setup_model(model)
52
- model.tstzrange_columns = args.flatten
49
+ model.tstzrange_columns = args
53
50
  model.tstzrange_columns.each do |column|
54
51
  create_accessors(model, column)
55
52
  end
56
53
  end
57
54
 
58
55
  def self.setup_model(model)
59
- model.class.define_method(:new_tstzrange) do |b, e|
60
- b = value_to_time(b)
61
- e = value_to_time(e)
62
- return Sequel::Postgres::PGRange.empty(:tstzrange) if b.nil? && e.nil?
63
-
64
- return Sequel::Postgres::PGRange.new(b&.to_time, e&.to_time, db_type: :tstzrange, exclude_end: true)
65
- end
66
-
67
- model.class.define_method(:value_to_time) do |v|
68
- return v if v.nil?
69
- return v if v.respond_to?(:to_time)
70
-
71
- return Time.parse(v)
72
- end
56
+ model.extend(SequelTstzrangeFields::Helpers::ClassMethods)
73
57
  end
74
58
 
75
59
  def self.create_accessors(model, column)
@@ -85,19 +69,7 @@ module Sequel
85
69
  end
86
70
 
87
71
  model.define_method(set_column_method) do |value|
88
- case value
89
- when Sequel::Postgres::PGRange
90
- self[column] = value
91
- when Float::INFINITY
92
- range = Sequel::Postgres::PGRange.new(nil, nil, empty: false, db_type: :tstzrange)
93
- self[column] = range
94
- when "empty", nil
95
- self[column] = Sequel::Postgres::PGRange.empty(:tstzrange)
96
- else
97
- beg = value.respond_to?(:begin) ? value.begin : (value[:begin] || value["begin"])
98
- en = value.respond_to?(:end) ? value.end : (value[:end] || value["end"])
99
- self[column] = self.class.new_tstzrange(beg, en)
100
- end
72
+ self[column] = self.class.value_to_tstzrange(value)
101
73
  end
102
74
 
103
75
  model.define_method(get_begin_method) do
@@ -127,13 +99,7 @@ module Sequel
127
99
  end
128
100
 
129
101
  module DatasetMethods
130
- # Limit the dataset to the rows where the tstzrange column contains the given value.
131
- # val is cast into a timestamptz.
132
- # column is the default/first tstzrange column if not given.
133
- def tstzrange_contains(val, column: nil)
134
- column ||= self.model.tstzrange_columns.first
135
- self.where(Sequel.pg_range(column).contains(Sequel.cast(val, :timestamptz)))
136
- end
102
+ include SequelTstzrangeFields::Helpers::DatasetMethods
137
103
  end
138
104
  end
139
105
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SequelTstzrangeFields::Helpers
4
+ module ClassMethods
5
+ def new_tstzrange(b, e)
6
+ b = value_to_time(b)
7
+ e = value_to_time(e)
8
+ return Sequel::Postgres::PGRange.empty(:tstzrange) if b.nil? && e.nil?
9
+ return Sequel::Postgres::PGRange.new(b&.to_time, e&.to_time, db_type: :tstzrange, exclude_end: true)
10
+ end
11
+
12
+ def value_to_time(v)
13
+ return v if v.nil?
14
+ return v if v.respond_to?(:to_time)
15
+ return Time.parse(v)
16
+ end
17
+
18
+ def value_to_tstzrange(value)
19
+ case value
20
+ when Sequel::Postgres::PGRange
21
+ return value
22
+ when Float::INFINITY
23
+ range = Sequel::Postgres::PGRange.new(nil, nil, empty: false, db_type: :tstzrange)
24
+ return range
25
+ when "empty", nil
26
+ return Sequel::Postgres::PGRange.empty(:tstzrange)
27
+ else
28
+ beg = value.respond_to?(:begin) ? value.begin : (value[:begin] || value["begin"])
29
+ en = value.respond_to?(:end) ? value.end : (value[:end] || value["end"])
30
+ return self.new_tstzrange(beg, en)
31
+ end
32
+ end
33
+ end
34
+
35
+ module DatasetMethods
36
+ # Limit the dataset to the rows where the tstzrange column contains the given value.
37
+ # val is cast into a timestamptz.
38
+ # column is the default/first tstzrange column if not given.
39
+ def tstzrange_contains(val, column: nil)
40
+ column ||= self.model.tstzrange_columns.first
41
+ self.where(Sequel.pg_range(column).contains(Sequel.cast(val, :timestamptz)))
42
+ end
43
+ end
44
+
45
+ def self.check_schema_type_available(db, dbtype, ext)
46
+ return if db.schema_type_class(dbtype)
47
+ msg = "plugin requires #{ext} db extension to be installed. " \
48
+ "Use db.extension(:#{ext}) after the db = Sequel.connect call."
49
+ raise TypeError, msg
50
+ end
51
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SequelTstzrangeFields
4
- VERSION = "0.3.1"
4
+ VERSION = "0.4.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel-tstzrange-fields
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lithic Tech
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-15 00:00:00.000000000 Z
11
+ date: 2026-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -103,7 +103,9 @@ executables: []
103
103
  extensions: []
104
104
  extra_rdoc_files: []
105
105
  files:
106
+ - lib/sequel/plugins/tstzmultirange_fields.rb
106
107
  - lib/sequel/plugins/tstzrange_fields.rb
108
+ - lib/sequel_tstzrange_fields/helpers.rb
107
109
  - lib/sequel_tstzrange_fields/version.rb
108
110
  homepage: https://github.com/lithictech/sequel-tstzrange-fields
109
111
  licenses: