upsert 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.md +14 -10
- data/Rakefile +1 -1
- data/lib/upsert.rb +95 -10
- data/lib/upsert/active_record_upsert.rb +12 -0
- data/lib/upsert/mysql2_client.rb +160 -0
- data/lib/upsert/pg_connection.rb +84 -0
- data/lib/upsert/pg_connection/column_definition.rb +60 -0
- data/lib/upsert/row.rb +8 -8
- data/lib/upsert/sqlite3_database.rb +39 -0
- data/lib/upsert/version.rb +1 -1
- data/test/misc/get_postgres_reserved_words.rb +12 -0
- data/test/misc/mysql_reserved.txt +226 -0
- data/test/misc/pg_reserved.txt +742 -0
- data/test/shared/multibyte.rb +2 -2
- data/test/shared/reserved_words.rb +41 -0
- data/test/test_active_record_upsert.rb +23 -0
- data/test/test_mysql2.rb +2 -0
- data/test/test_pg.rb +2 -0
- data/test/test_sqlite.rb +14 -11
- metadata +17 -8
- data/lib/upsert/buffer.rb +0 -58
- data/lib/upsert/buffer/mysql2_client.rb +0 -164
- data/lib/upsert/buffer/pg_connection.rb +0 -87
- data/lib/upsert/buffer/pg_connection/column_definition.rb +0 -60
- data/lib/upsert/buffer/sqlite3_database.rb +0 -43
- data/lib/upsert/quoter.rb +0 -43
@@ -1,60 +0,0 @@
|
|
1
|
-
class Upsert
|
2
|
-
class Buffer
|
3
|
-
class PG_Connection < Buffer
|
4
|
-
# @private
|
5
|
-
# activerecord-3.2.5/lib/active_record/connection_adapters/postgresql_adapter.rb#column_definitions
|
6
|
-
class ColumnDefinition
|
7
|
-
class << self
|
8
|
-
def auto_increment_primary_key(connection, table_name)
|
9
|
-
res = connection.exec <<-EOS
|
10
|
-
SELECT attr.attname, seq.relname
|
11
|
-
FROM pg_class seq,
|
12
|
-
pg_attribute attr,
|
13
|
-
pg_depend dep,
|
14
|
-
pg_namespace name,
|
15
|
-
pg_constraint cons
|
16
|
-
WHERE seq.oid = dep.objid
|
17
|
-
AND seq.relkind = 'S'
|
18
|
-
AND attr.attrelid = dep.refobjid
|
19
|
-
AND attr.attnum = dep.refobjsubid
|
20
|
-
AND attr.attrelid = cons.conrelid
|
21
|
-
AND attr.attnum = cons.conkey[1]
|
22
|
-
AND cons.contype = 'p'
|
23
|
-
AND dep.refobjid = '#{connection.quote_ident(table_name.to_s)}'::regclass
|
24
|
-
EOS
|
25
|
-
if hit = res.first
|
26
|
-
hit['attname']
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def all(connection, table_name)
|
31
|
-
auto_increment_primary_key = auto_increment_primary_key(connection, table_name)
|
32
|
-
res = connection.exec <<-EOS
|
33
|
-
SELECT a.attname AS name, format_type(a.atttypid, a.atttypmod) AS sql_type, d.adsrc AS default
|
34
|
-
FROM pg_attribute a LEFT JOIN pg_attrdef d
|
35
|
-
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
36
|
-
WHERE a.attrelid = '#{connection.quote_ident(table_name.to_s)}'::regclass
|
37
|
-
AND a.attnum > 0 AND NOT a.attisdropped
|
38
|
-
ORDER BY a.attnum
|
39
|
-
EOS
|
40
|
-
res.reject do |row|
|
41
|
-
row['name'] == auto_increment_primary_key
|
42
|
-
end.map do |row|
|
43
|
-
new row['name'], row['sql_type'], row['default']
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
attr_reader :name
|
49
|
-
attr_reader :sql_type
|
50
|
-
attr_reader :default
|
51
|
-
|
52
|
-
def initialize(name, sql_type, default)
|
53
|
-
@name = name
|
54
|
-
@sql_type = sql_type
|
55
|
-
@default = default
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
class Upsert
|
2
|
-
class Buffer
|
3
|
-
# @private
|
4
|
-
class SQLite3_Database < Buffer
|
5
|
-
include Quoter
|
6
|
-
|
7
|
-
def chunk
|
8
|
-
return if rows.empty?
|
9
|
-
row = rows.shift
|
10
|
-
%{INSERT OR IGNORE INTO "#{table_name}" (#{row.columns_sql}) VALUES (#{row.values_sql});UPDATE "#{table_name}" SET #{row.set_sql} WHERE #{row.where_sql}}
|
11
|
-
end
|
12
|
-
|
13
|
-
def execute(sql)
|
14
|
-
connection.execute_batch sql
|
15
|
-
end
|
16
|
-
|
17
|
-
def quote_string(v)
|
18
|
-
SINGLE_QUOTE + SQLite3::Database.quote(v) + SINGLE_QUOTE
|
19
|
-
end
|
20
|
-
|
21
|
-
def quote_binary(v)
|
22
|
-
X_AND_SINGLE_QUOTE + v.unpack("H*")[0] + SINGLE_QUOTE
|
23
|
-
end
|
24
|
-
|
25
|
-
def quote_time(v)
|
26
|
-
quote_string [v.strftime(ISO8601_DATETIME), sprintf(USEC_SPRINTF, v.usec)].join('.')
|
27
|
-
end
|
28
|
-
|
29
|
-
def quote_ident(k)
|
30
|
-
DOUBLE_QUOTE + SQLite3::Database.quote(k.to_s) + DOUBLE_QUOTE
|
31
|
-
end
|
32
|
-
|
33
|
-
def quote_boolean(v)
|
34
|
-
s = v ? 't' : 'f'
|
35
|
-
quote_string s
|
36
|
-
end
|
37
|
-
|
38
|
-
def quote_big_decimal(v)
|
39
|
-
v.to_f
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/upsert/quoter.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
class Upsert
|
2
|
-
# @private
|
3
|
-
module Quoter
|
4
|
-
ISO8601_DATE = '%F'
|
5
|
-
|
6
|
-
def quote_value(v)
|
7
|
-
case v
|
8
|
-
when NilClass
|
9
|
-
'NULL'
|
10
|
-
when Upsert::Binary
|
11
|
-
quote_binary v # must be defined by base
|
12
|
-
when String
|
13
|
-
quote_string v # must be defined by base
|
14
|
-
when TrueClass, FalseClass
|
15
|
-
quote_boolean v
|
16
|
-
when BigDecimal
|
17
|
-
quote_big_decimal v
|
18
|
-
when Numeric
|
19
|
-
v
|
20
|
-
when Symbol
|
21
|
-
quote_string v.to_s
|
22
|
-
when Time, DateTime
|
23
|
-
quote_time v # must be defined by base
|
24
|
-
when Date
|
25
|
-
quote_string v.strftime(ISO8601_DATE)
|
26
|
-
else
|
27
|
-
raise "not sure how to quote #{v.class}: #{v.inspect}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def quote_idents(idents)
|
32
|
-
idents.map { |k| quote_ident(k) }.join(',') # must be defined by base
|
33
|
-
end
|
34
|
-
|
35
|
-
def quote_values(values)
|
36
|
-
values.map { |v| quote_value(v) }.join(',')
|
37
|
-
end
|
38
|
-
|
39
|
-
def quote_pairs(pairs)
|
40
|
-
pairs.map { |k, v| [quote_ident(k),quote_value(v)].join('=') }.join(',')
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|