tapsoob 0.8.5 → 0.8.7
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 +4 -4
- data/lib/tapsoob/cli/schema.rb +1 -1
- data/lib/tapsoob/schema.rb +33 -10
- data/lib/tapsoob/version.rb +1 -1
- data/spec/integration/postgres_spec.rb +12 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/support/operation_helpers.rb +43 -0
- data/spec/unit/tapsoob/base_spec.rb +222 -0
- data/spec/unit/tapsoob/cli_pipeline_spec.rb +380 -0
- data/spec/unit/tapsoob/config_spec.rb +54 -0
- data/spec/unit/tapsoob/data_stream_spec.rb +48 -0
- data/spec/unit/tapsoob/file_partition_spec.rb +117 -0
- data/spec/unit/tapsoob/keyed_spec.rb +121 -0
- data/spec/unit/tapsoob/progress_event_spec.rb +136 -0
- data/spec/unit/tapsoob/progress_spec.rb +335 -0
- data/spec/unit/tapsoob/pull_spec.rb +335 -0
- data/spec/unit/tapsoob/push_spec.rb +264 -0
- data/spec/unit/tapsoob/schema_spec.rb +154 -0
- data/spec/unit/tapsoob/utils_spec.rb +64 -0
- metadata +11 -1
|
@@ -2,6 +2,20 @@ require 'spec_helper'
|
|
|
2
2
|
require 'tapsoob/schema'
|
|
3
3
|
|
|
4
4
|
RSpec.describe Tapsoob::Schema do
|
|
5
|
+
# SQLite file-based URL helpers — memory: URLs open a fresh DB on each connect,
|
|
6
|
+
# so methods that open their own connection (dump, foreign_keys, indexes, …)
|
|
7
|
+
# must use a file-backed database.
|
|
8
|
+
def with_sqlite_file
|
|
9
|
+
path = File.join(Dir.tmpdir, "tapsoob_schema_#{Process.pid}_#{rand(9999)}.db")
|
|
10
|
+
url = DbHelpers.adapt_url("sqlite://#{path}")
|
|
11
|
+
db = DbHelpers.connect(url)
|
|
12
|
+
db.extension :schema_dumper
|
|
13
|
+
yield url, db
|
|
14
|
+
ensure
|
|
15
|
+
DbHelpers.disconnect_all
|
|
16
|
+
File.delete(path) rescue nil
|
|
17
|
+
end
|
|
18
|
+
|
|
5
19
|
let(:db) do
|
|
6
20
|
d = connect_sqlite
|
|
7
21
|
d.extension :schema_dumper
|
|
@@ -99,4 +113,144 @@ RSpec.describe Tapsoob::Schema do
|
|
|
99
113
|
}.not_to raise_error
|
|
100
114
|
end
|
|
101
115
|
end
|
|
116
|
+
|
|
117
|
+
# ── dump ─────────────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
describe '.dump' do
|
|
120
|
+
it 'returns a migration string covering all tables' do
|
|
121
|
+
with_sqlite_file do |url, tmp|
|
|
122
|
+
tmp.create_table(:things) { primary_key :id; String :name }
|
|
123
|
+
result = described_class.dump(url)
|
|
124
|
+
expect(result).to include('Sequel::Migration')
|
|
125
|
+
expect(result).to include('things')
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it 'includes both up and down blocks' do
|
|
130
|
+
with_sqlite_file do |url, tmp|
|
|
131
|
+
tmp.create_table(:items) { primary_key :id }
|
|
132
|
+
result = described_class.dump(url)
|
|
133
|
+
expect(result).to include('def up')
|
|
134
|
+
expect(result).to include('def down')
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# ── foreign_keys ─────────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
describe '.foreign_keys' do
|
|
142
|
+
it 'returns a string (even when there are no FK constraints)' do
|
|
143
|
+
with_sqlite_file do |url, _|
|
|
144
|
+
result = described_class.foreign_keys(url)
|
|
145
|
+
expect(result).to be_a(String)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# ── indexes ──────────────────────────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
describe '.indexes' do
|
|
153
|
+
it 'returns a string' do
|
|
154
|
+
with_sqlite_file do |url, tmp|
|
|
155
|
+
tmp.create_table(:idx_things) { primary_key :id; String :slug }
|
|
156
|
+
tmp.add_index(:idx_things, :slug)
|
|
157
|
+
result = described_class.indexes(url)
|
|
158
|
+
expect(result).to be_a(String)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# ── load via URL ─────────────────────────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
describe '.load (URL path)' do
|
|
166
|
+
it 'creates the table when passed a URL string' do
|
|
167
|
+
with_sqlite_file do |url, tmp|
|
|
168
|
+
schema_str = described_class.dump_table(db, :articles, {})
|
|
169
|
+
described_class.load(url, schema_str)
|
|
170
|
+
expect(tmp.table_exists?(:articles)).to be true
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'drops then recreates table when drop: true and passed a URL' do
|
|
175
|
+
with_sqlite_file do |url, tmp|
|
|
176
|
+
schema_str = described_class.dump_table(db, :articles, {})
|
|
177
|
+
described_class.load(url, schema_str)
|
|
178
|
+
described_class.load(url, schema_str, drop: true)
|
|
179
|
+
expect(tmp.table_exists?(:articles)).to be true
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# ── load_indexes ─────────────────────────────────────────────────────────────
|
|
185
|
+
|
|
186
|
+
describe '.load_indexes' do
|
|
187
|
+
it 'applies an index migration without error' do
|
|
188
|
+
with_sqlite_file do |url, tmp|
|
|
189
|
+
tmp.create_table(:things) { primary_key :id; String :slug }
|
|
190
|
+
index_migration = <<~RUBY
|
|
191
|
+
Class.new(Sequel::Migration) do
|
|
192
|
+
def up
|
|
193
|
+
add_index :things, :slug
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
RUBY
|
|
197
|
+
expect { described_class.load_indexes(url, index_migration) }.not_to raise_error
|
|
198
|
+
expect(tmp.indexes(:things)).to have_key(:things_slug_index)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# ── load_foreign_keys ────────────────────────────────────────────────────────
|
|
204
|
+
|
|
205
|
+
describe '.load_foreign_keys' do
|
|
206
|
+
it 'applies a foreign key migration without error' do
|
|
207
|
+
with_sqlite_file do |url, tmp|
|
|
208
|
+
tmp.create_table(:parents) { primary_key :id }
|
|
209
|
+
tmp.create_table(:children) { primary_key :id; Integer :parent_id }
|
|
210
|
+
fk_migration = <<~RUBY
|
|
211
|
+
Class.new(Sequel::Migration) do
|
|
212
|
+
def up
|
|
213
|
+
alter_table(:children) { add_foreign_key [:parent_id], :parents }
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
RUBY
|
|
217
|
+
expect { described_class.load_foreign_keys(url, fk_migration) }.not_to raise_error
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# ── rewrite_non_integer_primary_keys ─────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
describe '.rewrite_non_integer_primary_keys' do
|
|
225
|
+
it 'leaves integer primary keys unchanged' do
|
|
226
|
+
schema = ' primary_key :id, :type=>"integer"'
|
|
227
|
+
expect(described_class.rewrite_non_integer_primary_keys(schema)).to eq(schema)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'leaves bigint primary keys unchanged' do
|
|
231
|
+
schema = ' primary_key :id, :type=>"bigint"'
|
|
232
|
+
expect(described_class.rewrite_non_integer_primary_keys(schema)).to eq(schema)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it 'rewrites varchar primary keys to column form' do
|
|
236
|
+
schema = ' primary_key :code, :type=>"varchar(10)"'
|
|
237
|
+
result = described_class.rewrite_non_integer_primary_keys(schema)
|
|
238
|
+
expect(result).to include('column :code')
|
|
239
|
+
expect(result).to include('"varchar(10)"')
|
|
240
|
+
expect(result).to include('primary_key: true')
|
|
241
|
+
expect(result).not_to include('primary_key :code,')
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it 'rewrites uuid primary keys to column form' do
|
|
245
|
+
schema = ' primary_key :id, :type=>"uuid"'
|
|
246
|
+
result = described_class.rewrite_non_integer_primary_keys(schema)
|
|
247
|
+
expect(result).to include('column :id')
|
|
248
|
+
expect(result).to include('primary_key: true')
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it 'passes through schema with no primary_key lines unchanged' do
|
|
252
|
+
schema = " String :name, size: 50\n Integer :score"
|
|
253
|
+
expect(described_class.rewrite_non_integer_primary_keys(schema)).to eq(schema)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
102
256
|
end
|
|
@@ -220,6 +220,70 @@ RSpec.describe Tapsoob::Utils do
|
|
|
220
220
|
end
|
|
221
221
|
end
|
|
222
222
|
|
|
223
|
+
# ── windows? / bin ───────────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
describe '.windows? / .bin' do
|
|
226
|
+
it 'returns a boolean for windows?' do
|
|
227
|
+
expect([true, false]).to include(described_class.windows?)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'returns the command unchanged on non-Windows' do
|
|
231
|
+
allow(described_class).to receive(:windows?).and_return(false)
|
|
232
|
+
expect(described_class.bin("mytool")).to eq("mytool")
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it 'appends .cmd on Windows' do
|
|
236
|
+
allow(described_class).to receive(:windows?).and_return(true)
|
|
237
|
+
expect(described_class.bin("mytool")).to eq("mytool.cmd")
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# ── incorrect_blobs ──────────────────────────────────────────────────────────
|
|
242
|
+
|
|
243
|
+
describe '.incorrect_blobs' do
|
|
244
|
+
let(:db) do
|
|
245
|
+
d = connect_sqlite
|
|
246
|
+
d.create_table(:blob_test) { primary_key :id; File :data; String :name }
|
|
247
|
+
d
|
|
248
|
+
end
|
|
249
|
+
after { db.disconnect }
|
|
250
|
+
|
|
251
|
+
it 'returns blob-typed column names' do
|
|
252
|
+
expect(described_class.incorrect_blobs(db, :blob_test)).to include(:data)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it 'does not include non-blob columns' do
|
|
256
|
+
expect(described_class.incorrect_blobs(db, :blob_test)).not_to include(:name)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# ── encode_blobs ASCII-8BIT branch ──────────────────────────────────────────
|
|
261
|
+
|
|
262
|
+
describe '.encode_blobs (ASCII-8BIT branch)' do
|
|
263
|
+
it 'encodes raw binary strings that are not Sequel::SQL::Blob' do
|
|
264
|
+
raw = "binary".force_encoding(Encoding::ASCII_8BIT)
|
|
265
|
+
row = { data: raw }
|
|
266
|
+
described_class.encode_blobs(row, [:data])
|
|
267
|
+
expect(row[:data]).to eq(described_class.base64encode(raw))
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# ── load_schema with a DB object ─────────────────────────────────────────────
|
|
272
|
+
|
|
273
|
+
describe '.load_schema' do
|
|
274
|
+
let(:dir) { Dir.mktmpdir }
|
|
275
|
+
after { FileUtils.rm_rf(dir) }
|
|
276
|
+
|
|
277
|
+
it 'accepts a Sequel::Database object directly' do
|
|
278
|
+
db = connect_sqlite
|
|
279
|
+
FileUtils.mkdir_p(File.join(dir, 'schemas'))
|
|
280
|
+
schema_content = "Sequel.migration { change { create_table(:load_test) { primary_key :id } } }"
|
|
281
|
+
File.write(File.join(dir, 'schemas', 'load_test.rb'), schema_content)
|
|
282
|
+
expect { described_class.load_schema(dir, db, :load_test) }.not_to raise_error
|
|
283
|
+
db.disconnect
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
223
287
|
# ── export_rows / export_schema / export_indexes (filesystem) ────────────────
|
|
224
288
|
|
|
225
289
|
describe 'filesystem export helpers' do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tapsoob
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Félix Bellanger
|
|
@@ -131,11 +131,21 @@ files:
|
|
|
131
131
|
- spec/spec_helper.rb
|
|
132
132
|
- spec/support/db_helpers.rb
|
|
133
133
|
- spec/support/fixtures.rb
|
|
134
|
+
- spec/support/operation_helpers.rb
|
|
134
135
|
- spec/support/round_trip_helper.rb
|
|
135
136
|
- spec/support/shared_examples/round_trip.rb
|
|
137
|
+
- spec/unit/tapsoob/base_spec.rb
|
|
136
138
|
- spec/unit/tapsoob/chunksize_spec.rb
|
|
139
|
+
- spec/unit/tapsoob/cli_pipeline_spec.rb
|
|
140
|
+
- spec/unit/tapsoob/config_spec.rb
|
|
137
141
|
- spec/unit/tapsoob/data_stream_spec.rb
|
|
142
|
+
- spec/unit/tapsoob/file_partition_spec.rb
|
|
143
|
+
- spec/unit/tapsoob/keyed_spec.rb
|
|
138
144
|
- spec/unit/tapsoob/operation_base_spec.rb
|
|
145
|
+
- spec/unit/tapsoob/progress_event_spec.rb
|
|
146
|
+
- spec/unit/tapsoob/progress_spec.rb
|
|
147
|
+
- spec/unit/tapsoob/pull_spec.rb
|
|
148
|
+
- spec/unit/tapsoob/push_spec.rb
|
|
139
149
|
- spec/unit/tapsoob/schema_spec.rb
|
|
140
150
|
- spec/unit/tapsoob/utils_spec.rb
|
|
141
151
|
- spec/unit/tapsoob/version_spec.rb
|