umbrellio-utils 1.13.2 → 1.14.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: b3fb1789266f96caa48d78ccd5889e105acdbef4dc223c4b172c6be49fb4612d
4
- data.tar.gz: fc558f846c8fa09ce78c0deb81f2b2e94760a063ebb281cf9f2e23be4c795fa6
3
+ metadata.gz: 6d29c478a9bce7022cddef6a1f54c3d11b48a23d65cc38fb385f75a751ea2022
4
+ data.tar.gz: 256c08e41a5860e8c430959a7e4848f36e9001f954a42c1160e6beff6758c19c
5
5
  SHA512:
6
- metadata.gz: 92dfcbbd2228a4f39fdb93eb0cc26e56ab9859d7a55233662a98118e70315474e819de791d187cecd75a99e9e1d99dc4cc95f1c45bd124f7df6cfbc7fe171ef0
7
- data.tar.gz: e544b012acf6d92bbad772cbce24d115cc03e5a7453270fc8c8b7dbead9e0bd209c7c83a726f19d6a73b2853163222fc3a29aea0920021fc2fdde58978bc7f9d
6
+ metadata.gz: d0b45c7757a482fb326731dbc5bb778c446a1dcd55c1ccc9c4f39d000196d66c541801ce93604ad11be5fc4aba974022d190b95e3cfc2ca19dc593523a4efafb
7
+ data.tar.gz: '01385fd42fd555ca9ae3f3d59a2602b459ab9d2cf2d299f3ff5634caabe5e75a35e82d912287ba4c57f634bad3e99d96e3ec71f37b5ce45c062d58c948fe40c4'
data/Gemfile.lock CHANGED
@@ -11,7 +11,7 @@ GIT
11
11
  PATH
12
12
  remote: .
13
13
  specs:
14
- umbrellio-utils (1.13.2)
14
+ umbrellio-utils (1.14.0)
15
15
  memery (~> 1)
16
16
 
17
17
  GEM
@@ -2,6 +2,8 @@
2
2
 
3
3
  module UmbrellioUtils
4
4
  module Database
5
+ DEFAULT_ORDER = :desc
6
+
5
7
  extend self
6
8
 
7
9
  class HandledConstaintError < StandardError
@@ -28,13 +30,14 @@ module UmbrellioUtils
28
30
  def each_record(dataset, primary_key: nil, **options, &block)
29
31
  primary_key = primary_key_from(dataset, primary_key:)
30
32
  eager_tables = Array(options.delete(:eager_load))
33
+ order = options.fetch(:order, DEFAULT_ORDER)
31
34
 
32
35
  with_temp_table(dataset, primary_key:, **options) do |ids|
33
36
  rows = ids.map { |id| row(id.is_a?(Hash) ? id.values : [id]) }
34
- records = dataset.model
35
- .eager(eager_tables)
36
- .where(row(primary_key) => rows)
37
- .reverse(row(primary_key)).all
37
+ records = ordered(
38
+ dataset.model.eager(eager_tables).where(row(primary_key) => rows),
39
+ row(primary_key), order
40
+ ).all
38
41
  records.each(&block)
39
42
  end
40
43
  end
@@ -48,6 +51,7 @@ module UmbrellioUtils
48
51
  # @option [Array] primary_key custom primary key to use for dataset
49
52
  # @option [Symbol, String] temp_table_name custom name for temporary table,
50
53
  # table is reused if already exists
54
+ # @option [Symbol] order primary key order to yield batches in, :asc or :desc
51
55
  # rubocop:disable Metrics/ParameterLists
52
56
  def with_temp_table(
53
57
  dataset,
@@ -55,8 +59,12 @@ module UmbrellioUtils
55
59
  sleep: nil,
56
60
  primary_key: nil,
57
61
  temp_table_name: nil,
58
- transaction: true
62
+ transaction: true,
63
+ order: DEFAULT_ORDER
59
64
  )
65
+ raise ArgumentError, "invalid order: #{order.inspect} (expected :asc or :desc)" \
66
+ unless %i[asc desc].include?(order)
67
+
60
68
  primary_key = primary_key_from(dataset, primary_key:)
61
69
  sleep_interval = sleep_interval_from(sleep)
62
70
 
@@ -68,7 +76,7 @@ module UmbrellioUtils
68
76
 
69
77
  loop do
70
78
  conditional_transaction(transaction) do
71
- pk_set = pop_next_pk_batch(temp_table_name, primary_key, page_size)
79
+ pk_set = pop_next_pk_batch(temp_table_name, primary_key, page_size, order)
72
80
  yield(pk_set) if pk_set.any?
73
81
  end
74
82
 
@@ -122,6 +130,14 @@ module UmbrellioUtils
122
130
  Sequel.function(:row, *values)
123
131
  end
124
132
 
133
+ def ordered(dataset, expr, order)
134
+ case order
135
+ when :asc then dataset.order(expr)
136
+ when :desc then dataset.reverse(expr)
137
+ else raise ArgumentError, "invalid order: #{order.inspect} (expected :asc or :desc)"
138
+ end
139
+ end
140
+
125
141
  def extract_primary_key(dataset)
126
142
  dataset.db.schema(dataset.first_source).select { |x| x[1][:primary_key] }.map(&:first)
127
143
  end
@@ -147,9 +163,9 @@ module UmbrellioUtils
147
163
  end
148
164
  end
149
165
 
150
- def pop_next_pk_batch(temp_table_name, primary_key, batch_size)
166
+ def pop_next_pk_batch(temp_table_name, primary_key, batch_size, order)
151
167
  row = row(primary_key)
