simple-sql 0.2.10 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/simple/sql.rb +7 -6
- data/lib/simple/sql/duplicate.rb +26 -74
- data/lib/simple/sql/version.rb +1 -1
- data/spec/simple/sql_duplicate_spec.rb +5 -5
- data/spec/simple/sql_insert_spec.rb +5 -0
- data/spec/support/001_database.rb +0 -9
- data/spec/support/factories/user_factory.rb +2 -8
- data/spec/support/model/user.rb +0 -3
- metadata +2 -4
- data/spec/simple/sql_duplicate_unique_spec.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c57a6e1295b2ce84040e5e0f8167aa83d367e0cf
|
4
|
+
data.tar.gz: 10527d7193cc63784a21ce703427f6e111fc9e39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9254b98c19843789d4ec814047316caefe96a020c3393d686ba5dcc4faac2aafcab638d01f1a04dce4286e676674a55fc7d5668d965a3452c68e80330e836ff
|
7
|
+
data.tar.gz: 3e662b58ff18e2608f3005d8f53c55e445dce91d8cd02011dcde2292d461e264b93bf0cabc7b54d12ec6df9ad84e11ade46bff5021f5e20c3d5c041a5a85d8d0
|
data/Gemfile.lock
CHANGED
data/lib/simple/sql.rb
CHANGED
@@ -25,12 +25,13 @@ module Simple
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def default_logger
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
if defined?(ActiveRecord)
|
29
|
+
ActiveRecord::Base.logger
|
30
|
+
else
|
31
|
+
logger = Logger.new(STDERR)
|
32
|
+
logger.level = Logger::INFO
|
33
|
+
logger
|
34
|
+
end
|
34
35
|
end
|
35
36
|
|
36
37
|
# execute one or more sql statements. This method does not allow to pass in
|
data/lib/simple/sql/duplicate.rb
CHANGED
@@ -1,89 +1,41 @@
|
|
1
|
-
# rubocop:disable
|
1
|
+
# rubocop:disable Metrics/MethodLength
|
2
|
+
# rubocop:disable Metrics/AbcSize
|
2
3
|
|
3
4
|
module Simple
|
4
5
|
module SQL
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def fragment(str)
|
9
|
-
Fragment.new(str)
|
10
|
-
end
|
11
|
-
|
12
|
-
#
|
13
|
-
# Creates duplicates of record in a table.
|
14
|
-
#
|
15
|
-
# This method handles timestamp columns (these will be set to the current
|
16
|
-
# time) and primary keys (will be set to NULL.) You can pass in overrides
|
17
|
-
# as a third argument for specific columns.
|
18
|
-
#
|
19
|
-
# Parameters:
|
20
|
-
#
|
21
|
-
# - ids: (Integer, Array<Integer>) primary key ids
|
22
|
-
# - overrides: Hash[column_names => SQL::Fragment]
|
23
|
-
#
|
24
|
-
def duplicate(table, ids, overrides = {})
|
6
|
+
def duplicate(table, ids, except: [])
|
25
7
|
ids = Array(ids)
|
26
8
|
return [] if ids.empty?
|
27
9
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
class Duplicator
|
32
|
-
attr_reader :table_name, :custom_overrides
|
33
|
-
|
34
|
-
def initialize(table_name, overrides)
|
35
|
-
@table_name = table_name
|
36
|
-
@custom_overrides = validated_overrides(overrides)
|
37
|
-
end
|
38
|
-
|
39
|
-
def call(ids)
|
40
|
-
Simple::SQL.all query, ids
|
41
|
-
rescue PG::UndefinedColumn => e
|
42
|
-
raise ArgumentError, e.message
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
# This stringify all keys of the overrides hash, and verifies that
|
48
|
-
# all values in there are SQL::Fragments
|
49
|
-
def validated_overrides(overrides)
|
50
|
-
overrides.inject({}) do |hsh, (key, value)|
|
51
|
-
raise ArgumentError, "Unknown value #{value.inspect}" unless value.is_a?(Fragment)
|
52
|
-
hsh.update key.to_s => value.to_sql
|
53
|
-
end
|
54
|
-
end
|
10
|
+
timestamp_columns = Reflection.timestamp_columns(table)
|
11
|
+
primary_key_columns = Reflection.primary_key_columns(table)
|
55
12
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
13
|
+
# duplicate all columns in the table that need to be SELECTed.
|
14
|
+
#
|
15
|
+
columns_to_dupe = Reflection.columns(table)
|
61
16
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
end
|
17
|
+
# Primary keys will not be selected from the table, they should be set
|
18
|
+
# automatically by the database, via a DEFAULT role on the column.
|
19
|
+
columns_to_dupe -= primary_key_columns
|
67
20
|
|
68
|
-
#
|
69
|
-
|
70
|
-
|
21
|
+
# timestamp_columns will not be selected from the table, they will be
|
22
|
+
# set to now() explicitely.
|
23
|
+
columns_to_dupe -= timestamp_columns
|
71
24
|
|
72
|
-
|
73
|
-
|
74
|
-
|
25
|
+
# If some other columns must be excluded they have to be added in the
|
26
|
+
# except: keyword argument. This is helpful for UNIQUE columns, but
|
27
|
+
# a column which is supposed to be UNIQUE and NOT NULL can not be dealt
|
28
|
+
# with.
|
29
|
+
columns_to_dupe -= except.map(&:to_s)
|
75
30
|
|
76
|
-
|
77
|
-
|
78
|
-
|
31
|
+
# build query
|
32
|
+
select_columns = columns_to_dupe + timestamp_columns
|
33
|
+
select_values = columns_to_dupe + timestamp_columns.map { |col| "now() AS #{col}" }
|
79
34
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
WHERE id = ANY($1) RETURNING id
|
85
|
-
SQL
|
86
|
-
end
|
35
|
+
Simple::SQL.all <<~SQL, ids
|
36
|
+
INSERT INTO #{table}(#{select_columns.join(', ')})
|
37
|
+
SELECT #{select_values.join(', ')} FROM #{table} WHERE id = ANY($1) RETURNING id
|
38
|
+
SQL
|
87
39
|
end
|
88
40
|
end
|
89
41
|
end
|
data/lib/simple/sql/version.rb
CHANGED
@@ -10,24 +10,24 @@ describe "Simple::SQL.duplicate" do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
it "does not fail on a non-existing user" do
|
13
|
-
dupe_ids = SQL.duplicate "users",
|
13
|
+
dupe_ids = SQL.duplicate "users", source_ids.first
|
14
14
|
|
15
|
-
expect(dupe_ids.length).to eq(
|
16
|
-
expect(SQL.ask("SELECT COUNT(*) FROM users")).to eq(
|
15
|
+
expect(dupe_ids.length).to eq(1)
|
16
|
+
expect(SQL.ask("SELECT COUNT(*) FROM users")).to eq(3)
|
17
17
|
end
|
18
18
|
|
19
19
|
it "duplicates a single user" do
|
20
20
|
dupe_ids = SQL.duplicate "users", source_ids.first
|
21
21
|
|
22
22
|
expect(dupe_ids.length).to eq(1)
|
23
|
-
expect(SQL.ask("SELECT COUNT(*) FROM users")).to eq(
|
23
|
+
expect(SQL.ask("SELECT COUNT(*) FROM users")).to eq(3)
|
24
24
|
end
|
25
25
|
|
26
26
|
it "duplicates many users" do
|
27
27
|
dupe_ids = SQL.duplicate "users", (source_ids + [ -10 ])
|
28
28
|
|
29
29
|
expect(dupe_ids.length).to eq(2)
|
30
|
-
expect(SQL.ask("SELECT COUNT(*) FROM users")).to eq(
|
30
|
+
expect(SQL.ask("SELECT COUNT(*) FROM users")).to eq(4)
|
31
31
|
end
|
32
32
|
|
33
33
|
it "updates the timestamp columns" do
|
@@ -15,6 +15,11 @@ describe "Simple::SQL.insert" do
|
|
15
15
|
expect(user.first_name).to eq("foo")
|
16
16
|
expect(user.last_name).to eq("bar")
|
17
17
|
expect(user.created_at).to be_a(Time)
|
18
|
+
|
19
|
+
#
|
20
|
+
# r = SQL.record("SELECT COUNT(*) AS count FROM users")
|
21
|
+
# r = SQL.record("SELECT COUNT(*) AS count FROM users")
|
22
|
+
# expect(r).to eq({count: 2})
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
@@ -35,13 +35,4 @@ ActiveRecord::Schema.define do
|
|
35
35
|
|
36
36
|
t.timestamps null: true
|
37
37
|
end
|
38
|
-
|
39
|
-
create_table :unique_users, force: true do |t|
|
40
|
-
t.string :first_name
|
41
|
-
t.string :last_name
|
42
|
-
end
|
43
|
-
|
44
|
-
execute <<-SQL
|
45
|
-
CREATE UNIQUE INDEX unique_users_ix1 ON unique_users(first_name, last_name)
|
46
|
-
SQL
|
47
38
|
end
|
@@ -1,14 +1,8 @@
|
|
1
1
|
FactoryGirl.define do
|
2
2
|
factory :user do
|
3
3
|
role_id 123
|
4
|
-
|
5
|
-
|
6
|
-
sequence :last_name do |n| "Last #{n}" end
|
4
|
+
first_name "Uni"
|
5
|
+
last_name "Corn"
|
7
6
|
access_level "viewable"
|
8
7
|
end
|
9
|
-
|
10
|
-
factory :unique_user do
|
11
|
-
sequence :first_name do |n| "First #{n}" end
|
12
|
-
sequence :last_name do |n| "Last #{n}" end
|
13
|
-
end
|
14
8
|
end
|
data/spec/support/model/user.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple-sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-02-
|
12
|
+
date: 2018-02-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pg_array_parser
|
@@ -198,7 +198,6 @@ files:
|
|
198
198
|
- spec/simple/sql_config_spec.rb
|
199
199
|
- spec/simple/sql_conversion_spec.rb
|
200
200
|
- spec/simple/sql_duplicate_spec.rb
|
201
|
-
- spec/simple/sql_duplicate_unique_spec.rb
|
202
201
|
- spec/simple/sql_insert_spec.rb
|
203
202
|
- spec/simple/sql_record_spec.rb
|
204
203
|
- spec/simple/sql_reflection_spec.rb
|
@@ -239,7 +238,6 @@ test_files:
|
|
239
238
|
- spec/simple/sql_config_spec.rb
|
240
239
|
- spec/simple/sql_conversion_spec.rb
|
241
240
|
- spec/simple/sql_duplicate_spec.rb
|
242
|
-
- spec/simple/sql_duplicate_unique_spec.rb
|
243
241
|
- spec/simple/sql_insert_spec.rb
|
244
242
|
- spec/simple/sql_record_spec.rb
|
245
243
|
- spec/simple/sql_reflection_spec.rb
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe "Simple::SQL.duplicate/unique indices" do
|
4
|
-
let!(:unique_users) { 1.upto(USER_COUNT).map { create(:unique_user) } }
|
5
|
-
|
6
|
-
let!(:source_ids) { SQL.all("SELECT id FROM unique_users") }
|
7
|
-
|
8
|
-
it "cannot duplicate unique_user" do
|
9
|
-
expect {
|
10
|
-
SQL.duplicate "unique_users", source_ids
|
11
|
-
}.to raise_error(PG::UniqueViolation)
|
12
|
-
end
|
13
|
-
|
14
|
-
it "raises an ArgumentError when called with unknown columns" do
|
15
|
-
expect {
|
16
|
-
SQL.duplicate "unique_users", source_ids, foo: SQL.fragment("baz")
|
17
|
-
}.to raise_error(ArgumentError)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "raises an ArgumentError when called with invalid overrides" do
|
21
|
-
expect {
|
22
|
-
SQL.duplicate "unique_users", source_ids, first_name: "I am invalid"
|
23
|
-
}.to raise_error(ArgumentError)
|
24
|
-
end
|
25
|
-
|
26
|
-
it "duplicates unique_users" do
|
27
|
-
overrides = {
|
28
|
-
first_name: SQL.fragment("first_name || '.' || id"),
|
29
|
-
last_name: SQL.fragment("last_name || '.' || id")
|
30
|
-
}
|
31
|
-
|
32
|
-
dupe_ids = SQL.duplicate "unique_users", source_ids, overrides
|
33
|
-
|
34
|
-
expect(dupe_ids.length).to eq(2)
|
35
|
-
expect(SQL.ask("SELECT COUNT(*) FROM unique_users")).to eq(4)
|
36
|
-
end
|
37
|
-
end
|