baza 0.0.20 → 0.0.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +84 -0
- data/.rubocop_todo.yml +17 -135
- data/.travis.yml +21 -0
- data/Gemfile +10 -7
- data/Gemfile.lock +39 -44
- data/README.md +61 -3
- data/VERSION +1 -1
- data/baza.gemspec +146 -98
- data/config/best_project_practice_rubocop.yml +8 -0
- data/config/best_project_practice_rubocop_todo.yml +6 -0
- data/lib/baza.rb +8 -12
- data/lib/baza/base_sql_driver.rb +198 -52
- data/lib/baza/cloner.rb +1 -0
- data/lib/baza/column.rb +26 -0
- data/lib/baza/database.rb +19 -3
- data/lib/baza/db.rb +69 -271
- data/lib/baza/driver.rb +1 -6
- data/lib/baza/{drivers → driver}/active_record.rb +65 -21
- data/lib/baza/{drivers → driver}/active_record/columns.rb +0 -0
- data/lib/baza/driver/active_record/commands.rb +10 -0
- data/lib/baza/driver/active_record/databases.rb +10 -0
- data/lib/baza/{drivers → driver}/active_record/indexes.rb +0 -0
- data/lib/baza/{drivers → driver}/active_record/result.rb +3 -1
- data/lib/baza/{drivers → driver}/active_record/tables.rb +0 -0
- data/lib/baza/driver/active_record/users.rb +12 -0
- data/lib/baza/{drivers → driver}/mysql.rb +9 -26
- data/lib/baza/{drivers → driver}/mysql/column.rb +14 -35
- data/lib/baza/{drivers → driver}/mysql/columns.rb +9 -12
- data/lib/baza/driver/mysql/commands.rb +39 -0
- data/lib/baza/driver/mysql/database.rb +64 -0
- data/lib/baza/driver/mysql/databases.rb +63 -0
- data/lib/baza/{drivers → driver}/mysql/index.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql/indexes.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql/result.rb +15 -7
- data/lib/baza/{drivers → driver}/mysql/sqlspecs.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql/table.rb +27 -43
- data/lib/baza/{drivers → driver}/mysql/tables.rb +5 -34
- data/lib/baza/{drivers → driver}/mysql/unbuffered_result.rb +8 -2
- data/lib/baza/driver/mysql/user.rb +22 -0
- data/lib/baza/driver/mysql/users.rb +39 -0
- data/lib/baza/{drivers → driver}/mysql2.rb +19 -49
- data/lib/baza/{drivers → driver}/mysql2/column.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql2/columns.rb +0 -0
- data/lib/baza/driver/mysql2/commands.rb +2 -0
- data/lib/baza/{drivers → driver}/mysql2/database.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql2/databases.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql2/index.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql2/indexes.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql2/result.rb +3 -1
- data/lib/baza/{drivers → driver}/mysql2/table.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql2/tables.rb +0 -0
- data/lib/baza/driver/mysql2/user.rb +2 -0
- data/lib/baza/driver/mysql2/users.rb +2 -0
- data/lib/baza/{drivers → driver}/mysql_java.rb +60 -38
- data/lib/baza/{drivers → driver}/mysql_java/column.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql_java/columns.rb +0 -0
- data/lib/baza/driver/mysql_java/commands.rb +2 -0
- data/lib/baza/driver/mysql_java/database.rb +2 -0
- data/lib/baza/driver/mysql_java/databases.rb +2 -0
- data/lib/baza/{drivers → driver}/mysql_java/index.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql_java/indexes.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql_java/table.rb +0 -0
- data/lib/baza/{drivers → driver}/mysql_java/tables.rb +0 -0
- data/lib/baza/driver/mysql_java/user.rb +2 -0
- data/lib/baza/driver/mysql_java/users.rb +2 -0
- data/lib/baza/driver/pg.rb +80 -0
- data/lib/baza/driver/pg/column.rb +125 -0
- data/lib/baza/driver/pg/columns.rb +37 -0
- data/lib/baza/driver/pg/commands.rb +35 -0
- data/lib/baza/driver/pg/create_index_sql_creator.rb +51 -0
- data/lib/baza/driver/pg/database.rb +89 -0
- data/lib/baza/driver/pg/databases.rb +79 -0
- data/lib/baza/driver/pg/index.rb +35 -0
- data/lib/baza/driver/pg/indexes.rb +5 -0
- data/lib/baza/driver/pg/result.rb +139 -0
- data/lib/baza/driver/pg/table.rb +184 -0
- data/lib/baza/driver/pg/tables.rb +45 -0
- data/lib/baza/{drivers → driver}/sqlite3.rb +6 -24
- data/lib/baza/{drivers → driver}/sqlite3/column.rb +22 -24
- data/lib/baza/{drivers → driver}/sqlite3/columns.rb +6 -6
- data/lib/baza/driver/sqlite3/commands.rb +28 -0
- data/lib/baza/{drivers → driver}/sqlite3/database.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3/databases.rb +0 -1
- data/lib/baza/{drivers → driver}/sqlite3/index.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3/indexes.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3/result.rb +14 -6
- data/lib/baza/{drivers → driver}/sqlite3/sqlspecs.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3/table.rb +25 -16
- data/lib/baza/{drivers → driver}/sqlite3/tables.rb +5 -6
- data/lib/baza/{drivers → driver}/sqlite3/unbuffered_result.rb +8 -2
- data/lib/baza/{drivers → driver}/sqlite3_java.rb +13 -23
- data/lib/baza/{drivers → driver}/sqlite3_java/column.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3_java/columns.rb +0 -0
- data/lib/baza/driver/sqlite3_java/commands.rb +2 -0
- data/lib/baza/{drivers → driver}/sqlite3_java/database.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3_java/index.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3_java/indexes.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3_java/table.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3_java/tables.rb +0 -0
- data/lib/baza/{drivers → driver}/sqlite3_java/unbuffered_result.rb +14 -9
- data/lib/baza/{drivers → driver}/sqlite3_rhodes.rb +6 -24
- data/lib/baza/errors.rb +2 -0
- data/lib/baza/idquery.rb +15 -8
- data/lib/baza/index.rb +7 -0
- data/lib/baza/jdbc_driver.rb +4 -16
- data/lib/baza/jdbc_result.rb +20 -12
- data/lib/baza/mysql_base_driver.rb +7 -7
- data/lib/baza/query_buffer.rb +20 -19
- data/lib/baza/row.rb +16 -16
- data/lib/baza/sql_queries.rb +3 -0
- data/lib/baza/sql_queries/generic_insert.rb +81 -0
- data/lib/baza/sql_queries/generic_update.rb +31 -0
- data/lib/baza/sql_queries/mysql_upsert.rb +52 -0
- data/lib/baza/sql_queries/mysql_upsert_duplicate_key.rb +57 -0
- data/lib/baza/sql_queries/non_atomic_upsert.rb +25 -0
- data/lib/baza/sql_queries/postgres_upsert_duplicate_key.rb +118 -0
- data/lib/baza/sql_queries/select.rb +170 -0
- data/lib/baza/sql_queries/sqlite_upsert_duplicate_key.rb +99 -0
- data/lib/baza/table.rb +35 -8
- data/spec/active_record/models/user.rb +3 -0
- data/spec/{cloner_spec.rb → baza/cloner_spec.rb} +0 -0
- data/spec/drivers/active_record_mysql2_spec.rb +5 -3
- data/spec/drivers/active_record_mysql_spec.rb +2 -1
- data/spec/drivers/active_record_pg_spec.rb +20 -0
- data/spec/drivers/active_record_sqlite3_spec.rb +2 -1
- data/spec/drivers/mysql2_spec.rb +1 -1
- data/spec/drivers/mysql_spec.rb +10 -10
- data/spec/drivers/pg_spec.rb +18 -0
- data/spec/drivers/sqlite3_spec.rb +7 -8
- data/spec/info_active_record_example.rb +1 -1
- data/spec/{info_active_record_mysql2.rb → info_active_record_mysql2_example.rb} +3 -2
- data/spec/info_active_record_mysql2_travis.rb +35 -0
- data/spec/{info_active_record_mysql.rb → info_active_record_mysql_example.rb} +5 -4
- data/spec/info_active_record_mysql_travis.rb +36 -0
- data/spec/info_active_record_pg_example.rb +36 -0
- data/spec/info_active_record_pg_travis.rb +34 -0
- data/spec/info_active_record_sqlite3.rb +1 -1
- data/spec/info_mysql2_example.rb +1 -3
- data/spec/{info_mysql2_shippable.rb → info_mysql2_travis.rb} +2 -4
- data/spec/info_mysql_example.rb +1 -3
- data/spec/{info_mysql_shippable.rb → info_mysql_travis.rb} +2 -4
- data/spec/info_pg_example.rb +22 -0
- data/spec/info_pg_travis.rb +20 -0
- data/spec/info_sqlite3.rb +1 -3
- data/spec/spec_helper.rb +1 -1
- data/spec/support/driver_active_record_collection.rb +62 -0
- data/spec/support/driver_collection.rb +136 -121
- data/spec/support/driver_columns_collection.rb +19 -10
- data/spec/support/driver_databases_collection.rb +23 -1
- data/spec/support/driver_indexes_collection.rb +2 -2
- data/spec/support/driver_tables_collection.rb +24 -4
- data/spec/support/driver_users_collection.rb +53 -0
- metadata +185 -104
- data/lib/baza/drivers/mysql/database.rb +0 -28
- data/lib/baza/drivers/mysql/databases.rb +0 -35
- data/lib/baza/drivers/mysql_java/database.rb +0 -2
- data/lib/baza/drivers/mysql_java/databases.rb +0 -2
- data/lib/baza/model.rb +0 -875
- data/lib/baza/model_custom.rb +0 -155
- data/lib/baza/model_handler.rb +0 -910
- data/lib/baza/model_handler_sqlhelper.rb +0 -484
- data/lib/baza/revision.rb +0 -383
- data/shippable.yml +0 -17
- data/spec/info_active_record_mysql2_shippable.rb +0 -34
- data/spec/info_active_record_mysql_shippable.rb +0 -34
- data/spec/model_handler_spec.rb +0 -431
data/lib/baza/row.rb
CHANGED
@@ -13,24 +13,24 @@ class Baza::Row
|
|
13
13
|
@args[key.to_sym] = value
|
14
14
|
end
|
15
15
|
|
16
|
-
@args[:objects] = $objects if !@args[:objects] && $objects && $objects.is_a?(Baza::ModelHandler)
|
17
16
|
@args[:col_id] ||= :id
|
18
17
|
raise "No table given." unless @args[:table]
|
19
18
|
|
20
19
|
if @args[:data] && (@args[:data].is_a?(Integer) || @args[:data].is_a?(Fixnum) || @args[:data].is_a?(String))
|
21
20
|
@data = {@args[:col_id].to_sym => @args[:data].to_s}
|
22
21
|
reload
|
23
|
-
elsif @args[:data] && @args
|
22
|
+
elsif @args[:data] && @args.fetch(:data).is_a?(Hash)
|
24
23
|
@data = {}
|
25
|
-
@args
|
26
|
-
|
24
|
+
@args.fetch(:data).each do |key, value|
|
25
|
+
key = key.to_sym unless key.is_a?(Fixnum)
|
26
|
+
@data[key] = value
|
27
27
|
end
|
28
28
|
elsif @args[:id]
|
29
29
|
@data = {}
|
30
30
|
@data[@args[:col_id].to_sym] = @args[:id]
|
31
31
|
reload
|
32
32
|
else
|
33
|
-
raise ArgumentError
|
33
|
+
raise ArgumentError, "Invalid data: #{@args[:data]} (#{@args[:data].class})"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -43,7 +43,7 @@ class Baza::Row
|
|
43
43
|
false
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
alias objects ob
|
47
47
|
|
48
48
|
def reload
|
49
49
|
last_id = id
|
@@ -59,14 +59,14 @@ class Baza::Row
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def update(newdata)
|
62
|
-
db.update(@args
|
62
|
+
db.update(@args.fetch(:table), newdata, @args.fetch(:col_id) => id)
|
63
63
|
reload
|
64
64
|
|
65
65
|
ob.call("object" => self, "signal" => "update") if ob
|
66
66
|
end
|
67
67
|
|
68
68
|
def delete
|
69
|
-
db.delete(@args
|
69
|
+
db.delete(@args.fetch(:table), @args.fetch(:col_id) => id)
|
70
70
|
destroy
|
71
71
|
end
|
72
72
|
|
@@ -100,7 +100,7 @@ class Baza::Row
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def id
|
103
|
-
@data
|
103
|
+
@data.fetch(@args.fetch(:col_id))
|
104
104
|
end
|
105
105
|
|
106
106
|
def to_param
|
@@ -108,18 +108,18 @@ class Baza::Row
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def title
|
111
|
-
return @data[@args
|
111
|
+
return @data[@args.fetch(:col_title).to_sym] if @args[:col_title]
|
112
112
|
|
113
113
|
if @data.key?(:title)
|
114
|
-
return @data
|
114
|
+
return @data.fetch(:title)
|
115
115
|
elsif @data.key?(:name)
|
116
|
-
return @data
|
116
|
+
return @data.fetch(:name)
|
117
117
|
end
|
118
118
|
|
119
119
|
raise "'col_title' has not been set for the class: '#{self.class}'."
|
120
120
|
end
|
121
121
|
|
122
|
-
|
122
|
+
alias name title
|
123
123
|
|
124
124
|
def each(*args, &blk)
|
125
125
|
@data.each(*args, &blk)
|
@@ -138,10 +138,10 @@ class Baza::Row
|
|
138
138
|
end
|
139
139
|
|
140
140
|
def method_missing(func_name, *args)
|
141
|
-
if match = func_name.to_s.match(/^(\S+)\?$/) && @data.key?(match[1].to_sym)
|
142
|
-
if @data
|
141
|
+
if (match = func_name.to_s.match(/^(\S+)\?$/)) && @data.key?(match[1].to_sym)
|
142
|
+
if @data.fetch(match[1].to_sym) == "1" || @data.fetch(match[1].to_sym) == "yes"
|
143
143
|
return true
|
144
|
-
elsif @data
|
144
|
+
elsif @data.fetch(match[1].to_sym) == "0" || @data.fetch(match[1].to_sym) == "no"
|
145
145
|
return false
|
146
146
|
end
|
147
147
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
class Baza::SqlQueries::GenericInsert
|
2
|
+
def initialize(args)
|
3
|
+
@db = args.fetch(:db)
|
4
|
+
@table_name = args.fetch(:table_name)
|
5
|
+
@data = args.fetch(:data)
|
6
|
+
@buffer = args[:buffer]
|
7
|
+
@return_sql = args[:return_sql]
|
8
|
+
@return_id = args[:return_id]
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
if @return_sql
|
13
|
+
to_sql
|
14
|
+
elsif @buffer
|
15
|
+
@buffer.query(to_sql)
|
16
|
+
else
|
17
|
+
@db.query(to_sql)
|
18
|
+
@db.last_id if @return_id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_sql
|
23
|
+
sql = "INSERT INTO #{@db.sep_table}#{@db.escape_table(@table_name)}#{@db.sep_table}"
|
24
|
+
|
25
|
+
if !@data || @data.empty?
|
26
|
+
sql << " #{sql_default_values}"
|
27
|
+
else
|
28
|
+
sql << " #{sql_columns} VALUES #{sql_values}"
|
29
|
+
end
|
30
|
+
|
31
|
+
sql
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def sql_default_values
|
37
|
+
if @db.opts.fetch(:type).to_s.include?("mysql")
|
38
|
+
"VALUES ()" # This is the correct syntax for inserting a blank row in MySQL.
|
39
|
+
elsif @db.opts.fetch(:type).to_s.include?("sqlite3")
|
40
|
+
"DEFAULT VALUES"
|
41
|
+
else
|
42
|
+
raise "Unknown database-type: '#{@db.opts.fetch(:type)}'."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def sql_columns
|
47
|
+
sql = "("
|
48
|
+
|
49
|
+
first = true
|
50
|
+
@data.each_key do |key|
|
51
|
+
if first
|
52
|
+
first = false
|
53
|
+
else
|
54
|
+
sql << ", "
|
55
|
+
end
|
56
|
+
|
57
|
+
sql << "#{@db.sep_col}#{@db.escape_column(key)}#{@db.sep_col}"
|
58
|
+
end
|
59
|
+
|
60
|
+
sql << ")"
|
61
|
+
sql
|
62
|
+
end
|
63
|
+
|
64
|
+
def sql_values
|
65
|
+
sql = "("
|
66
|
+
|
67
|
+
first = true
|
68
|
+
@data.each_value do |value|
|
69
|
+
if first
|
70
|
+
first = false
|
71
|
+
else
|
72
|
+
sql << ", "
|
73
|
+
end
|
74
|
+
|
75
|
+
sql << @db.sqlval(value)
|
76
|
+
end
|
77
|
+
|
78
|
+
sql << ")"
|
79
|
+
sql
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Baza::SqlQueries::GenericUpdate
|
2
|
+
def initialize(args)
|
3
|
+
@db = args.fetch(:db)
|
4
|
+
@table_name = args.fetch(:table_name)
|
5
|
+
@data = args.fetch(:data)
|
6
|
+
@terms = args.fetch(:terms)
|
7
|
+
@buffer = args[:buffer]
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute
|
11
|
+
if @buffer
|
12
|
+
@buffer.query(to_sql)
|
13
|
+
else
|
14
|
+
@db.query(to_sql)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_sql
|
19
|
+
sql = "UPDATE #{@db.sep_col}#{@db.escape_table(@table_name)}#{@db.sep_col} SET "
|
20
|
+
|
21
|
+
first = true
|
22
|
+
@data.each do |key, value|
|
23
|
+
sql << ", " unless first
|
24
|
+
first = false if first
|
25
|
+
sql << "#{@db.sep_col}#{@db.escape_column(key)}#{@db.sep_col} = #{@db.sqlval(value)}"
|
26
|
+
end
|
27
|
+
|
28
|
+
sql << " WHERE #{@db.sql_make_where(@terms)}" if @terms && !@terms.empty?
|
29
|
+
sql
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class Baza::SqlQueries::MysqlUpsert
|
2
|
+
def initialize(args)
|
3
|
+
@db = args.fetch(:db)
|
4
|
+
@table_name = args.fetch(:table_name)
|
5
|
+
@updates = args.fetch(:updates)
|
6
|
+
@terms = args.fetch(:terms)
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute
|
10
|
+
procedure_name = "baza_upsert_#{SecureRandom.hex(5)}"
|
11
|
+
|
12
|
+
sql = "CREATE PROCEDURE `#{@db.escape_table(procedure_name)}` () BEGIN\n"
|
13
|
+
sql << "\tIF EXISTS(#{select_query}) THEN\n"
|
14
|
+
sql << "\t\t#{update_sql};\n"
|
15
|
+
sql << "\tELSE\n"
|
16
|
+
sql << "\t\t#{insert_sql};\n"
|
17
|
+
sql << "\tEND IF;\n"
|
18
|
+
sql << "END;\n"
|
19
|
+
|
20
|
+
@db.query(sql)
|
21
|
+
|
22
|
+
begin
|
23
|
+
@db.query("CALL `#{@db.escape_table(procedure_name)}`")
|
24
|
+
ensure
|
25
|
+
@db.query("DROP PROCEDURE `#{@db.escape_table(procedure_name)}`")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def select_query
|
32
|
+
sql = ""
|
33
|
+
sql << "SELECT * FROM #{@db.sep_table}#{@db.escape_table(@table_name)}#{@db.sep_table} WHERE"
|
34
|
+
|
35
|
+
first = true
|
36
|
+
@terms.each do |column, value|
|
37
|
+
sql << " AND" unless first
|
38
|
+
first = false if first
|
39
|
+
sql << " #{@db.sep_col}#{@db.escape_column(column)}#{@db.sep_col} = #{@db.sqlval(value)}"
|
40
|
+
end
|
41
|
+
|
42
|
+
sql
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_sql
|
46
|
+
@db.update(@table_name, @updates, @terms, return_sql: true)
|
47
|
+
end
|
48
|
+
|
49
|
+
def insert_sql
|
50
|
+
@db.insert(@table_name, @updates.merge(@terms), return_sql: true)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Baza::SqlQueries::MysqlUpsertDuplicateKey
|
2
|
+
def initialize(args)
|
3
|
+
@db = args.fetch(:db)
|
4
|
+
@table_name = args.fetch(:table_name)
|
5
|
+
@updates = StringCases.stringify_keys(args.fetch(:updates))
|
6
|
+
@terms = StringCases.stringify_keys(args.fetch(:terms))
|
7
|
+
@buffer = args[:buffer]
|
8
|
+
@return_id = args[:return_id]
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_sql
|
12
|
+
sql = insert_sql
|
13
|
+
sql << " ON DUPLICATE KEY UPDATE"
|
14
|
+
|
15
|
+
first = true
|
16
|
+
|
17
|
+
if @return_id
|
18
|
+
sql << " #{@db.sep_col}#{@db.escape_column(primary_key_column_name)}#{@db.sep_col} = LAST_INSERT_ID(#{@db.sep_col}#{@db.escape_column(primary_key_column_name)}#{@db.sep_col})"
|
19
|
+
first = false
|
20
|
+
end
|
21
|
+
|
22
|
+
@updates.each do |key, value|
|
23
|
+
sql << "," unless first
|
24
|
+
first = false if first
|
25
|
+
sql << " #{@db.sep_col}#{@db.escape_column(key)}#{@db.sep_col} = #{@db.sqlval(value)}"
|
26
|
+
end
|
27
|
+
|
28
|
+
sql
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute
|
32
|
+
if @buffer
|
33
|
+
@buffer.query(to_sql)
|
34
|
+
else
|
35
|
+
@db.query(to_sql)
|
36
|
+
return @db.query(last_insert_sql).fetch.fetch(:id).to_i if @return_id
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def insert_sql
|
43
|
+
@db.insert(@table_name, @updates.merge(@terms), return_sql: true)
|
44
|
+
end
|
45
|
+
|
46
|
+
def table
|
47
|
+
@table ||= @db.tables[@table_name.to_s]
|
48
|
+
end
|
49
|
+
|
50
|
+
def primary_key_column_name
|
51
|
+
@primary_key_column_name ||= table.columns(primarykey: true).first.name
|
52
|
+
end
|
53
|
+
|
54
|
+
def last_insert_sql
|
55
|
+
"SELECT LAST_INSERT_ID() AS `id` FROM #{@db.sep_table}#{@db.escape_table(@table_name)}#{@db.sep_table}"
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Baza::SqlQueries::NonAtomicUpsert
|
2
|
+
def initialize(args)
|
3
|
+
@db = args.fetch(:db)
|
4
|
+
@table_name = args.fetch(:table_name)
|
5
|
+
@updates = args.fetch(:updates)
|
6
|
+
@terms = args.fetch(:terms)
|
7
|
+
@buffer = args[:buffer]
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute
|
11
|
+
row = @db.single(@table_name, @terms)
|
12
|
+
|
13
|
+
if @buffer
|
14
|
+
obj = @buffer
|
15
|
+
else
|
16
|
+
obj = @db
|
17
|
+
end
|
18
|
+
|
19
|
+
if row
|
20
|
+
obj.update(@table_name, @updates, @terms)
|
21
|
+
else
|
22
|
+
obj.insert(@table_name, @terms.merge(@updates))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
class Baza::SqlQueries::PostgresUpsertDuplicateKey
|
2
|
+
def initialize(args)
|
3
|
+
@db = args.fetch(:db)
|
4
|
+
@table_name = args.fetch(:table_name)
|
5
|
+
@updates = StringCases.stringify_keys(args.fetch(:updates))
|
6
|
+
@terms = StringCases.stringify_keys(args.fetch(:terms))
|
7
|
+
@return_id = args[:return_id]
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute
|
11
|
+
if @db.commands.version.to_f >= 9.5
|
12
|
+
@db.query(on_conflict_sql)
|
13
|
+
elsif @terms.empty?
|
14
|
+
return insert_and_register_conflict
|
15
|
+
else
|
16
|
+
@db.query(begin_update_exception_sql)
|
17
|
+
end
|
18
|
+
|
19
|
+
@db.last_id if @return_id
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def insert_and_register_conflict
|
25
|
+
@db.query(insert_sql)
|
26
|
+
@db.last_id if @return_id
|
27
|
+
rescue => e
|
28
|
+
if (match = e.message.match(/Key \((.+)\)=\((.+)\) already exists/))
|
29
|
+
column_name = match[1]
|
30
|
+
conflicting_value = match[2]
|
31
|
+
|
32
|
+
@terms = {column_name => conflicting_value}
|
33
|
+
@db.query(begin_update_exception_sql)
|
34
|
+
|
35
|
+
if @return_id
|
36
|
+
primary_column = table.columns.find(&:primarykey?).name.to_sym
|
37
|
+
data = @db.single(@table_name, column_name => conflicting_value)
|
38
|
+
return data.fetch(primary_column).to_i
|
39
|
+
end
|
40
|
+
else
|
41
|
+
raise e
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def begin_update_exception_sql
|
46
|
+
sql = "do $$\n"
|
47
|
+
sql << "BEGIN\n"
|
48
|
+
sql << "\t#{insert_sql};\n"
|
49
|
+
sql << "EXCEPTION WHEN unique_violation THEN\n"
|
50
|
+
sql << "\t#{update_sql};\n"
|
51
|
+
sql << "END $$;"
|
52
|
+
|
53
|
+
sql
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_conflict_sql
|
57
|
+
"#{insert_sql} ON CONFLICT DO UPDATE #{update_set_sql}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def insert_sql
|
61
|
+
sql = "INSERT INTO #{@db.sep_table}#{@db.escape_table(@table_name)}#{@db.sep_table} ("
|
62
|
+
|
63
|
+
combined_data = @updates.merge(@terms)
|
64
|
+
|
65
|
+
first = true
|
66
|
+
combined_data.each_key do |column_name|
|
67
|
+
sql << ", " unless first
|
68
|
+
first = false if first
|
69
|
+
sql << "#{@db.sep_col}#{@db.escape_column(column_name)}#{@db.sep_col}"
|
70
|
+
end
|
71
|
+
|
72
|
+
sql << ") VALUES ("
|
73
|
+
|
74
|
+
first = true
|
75
|
+
combined_data.each_value do |value|
|
76
|
+
sql << ", " unless first
|
77
|
+
first = false if first
|
78
|
+
sql << @db.sqlval(value).to_s
|
79
|
+
end
|
80
|
+
|
81
|
+
sql << ")"
|
82
|
+
sql
|
83
|
+
end
|
84
|
+
|
85
|
+
def update_sql
|
86
|
+
"UPDATE #{@db.sep_table}#{@db.escape_table(@table_name)}#{@db.sep_table} #{update_set_sql} #{update_where_sql}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def update_set_sql
|
90
|
+
sql = "SET "
|
91
|
+
|
92
|
+
first = true
|
93
|
+
@updates.each do |key, value|
|
94
|
+
sql << ", " unless first
|
95
|
+
first = false if first
|
96
|
+
sql << "#{@db.sep_col}#{@db.escape_column(key)}#{@db.sep_col} = #{@db.sqlval(value)}"
|
97
|
+
end
|
98
|
+
|
99
|
+
sql
|
100
|
+
end
|
101
|
+
|
102
|
+
def update_where_sql
|
103
|
+
sql = "WHERE "
|
104
|
+
|
105
|
+
first = true
|
106
|
+
@terms.each do |key, value|
|
107
|
+
sql << " AND " unless first
|
108
|
+
first = false if first
|
109
|
+
sql << "#{@db.sep_col}#{@db.escape_column(key)}#{@db.sep_col} = #{@db.sqlval(value)}"
|
110
|
+
end
|
111
|
+
|
112
|
+
sql
|
113
|
+
end
|
114
|
+
|
115
|
+
def table
|
116
|
+
@table ||= @db.tables[@table_name.to_s]
|
117
|
+
end
|
118
|
+
end
|