152
- pk_expr = DB[temp_table_name].select(*primary_key).reverse(row).limit(batch_size)
168
+ pk_expr = ordered(DB[temp_table_name].select(*primary_key), row, order).limit(batch_size)
153
169
  deleted_items = DB[temp_table_name].where(row => pk_expr).returning.delete
154
170
  deleted_items.map do |item|
155
171
  next item if primary_key.size > 1
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UmbrellioUtils
4
+ class LargeObject
5
+ # :nocov:
6
+ class Writer
7
+ MAX_BUFFER_SIZE = PG_PAGE_SIZE * 10
8
+
9
+ attr_reader :large_object
10
+
11
+ def initialize(large_object)
12
+ @large_object = large_object
13
+ self.sio = StringIO.new.binmode
14
+ super()
15
+
16
+ if block_given?
17
+ yield(self)
18
+ flush
19
+ end
20
+ end
21
+
22
+ def flush
23
+ sio.flush
24
+ large_object.append!(sio.string)
25
+ sio.truncate(0)
26
+ sio.rewind
27
+ self
28
+ end
29
+
30
+ def tell
31
+ sio.tell + large_object.str_offset
32
+ end
33
+ alias pos tell
34
+
35
+ def write(*)
36
+ sio.write(*)
37
+ flush if sio.string.size >= MAX_BUFFER_SIZE
38
+ self
39
+ end
40
+ alias << write
41
+
42
+ def reopen(other, *)
43
+ sio.reopen(other.sio.string, *)
44
+ self
45
+ end
46
+
47
+ def pos=(new_pos)
48
+ case
49
+ when new_pos < large_object.str_offset
50
+ flush
51
+ relative_pos = new_pos - large_object.str_offset
52
+ large_object.str_offset += relative_pos
53
+ when new_pos > sio.string.length
54
+ flush
55
+ large_object.str_offset = new_pos
56
+ else
57
+ sio.pos = new_pos - large_object.str_offset
58
+ end
59
+ end
60
+
61
+ def rewind
62
+ large_object.str_offset = 0
63
+ sio.rewind
64
+ end
65
+
66
+ protected
67
+
68
+ attr_accessor :sio
69
+ end
70
+ # :nocov:
71
+ end
72
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UmbrellioUtils
4
+ class LargeObject
5
+ FILE_END = 2
6
+ PG_PAGE_SIZE = 8 * 1024
7
+
8
+ class AlreadyExists < StandardError
9
+ end
10
+
11
+ autoload :Writer, "umbrellio_utils/large_object/writer"
12
+
13
+ attr_reader :oid
14
+ attr_accessor :str_offset
15
+
16
+ def initialize(oid = -1)
17
+ self.oid = oid
18
+ self.str_offset = 0
19
+ end
20
+
21
+ def create!
22
+ run(:lo_create, oid)
23
+ rescue Sequel::UniqueConstraintViolation
24
+ raise AlreadyExists.new
25
+ end
26
+
27
+ def open_to_write!
28
+ DB.transaction do
29
+ fd = run(:lo_open, oid, 0x60000)
30
+ self.str_offset = run(:lo_lseek, fd, 0, FILE_END)
31
+ end
32
+ end
33
+
34
+ def append!(str)
35
+ run(:lo_put, oid, str_offset, Sequel.blob(str))
36
+ self.str_offset += str.bytesize
37
+ end
38
+
39
+ def read(*)
40
+ run(:lo_get, oid, *)
41
+ end
42
+
43
+ def delete!
44
+ run(:lo_unlink, oid)
45
+ rescue PG::UndefinedObject
46
+ # Ignored
47
+ end
48
+
49
+ def exists?
50
+ DB[:pg_largeobject_metadata].first(oid:).present?
51
+ end
52
+
53
+ private
54
+
55
+ attr_writer :oid
56
+
57
+ def run(method_name, *)
58
+ DB.get(Sequel.function(method_name, *))
59
+ end
60
+ end
61
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UmbrellioUtils
4
- VERSION = "1.13.2"
4
+ VERSION = "1.14.0"
5
5
  end
@@ -72,6 +72,7 @@ require_relative "umbrellio_utils/database"
72
72
  require_relative "umbrellio_utils/formatting"
73
73
  require_relative "umbrellio_utils/http_client"
74
74
  require_relative "umbrellio_utils/jobs"
75
+ require_relative "umbrellio_utils/large_object" if defined?(Sequel)
75
76
  require_relative "umbrellio_utils/migrations"
76
77
  require_relative "umbrellio_utils/misc"
77
78
  require_relative "umbrellio_utils/parsing"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: umbrellio-utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.2
4
+ version: 1.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Team Umbrellio
@@ -61,6 +61,8 @@ files:
61
61
  - lib/umbrellio_utils/formatting.rb
62
62
  - lib/umbrellio_utils/http_client.rb
63
63
  - lib/umbrellio_utils/jobs.rb
64
+ - lib/umbrellio_utils/large_object.rb
65
+ - lib/umbrellio_utils/large_object/writer.rb
64
66
  - lib/umbrellio_utils/migrations.rb
65
67
  - lib/umbrellio_utils/misc.rb
66
68
  - lib/umbrellio_utils/parsing.rb
@@ -100,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
102
  - !ruby/object:Gem::Version
101
103
  version: '0'
102
104
  requirements: []
103
- rubygems_version: 4.0.12
105
+ rubygems_version: 3.6.9
104
106
  specification_version: 4
105
107
  summary: A set of utilities that speed up development
106
108
  test_files: []