purview 1.0.0.alpha → 1.0.0.beta1
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/.travis.yml +0 -4
- data/Gemfile +10 -0
- data/README.md +2 -2
- data/TODO +10 -5
- data/lib/purview/columns/base.rb +2 -2
- data/lib/purview/columns.rb +1 -0
- data/lib/purview/connections/base.rb +17 -31
- data/lib/purview/connections/mysql.rb +2 -30
- data/lib/purview/connections/postgresql.rb +2 -18
- data/lib/purview/databases/base.rb +32 -31
- data/lib/purview/databases/mysql.rb +4 -16
- data/lib/purview/databases/postgresql.rb +4 -16
- data/lib/purview/databases.rb +1 -0
- data/lib/purview/dialects/base.rb +25 -0
- data/lib/purview/dialects/mysql.rb +25 -0
- data/lib/purview/dialects/postgresql.rb +25 -0
- data/lib/purview/dialects.rb +4 -0
- data/lib/purview/exceptions/{table.rb → base_table.rb} +1 -1
- data/lib/purview/exceptions/could_not_acquire_lock.rb +1 -1
- data/lib/purview/exceptions/lock_already_released.rb +1 -1
- data/lib/purview/exceptions/no_window.rb +1 -1
- data/lib/purview/exceptions.rb +2 -1
- data/lib/purview/loaders/base.rb +26 -2
- data/lib/purview/loaders/mysql.rb +4 -0
- data/lib/purview/loaders/postgresql.rb +4 -0
- data/lib/purview/loaders.rb +1 -0
- data/lib/purview/loggers.rb +1 -0
- data/lib/purview/mixins/connection.rb +13 -0
- data/lib/purview/mixins/helpers.rb +5 -1
- data/lib/purview/mixins/logger.rb +2 -2
- data/lib/purview/mixins.rb +1 -0
- data/lib/purview/parsers/base.rb +7 -11
- data/lib/purview/parsers/csv.rb +19 -3
- data/lib/purview/parsers/sql.rb +13 -0
- data/lib/purview/parsers.rb +2 -0
- data/lib/purview/pullers/base.rb +4 -0
- data/lib/purview/pullers/base_sql.rb +97 -0
- data/lib/purview/pullers/mysql.rb +15 -0
- data/lib/purview/pullers/postgresql.rb +15 -0
- data/lib/purview/pullers.rb +4 -0
- data/lib/purview/raw_connections/base.rb +118 -0
- data/lib/purview/raw_connections/jdbc/base.rb +65 -0
- data/lib/purview/raw_connections/jdbc/mysql.rb +19 -0
- data/lib/purview/raw_connections/jdbc/postgres.rb +19 -0
- data/lib/purview/raw_connections/jdbc.rb +4 -0
- data/lib/purview/raw_connections/mysql2.rb +35 -0
- data/lib/purview/raw_connections/pg.rb +35 -0
- data/lib/purview/raw_connections.rb +8 -0
- data/lib/purview/refinements/object.rb +4 -0
- data/lib/purview/refinements/string.rb +5 -0
- data/lib/purview/refinements.rb +1 -0
- data/lib/purview/structs/base.rb +12 -2
- data/lib/purview/structs/row.rb +7 -0
- data/lib/purview/structs.rb +2 -0
- data/lib/purview/tables/base.rb +1 -1
- data/lib/purview/types.rb +1 -0
- data/lib/purview/version.rb +1 -1
- data/lib/purview.rb +3 -3
- data/purview.gemspec +2 -2
- metadata +25 -32
data/lib/purview/loaders.rb
CHANGED
data/lib/purview/loggers.rb
CHANGED
@@ -5,10 +5,14 @@ module Purview
|
|
5
5
|
value.to_s.strip.length.zero?
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
8
|
+
def coalesced(value, default)
|
9
9
|
value.nil? ? default : value
|
10
10
|
end
|
11
11
|
|
12
|
+
def filter_nil_values(hash)
|
13
|
+
hash.reject { |_, value| value.nil? }
|
14
|
+
end
|
15
|
+
|
12
16
|
def present?(value)
|
13
17
|
!blank?(value)
|
14
18
|
end
|
@@ -6,11 +6,11 @@ module Purview
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def logger_opts
|
9
|
-
opts[:logger] || {}
|
9
|
+
(defined?(opts) && opts[:logger]) || {}
|
10
10
|
end
|
11
11
|
|
12
12
|
def logger_type
|
13
|
-
opts[:logger_type] || Purview::Loggers::Console
|
13
|
+
(defined?(opts) && opts[:logger_type]) || Purview::Loggers::Console
|
14
14
|
end
|
15
15
|
|
16
16
|
def with_context_logging(*args)
|
data/lib/purview/mixins.rb
CHANGED
data/lib/purview/parsers/base.rb
CHANGED
@@ -10,7 +10,7 @@ module Purview
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def validate(data)
|
13
|
-
|
13
|
+
raise %{All "#{Base}(s)" must override the "validate" method}
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
@@ -19,16 +19,12 @@ module Purview
|
|
19
19
|
|
20
20
|
attr_reader :opts
|
21
21
|
|
22
|
-
def
|
23
|
-
{}
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
logger.debug(%{Unexpected column: "#{key}" in data-set})
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
22
|
+
def extract_headers(data)
|
23
|
+
raise %{All "#{Base}(s)" must override the "extract_headers" method}
|
24
|
+
end
|
25
|
+
|
26
|
+
def extract_rows(data)
|
27
|
+
raise %{All "#{Base}(s)" must override the "extract_rows" method}
|
32
28
|
end
|
33
29
|
|
34
30
|
def table
|
data/lib/purview/parsers/csv.rb
CHANGED
@@ -5,7 +5,7 @@ module Purview
|
|
5
5
|
with_context_logging("`parse` for: #{table.name}") do
|
6
6
|
[].tap do |results|
|
7
7
|
headers = extract_headers(data)
|
8
|
-
extract_rows(data) do |row|
|
8
|
+
extract_rows(data).each do |row|
|
9
9
|
results << build_result(headers.zip(row))
|
10
10
|
end
|
11
11
|
end
|
@@ -14,7 +14,7 @@ module Purview
|
|
14
14
|
|
15
15
|
def validate(data)
|
16
16
|
with_context_logging("`validate` for: #{table.name}") do
|
17
|
-
missing_columns =
|
17
|
+
missing_columns = missing_columns(data)
|
18
18
|
raise 'Missing one or more columns: "%s"' % missing_columns.join('", "') \
|
19
19
|
unless missing_columns.empty?
|
20
20
|
true
|
@@ -23,6 +23,18 @@ module Purview
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
+
def build_result(row)
|
27
|
+
{}.tap do |result|
|
28
|
+
row.each do |key, value|
|
29
|
+
if column = table.columns_by_name[key]
|
30
|
+
result[key] = column.parse(value)
|
31
|
+
else
|
32
|
+
logger.debug(%{Unexpected column: "#{key}" in data-set})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
26
38
|
def column_separator
|
27
39
|
','
|
28
40
|
end
|
@@ -34,7 +46,11 @@ module Purview
|
|
34
46
|
|
35
47
|
def extract_rows(data)
|
36
48
|
rows = data.split(row_separator)[1..-1]
|
37
|
-
rows.
|
49
|
+
rows.map { |row| parse_row(row) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def missing_columns(data)
|
53
|
+
table.column_names - extract_headers(data)
|
38
54
|
end
|
39
55
|
|
40
56
|
def parse_row(row)
|
data/lib/purview/parsers.rb
CHANGED
data/lib/purview/pullers/base.rb
CHANGED
@@ -0,0 +1,97 @@
|
|
1
|
+
module Purview
|
2
|
+
module Pullers
|
3
|
+
class BaseSQL < Base
|
4
|
+
def pull(window)
|
5
|
+
with_new_connection do |connection|
|
6
|
+
connection.execute(pull_sql(window))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
include Purview::Mixins::Connection
|
13
|
+
include Purview::Mixins::Helpers
|
14
|
+
include Purview::Mixins::Logger
|
15
|
+
|
16
|
+
def column_names
|
17
|
+
table.column_names
|
18
|
+
end
|
19
|
+
|
20
|
+
def connection_opts
|
21
|
+
filter_nil_values(
|
22
|
+
:database => database_name,
|
23
|
+
:host => database_host,
|
24
|
+
:password => database_password,
|
25
|
+
:port => database_port,
|
26
|
+
:username => database_username
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def connection_type
|
31
|
+
raise %{All "#{BaseSQL}(s)" must override the "connection_type" method}
|
32
|
+
end
|
33
|
+
|
34
|
+
def database_host
|
35
|
+
opts[:database_host]
|
36
|
+
end
|
37
|
+
|
38
|
+
def database_name
|
39
|
+
opts[:database_name]
|
40
|
+
end
|
41
|
+
|
42
|
+
def database_password
|
43
|
+
opts[:database_password]
|
44
|
+
end
|
45
|
+
|
46
|
+
def database_port
|
47
|
+
opts[:database_port]
|
48
|
+
end
|
49
|
+
|
50
|
+
def database_username
|
51
|
+
opts[:database_username]
|
52
|
+
end
|
53
|
+
|
54
|
+
def dialect
|
55
|
+
dialect_type.new
|
56
|
+
end
|
57
|
+
|
58
|
+
def dialect_type
|
59
|
+
raise %{All "#{BaseSQL}(s)" must override the "dialect_type" method}
|
60
|
+
end
|
61
|
+
|
62
|
+
def false_value
|
63
|
+
dialect.false_value
|
64
|
+
end
|
65
|
+
|
66
|
+
def null_value
|
67
|
+
dialect.null_value
|
68
|
+
end
|
69
|
+
|
70
|
+
def pull_sql(window)
|
71
|
+
'SELECT %s FROM %s WHERE %s BETWEEN %s AND %s' % [
|
72
|
+
column_names.join(', '),
|
73
|
+
table_name,
|
74
|
+
table.updated_timestamp_column.name,
|
75
|
+
quoted(window.min),
|
76
|
+
quoted(window.max),
|
77
|
+
]
|
78
|
+
end
|
79
|
+
|
80
|
+
def quoted(value)
|
81
|
+
dialect.quoted(value)
|
82
|
+
end
|
83
|
+
|
84
|
+
def sanitized(value)
|
85
|
+
dialect.sanitized(value)
|
86
|
+
end
|
87
|
+
|
88
|
+
def table_name
|
89
|
+
opts[:table_name]
|
90
|
+
end
|
91
|
+
|
92
|
+
def true_value
|
93
|
+
dialect.true_value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/purview/pullers.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
module Purview
|
2
|
+
module RawConnections
|
3
|
+
class Base
|
4
|
+
def self.connect(opts)
|
5
|
+
new(opts)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.with_new_connection(opts)
|
9
|
+
yield connection = connect(opts)
|
10
|
+
ensure
|
11
|
+
connection.disconnect if connection
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(opts)
|
15
|
+
@opts = opts
|
16
|
+
@raw_connection = new_connection
|
17
|
+
end
|
18
|
+
|
19
|
+
def disconnect
|
20
|
+
raw_connection.close
|
21
|
+
@raw_connection = nil
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute(sql, opts={})
|
26
|
+
logger.debug("Executing: #{sql}")
|
27
|
+
result = execute_sql(sql, opts)
|
28
|
+
structify_result(result)
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_transaction
|
32
|
+
execute_sql(BEGIN_TRANSACTION)
|
33
|
+
yield.tap { |result| execute_sql(COMMIT_TRANSACTION) }
|
34
|
+
rescue
|
35
|
+
execute_sql(ROLLBACK_TRANSACTION)
|
36
|
+
raise
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
include Purview::Mixins::Helpers
|
42
|
+
include Purview::Mixins::Logger
|
43
|
+
|
44
|
+
BEGIN_TRANSACTION = 'BEGIN'
|
45
|
+
COMMIT_TRANSACTION = 'COMMIT'
|
46
|
+
ROLLBACK_TRANSACTION = 'ROLLBACK'
|
47
|
+
|
48
|
+
attr_reader :opts, :raw_connection
|
49
|
+
|
50
|
+
def database
|
51
|
+
opts[:database]
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete?(sql)
|
55
|
+
!!(sql.to_s =~ /\ADELETE/i)
|
56
|
+
end
|
57
|
+
|
58
|
+
def execute_sql(sql, opts={})
|
59
|
+
raise %{All "#{Base}(s)" must override the "execute_sql" method}
|
60
|
+
end
|
61
|
+
|
62
|
+
def extract_rows(result)
|
63
|
+
raise %{All "#{Base}(s)" must override the "extract_rows" method}
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_rows_affected(result)
|
67
|
+
raise %{All "#{Base}(s)" must override the "extract_rows_affected" method}
|
68
|
+
end
|
69
|
+
|
70
|
+
def host
|
71
|
+
opts[:host]
|
72
|
+
end
|
73
|
+
|
74
|
+
def insert?(sql)
|
75
|
+
!!(sql.to_s =~ /\AINSERT/i)
|
76
|
+
end
|
77
|
+
|
78
|
+
def new_connection
|
79
|
+
raise %{All "#{Base}(s)" must override the "new_connection" method}
|
80
|
+
end
|
81
|
+
|
82
|
+
def password
|
83
|
+
opts[:password]
|
84
|
+
end
|
85
|
+
|
86
|
+
def port
|
87
|
+
opts[:port]
|
88
|
+
end
|
89
|
+
|
90
|
+
def select?(sql)
|
91
|
+
!!(sql.to_s =~ /\ASELECT/i)
|
92
|
+
end
|
93
|
+
|
94
|
+
def structify_result(result)
|
95
|
+
Purview::Structs::Result.new(
|
96
|
+
:rows => structify_rows(extract_rows(result) || []),
|
97
|
+
:rows_affected => extract_rows_affected(result)
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
def structify_row(row)
|
102
|
+
Purview::Structs::Row.new(row)
|
103
|
+
end
|
104
|
+
|
105
|
+
def structify_rows(rows)
|
106
|
+
rows.map { |row| structify_row(row) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def update?(sql)
|
110
|
+
!!(sql.to_s =~ /\AUPDATE/i)
|
111
|
+
end
|
112
|
+
|
113
|
+
def username
|
114
|
+
opts[:username] || Etc.getlogin
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Purview
|
2
|
+
module RawConnections
|
3
|
+
module JDBC
|
4
|
+
class Base < Purview::RawConnections::Base
|
5
|
+
private
|
6
|
+
|
7
|
+
attr_reader :last_sql, :last_statement
|
8
|
+
|
9
|
+
def delete_or_insert_or_update?(sql)
|
10
|
+
delete?(sql) || insert?(sql) || update?(sql)
|
11
|
+
end
|
12
|
+
|
13
|
+
def engine
|
14
|
+
raise %{All "#{Base}(s)" must override the "engine" method}
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_sql(sql, opts={})
|
18
|
+
@last_sql = sql
|
19
|
+
@last_statement = statement = raw_connection.createStatement
|
20
|
+
if select?(sql)
|
21
|
+
statement.executeQuery(sql)
|
22
|
+
elsif delete_or_insert_or_update?(sql)
|
23
|
+
statement.executeUpdate(sql)
|
24
|
+
nil
|
25
|
+
else
|
26
|
+
statement.execute(sql)
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def extract_rows(result)
|
32
|
+
return unless result
|
33
|
+
metadata = result.getMetaData
|
34
|
+
column_count = metadata.getColumnCount
|
35
|
+
[].tap do |rows|
|
36
|
+
while result.next
|
37
|
+
rows << {}.tap do |row|
|
38
|
+
(1..column_count).each do |index|
|
39
|
+
column_name = metadata.getColumnName(index)
|
40
|
+
row[column_name] = result.getString(column_name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def extract_rows_affected(result)
|
48
|
+
delete_or_insert_or_update?(last_sql) ? last_statement.getUpdateCount : 0
|
49
|
+
end
|
50
|
+
|
51
|
+
def new_connection
|
52
|
+
java.sql.DriverManager.getConnection(
|
53
|
+
url,
|
54
|
+
username,
|
55
|
+
password
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def url
|
60
|
+
"jdbc:#{engine}://#{host}#{port && ":#{port}"}/#{database}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
if defined?(JRUBY_VERSION) && (require 'jdbc/mysql' rescue nil)
|
2
|
+
Jdbc::MySQL.load_driver
|
3
|
+
|
4
|
+
module Purview
|
5
|
+
module RawConnections
|
6
|
+
module JDBC
|
7
|
+
class MySQL < Base
|
8
|
+
private
|
9
|
+
|
10
|
+
def engine
|
11
|
+
'mysql'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Purview::RawConnections::MySQL = Purview::RawConnections::JDBC::MySQL
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
if defined?(JRUBY_VERSION) && (require 'jdbc/postgres' rescue nil)
|
2
|
+
Jdbc::Postgres.load_driver
|
3
|
+
|
4
|
+
module Purview
|
5
|
+
module RawConnections
|
6
|
+
module JDBC
|
7
|
+
class Postgres < Base
|
8
|
+
private
|
9
|
+
|
10
|
+
def engine
|
11
|
+
'postgresql'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Purview::RawConnections::PostgreSQL = Purview::RawConnections::JDBC::Postgres
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
if !defined?(JRUBY_VERSION) && (require 'mysql2' rescue nil)
|
2
|
+
module Purview
|
3
|
+
module RawConnections
|
4
|
+
class Mysql2 < Base
|
5
|
+
private
|
6
|
+
|
7
|
+
def execute_sql(sql, opts={})
|
8
|
+
raw_connection.query(sql, opts.merge(:cast => false))
|
9
|
+
end
|
10
|
+
|
11
|
+
def extract_rows(result)
|
12
|
+
result && result.to_a
|
13
|
+
end
|
14
|
+
|
15
|
+
def extract_rows_affected(result)
|
16
|
+
raw_connection.affected_rows
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_connection
|
20
|
+
::Mysql2::Client.new(
|
21
|
+
filter_nil_values(
|
22
|
+
:database => database,
|
23
|
+
:host => host,
|
24
|
+
:password => password,
|
25
|
+
:port => port,
|
26
|
+
:username => username
|
27
|
+
)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Purview::RawConnections::MySQL = Purview::RawConnections::Mysql2
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
if !defined?(JRUBY_VERSION) && (require 'pg' rescue nil)
|
2
|
+
module Purview
|
3
|
+
module RawConnections
|
4
|
+
class PG < Base
|
5
|
+
private
|
6
|
+
|
7
|
+
def execute_sql(sql, opts={})
|
8
|
+
raw_connection.exec(sql)
|
9
|
+
end
|
10
|
+
|
11
|
+
def extract_rows(result)
|
12
|
+
result && result.to_a
|
13
|
+
end
|
14
|
+
|
15
|
+
def extract_rows_affected(result)
|
16
|
+
result && result.cmd_tuples
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_connection
|
20
|
+
::PG.connect(
|
21
|
+
filter_nil_values(
|
22
|
+
:dbname => database,
|
23
|
+
:host => host,
|
24
|
+
:password => password,
|
25
|
+
:port => port,
|
26
|
+
:user => username
|
27
|
+
)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Purview::RawConnections::PostgreSQL = Purview::RawConnections::PG
|
35
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'purview/raw_connections/base'
|
2
|
+
require 'purview/raw_connections/jdbc/base'
|
3
|
+
|
4
|
+
require 'purview/raw_connections/jdbc/mysql'
|
5
|
+
require 'purview/raw_connections/jdbc/postgres'
|
6
|
+
|
7
|
+
require 'purview/raw_connections/mysql2'
|
8
|
+
require 'purview/raw_connections/pg'
|
data/lib/purview/refinements.rb
CHANGED
data/lib/purview/structs/base.rb
CHANGED
@@ -1,8 +1,18 @@
|
|
1
1
|
module Purview
|
2
2
|
module Structs
|
3
3
|
class Base < OpenStruct
|
4
|
-
def
|
5
|
-
|
4
|
+
def [](key)
|
5
|
+
key = key.to_sym unless key.is_a?(Symbol)
|
6
|
+
raise NoMethodError unless respond_to?(key)
|
7
|
+
send(key)
|
8
|
+
end
|
9
|
+
|
10
|
+
def []=(key, value)
|
11
|
+
send("#{key}=", value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(method, *args, &block)
|
15
|
+
raise NoMethodError if args.empty?
|
6
16
|
super
|
7
17
|
end
|
8
18
|
end
|