db2_query 0.2.3 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +472 -124
- data/Rakefile +3 -2
- data/lib/db2_query/base.rb +15 -5
- data/lib/db2_query/config.rb +20 -17
- data/lib/db2_query/core.rb +79 -60
- data/lib/db2_query/db_client.rb +56 -0
- data/lib/db2_query/db_connection.rb +68 -0
- data/lib/db2_query/db_statements.rb +87 -0
- data/lib/db2_query/definitions.rb +93 -0
- data/lib/db2_query/error.rb +72 -7
- data/lib/db2_query/field_type.rb +31 -0
- data/lib/db2_query/helper.rb +50 -0
- data/lib/db2_query/logger.rb +52 -0
- data/lib/db2_query/query.rb +128 -0
- data/lib/db2_query/railtie.rb +5 -10
- data/lib/db2_query/result.rb +51 -31
- data/lib/db2_query/sql_statement.rb +34 -0
- data/lib/db2_query/tasks/database.rake +2 -46
- data/lib/db2_query/tasks/init.rake +1 -1
- data/lib/db2_query/tasks/initializer.rake +2 -34
- data/lib/db2_query/tasks/templates/database.rb.tt +19 -0
- data/lib/db2_query/tasks/templates/initializer.rb.tt +8 -0
- data/lib/db2_query/tasks.rb +29 -0
- data/lib/db2_query/type/binary.rb +19 -0
- data/lib/db2_query/type/boolean.rb +41 -0
- data/lib/db2_query/type/date.rb +34 -0
- data/lib/db2_query/type/decimal.rb +15 -0
- data/lib/db2_query/type/integer.rb +15 -0
- data/lib/db2_query/type/string.rb +30 -0
- data/lib/db2_query/type/text.rb +11 -0
- data/lib/db2_query/type/time.rb +30 -0
- data/lib/db2_query/type/timestamp.rb +30 -0
- data/lib/db2_query/type/value.rb +29 -0
- data/lib/db2_query/version.rb +2 -2
- data/lib/db2_query.rb +42 -18
- data/lib/rails/generators/query/USAGE +15 -0
- data/lib/rails/generators/query/query_generator.rb +70 -0
- data/lib/rails/generators/query/templates/query.rb.tt +26 -0
- data/lib/rails/generators/query/templates/query_definitions.rb.tt +18 -0
- data/lib/rails/generators/query/templates/unit_test.rb.tt +9 -0
- metadata +74 -36
- data/lib/db2_query/bind.rb +0 -6
- data/lib/db2_query/connection.rb +0 -164
- data/lib/db2_query/connection_handling.rb +0 -112
- data/lib/db2_query/database_statements.rb +0 -89
- data/lib/db2_query/formatter.rb +0 -27
- data/lib/db2_query/odbc_connector.rb +0 -44
data/Rakefile
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bundler/setup"
|
3
4
|
require "bundler/gem_tasks"
|
4
5
|
require "rake/testtask"
|
5
6
|
|
6
7
|
Rake::TestTask.new(:test) do |t|
|
7
8
|
t.libs << "test"
|
8
|
-
t.
|
9
|
-
t.
|
9
|
+
t.pattern = "test/**/*_test.rb"
|
10
|
+
t.verbose = false
|
10
11
|
end
|
11
12
|
|
12
13
|
task default: :test
|
data/lib/db2_query/base.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Db2Query
|
4
4
|
class Base
|
5
|
-
include
|
6
|
-
include
|
7
|
-
|
8
|
-
|
5
|
+
include Config
|
6
|
+
include Helper
|
7
|
+
include DbConnection
|
8
|
+
include FieldType
|
9
|
+
include Core
|
10
|
+
|
11
|
+
def self.inherited(subclass)
|
12
|
+
subclass.define_query_definitions
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.establish_connection
|
16
|
+
load_database_configurations
|
17
|
+
new_database_connection
|
18
|
+
end
|
9
19
|
end
|
10
20
|
end
|
data/lib/db2_query/config.rb
CHANGED
@@ -1,26 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
@config ||= read_config
|
7
|
-
end
|
3
|
+
module Db2Query
|
4
|
+
module Config
|
5
|
+
DEFAULT_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence }
|
8
6
|
|
9
|
-
def
|
10
|
-
|
11
|
-
"#{Rails.root}/config/db2query_database.yml"
|
12
|
-
else
|
13
|
-
ENV["DQ_CONFIG_PATH"]
|
14
|
-
end
|
7
|
+
def self.included(base)
|
8
|
+
base.send(:extend, ClassMethods)
|
15
9
|
end
|
16
10
|
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
module ClassMethods
|
12
|
+
mattr_accessor :configurations
|
13
|
+
@@configurations = nil
|
14
|
+
|
15
|
+
alias config configurations
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
def default_path
|
18
|
+
"#{Rails.root}/config/db2query.yml"
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_database_configurations(path = nil)
|
22
|
+
config_file = IO.read(path || default_path)
|
23
|
+
@@configurations = YAML.load(config_file)[DEFAULT_ENV.call].transform_keys(&:to_sym)
|
24
|
+
rescue Exception => e
|
25
|
+
raise Db2Query::Error, e.message
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
data/lib/db2_query/core.rb
CHANGED
@@ -1,91 +1,110 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
module DB2Query
|
3
|
+
module Db2Query
|
6
4
|
module Core
|
7
|
-
|
5
|
+
def self.included(base)
|
6
|
+
base.send(:extend, ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
attr_reader :definitions
|
11
|
+
|
12
|
+
delegate :query_rows, :query_value, :query_values, :execute, to: :connection
|
8
13
|
|
9
|
-
|
10
|
-
|
11
|
-
@@configurations = ActiveRecord::DatabaseConfigurations.new(config)
|
14
|
+
def initiation
|
15
|
+
yield(self) if block_given?
|
12
16
|
end
|
13
|
-
self.configurations = {}
|
14
17
|
|
15
|
-
def
|
16
|
-
|
18
|
+
def define_query_definitions
|
19
|
+
@definitions = new_definitions
|
17
20
|
end
|
18
21
|
|
19
|
-
|
22
|
+
def exec_query_result(query, args)
|
23
|
+
reset_id_when_required(query)
|
24
|
+
connection.exec_query(query, args)
|
25
|
+
end
|
20
26
|
|
21
|
-
|
27
|
+
def query(*query_args)
|
28
|
+
if query_args.first.is_a?(Symbol)
|
29
|
+
query_name, body = query_args
|
22
30
|
|
23
|
-
|
24
|
-
|
31
|
+
body_lambda = if body.is_a?(Proc)
|
32
|
+
-> args { body.call(args << { query_name: query_name }) }
|
33
|
+
elsif body.is_a?(String)
|
34
|
+
definition = definitions.lookup_query(query_name, body.strip)
|
35
|
+
-> args { exec_query_result(definition, args) }
|
36
|
+
else
|
37
|
+
raise Db2Query::QueryMethodError.new
|
38
|
+
end
|
39
|
+
|
40
|
+
singleton_class.define_method(query_name) do |*args|
|
41
|
+
body_lambda.call(args)
|
42
|
+
end
|
43
|
+
elsif query_args.first.is_a?(String)
|
44
|
+
sql, args = [query_args.first.strip, query_args.drop(1)]
|
45
|
+
|
46
|
+
definition = Query.new.tap do |d|
|
47
|
+
d.define_sql(sql)
|
48
|
+
d.define_args(args)
|
49
|
+
end
|
50
|
+
|
51
|
+
connection.raw_query(definition.db2_spec_sql, definition.args)
|
52
|
+
else
|
53
|
+
raise Db2Query::Error, "Wrong query implementation"
|
54
|
+
end
|
25
55
|
end
|
56
|
+
alias define query
|
26
57
|
|
27
|
-
def
|
28
|
-
|
58
|
+
def query_arguments_map
|
59
|
+
@query_arguments_map ||= {}
|
29
60
|
end
|
30
61
|
|
31
|
-
|
32
|
-
|
62
|
+
def query_arguments(query_name, argument_types)
|
63
|
+
query_arguments_map[query_name] = argument_types
|
64
|
+
end
|
33
65
|
|
34
|
-
|
35
|
-
|
36
|
-
|
66
|
+
def fetch(sql, args = [])
|
67
|
+
query = definitions.lookup_query(args, sql)
|
68
|
+
query.validate_select_query
|
69
|
+
connection.exec_query(query, args)
|
37
70
|
end
|
38
71
|
|
39
|
-
def
|
40
|
-
|
72
|
+
def fetch_list(sql, args)
|
73
|
+
list = args.first
|
74
|
+
fetch(sql_with_list(sql, list), args.drop(1))
|
41
75
|
end
|
42
76
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
77
|
+
private
|
78
|
+
def new_definitions
|
79
|
+
definition_class = "Definitions::#{name}Definitions"
|
80
|
+
Object.const_get(definition_class).new(
|
81
|
+
query_arguments_map,
|
82
|
+
field_types_map
|
83
|
+
)
|
84
|
+
rescue Exception => e
|
85
|
+
raise Db2Query::Error, e.message
|
48
86
|
end
|
49
87
|
|
50
|
-
|
51
|
-
|
52
|
-
|
88
|
+
def reset_id_when_required(query)
|
89
|
+
if query.insert_sql? && !query.column_id.nil?
|
90
|
+
connection.reset_id_sequence!(query.table_name)
|
53
91
|
end
|
54
|
-
elsif body.is_a?(String)
|
55
|
-
sql = body
|
56
|
-
singleton_class.define_method(name) do |*args|
|
57
|
-
connection.exec_query(formatters, sql, args)
|
58
|
-
end
|
59
|
-
else
|
60
|
-
raise DB2Query::Error, "The query body needs to be callable or is a sql string"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
def formatters
|
66
|
-
@formatters ||= Hash.new
|
67
92
|
end
|
68
93
|
|
69
|
-
def
|
70
|
-
|
94
|
+
def define_sql_query(method_name)
|
95
|
+
sql_query_name = sql_query_symbol(method_name)
|
96
|
+
sql_statement = allocate.method(sql_query_name).call
|
97
|
+
define(method_name, sql_statement)
|
71
98
|
end
|
72
99
|
|
73
100
|
def method_missing(method_name, *args, &block)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
if sql_methods.include?(sql_method)
|
78
|
-
sql_statement = allocate.method(sql_method).call
|
79
|
-
|
80
|
-
unless sql_statement.is_a? String
|
81
|
-
raise DB2Query::Error, "Query methods must return a SQL statement string!"
|
82
|
-
end
|
83
|
-
|
84
|
-
query(method_name, sql_statement)
|
85
|
-
|
101
|
+
if sql_query_method?(method_name)
|
102
|
+
define_sql_query(method_name)
|
86
103
|
method(method_name).call(*args)
|
87
|
-
elsif
|
88
|
-
|
104
|
+
elsif method_name == :exec_query
|
105
|
+
sql, args = [args.shift, args.first]
|
106
|
+
query = definitions.lookup_query(args, sql)
|
107
|
+
exec_query_result(query, args)
|
89
108
|
else
|
90
109
|
super
|
91
110
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class DbClient
|
5
|
+
attr_reader :dsn
|
6
|
+
|
7
|
+
include ActiveModel::Type::Helpers::Timezone
|
8
|
+
|
9
|
+
delegate :run, :do, to: :client
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
@dsn = config[:dsn]
|
13
|
+
@idle_time_limit = config[:idle] || 5
|
14
|
+
@client = new_client
|
15
|
+
@last_transaction = Time.now
|
16
|
+
end
|
17
|
+
|
18
|
+
def expire?
|
19
|
+
Time.now - @last_transaction > 60 * @idle_time_limit
|
20
|
+
end
|
21
|
+
|
22
|
+
def active?
|
23
|
+
@client.connected?
|
24
|
+
end
|
25
|
+
|
26
|
+
def connected_and_persist?
|
27
|
+
active? && !expire?
|
28
|
+
end
|
29
|
+
|
30
|
+
def disconnect!
|
31
|
+
@client.drop_all
|
32
|
+
@client.disconnect if active?
|
33
|
+
@client = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def new_client
|
37
|
+
ODBC.connect(dsn).tap do |odbc_conn|
|
38
|
+
odbc_conn.use_time = true
|
39
|
+
odbc_conn.use_utc = is_utc?
|
40
|
+
end
|
41
|
+
rescue ::ODBC::Error => e
|
42
|
+
raise Db2Query::ConnectionError.new(e.message)
|
43
|
+
end
|
44
|
+
|
45
|
+
def reconnect!
|
46
|
+
disconnect!
|
47
|
+
@client = new_client
|
48
|
+
end
|
49
|
+
|
50
|
+
def client
|
51
|
+
reconnect! unless connected_and_persist?
|
52
|
+
@last_transaction = Time.now
|
53
|
+
@client
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module DbConnection
|
5
|
+
def self.included(base)
|
6
|
+
base.send(:extend, ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
mattr_reader :connection
|
11
|
+
@@connection = nil
|
12
|
+
|
13
|
+
def new_database_connection
|
14
|
+
@@connection = Connection.new(config)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Connection
|
20
|
+
class Pool < ConnectionPool
|
21
|
+
def initialize(config, &block)
|
22
|
+
super(config, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def current_state
|
26
|
+
{ size: self.size, available: self.available }
|
27
|
+
end
|
28
|
+
|
29
|
+
def disconnect!
|
30
|
+
shutdown { |client| client.disconnect! }
|
31
|
+
end
|
32
|
+
|
33
|
+
def reload
|
34
|
+
super { |client| client.disconnect! }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :config, :connection_pool, :instrumenter, :lock
|
39
|
+
|
40
|
+
delegate :with, :current_state, :disconnect!, :reload, to: :connection_pool
|
41
|
+
delegate :instrument, to: :instrumenter
|
42
|
+
delegate :synchronize, to: :lock
|
43
|
+
|
44
|
+
include Logger
|
45
|
+
include DbStatements
|
46
|
+
|
47
|
+
def initialize(config)
|
48
|
+
@config = config
|
49
|
+
@instrumenter = ActiveSupport::Notifications.instrumenter
|
50
|
+
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
51
|
+
@connection_pool = nil
|
52
|
+
create_connection_pool
|
53
|
+
end
|
54
|
+
|
55
|
+
alias pool with
|
56
|
+
|
57
|
+
def pool_config
|
58
|
+
{ size: config[:pool], timeout: config[:timeout] }
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_connection_pool
|
62
|
+
synchronize do
|
63
|
+
return @connection_pool if @connection_pool
|
64
|
+
@connection_pool = Pool.new(pool_config) { DbClient.new(config) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module DbStatements
|
5
|
+
def query(sql)
|
6
|
+
pool do |client|
|
7
|
+
stmt = client.run(sql)
|
8
|
+
stmt.to_a
|
9
|
+
ensure
|
10
|
+
stmt.drop unless stmt.nil?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def query_rows(sql)
|
15
|
+
query(sql)
|
16
|
+
end
|
17
|
+
|
18
|
+
def query_value(sql)
|
19
|
+
rows = query(sql)
|
20
|
+
row = rows.first
|
21
|
+
row && row.first
|
22
|
+
end
|
23
|
+
|
24
|
+
def query_values(sql)
|
25
|
+
query(sql).map(&:first)
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute(sql, args = [])
|
29
|
+
pool do |client|
|
30
|
+
client.do(sql, *args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def raw_query(sql, args = [])
|
35
|
+
pool do |client|
|
36
|
+
stmt = client.run(sql, *args)
|
37
|
+
raw_result(stmt)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def exec_query(query, args = [])
|
42
|
+
sql, binds, args = query.exec_query_arguments(args)
|
43
|
+
log(sql, binds, args) do
|
44
|
+
pool do |client|
|
45
|
+
stmt = client.run(sql, *args)
|
46
|
+
columns = stmt.columns.values.map { |col| col.name.downcase }
|
47
|
+
rows = stmt.to_a
|
48
|
+
Db2Query::Result.new(columns, rows, query)
|
49
|
+
ensure
|
50
|
+
stmt.drop unless stmt.nil?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def reset_id_sequence!(table_name)
|
56
|
+
next_val = max_id(table_name) + 1
|
57
|
+
execute <<-SQL
|
58
|
+
ALTER TABLE #{table_name}
|
59
|
+
ALTER COLUMN ID
|
60
|
+
RESTART WITH #{next_val}
|
61
|
+
SET INCREMENT BY 1
|
62
|
+
SET NO CYCLE
|
63
|
+
SET CACHE 500
|
64
|
+
SET NO ORDER;
|
65
|
+
SQL
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def max_id(table_name)
|
70
|
+
query_value("SELECT COALESCE(MAX (ID),0) FROM #{table_name}")
|
71
|
+
end
|
72
|
+
|
73
|
+
def raw_result(stmt)
|
74
|
+
columns = stmt.columns.values.map { |col| col.name.downcase }
|
75
|
+
stmt.to_a.map do |row|
|
76
|
+
index, hash = [0, {}]
|
77
|
+
while index < columns.length
|
78
|
+
hash[columns[index].to_sym] = row[index]
|
79
|
+
index += 1
|
80
|
+
end
|
81
|
+
hash
|
82
|
+
end
|
83
|
+
ensure
|
84
|
+
stmt.drop unless stmt.nil?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class Definitions
|
5
|
+
attr_accessor :types, :types_map
|
6
|
+
attr_reader :arguments_map
|
7
|
+
|
8
|
+
def initialize(query_arguments_map, field_types_map)
|
9
|
+
@arguments_map = query_arguments_map
|
10
|
+
@types_map = field_types_map
|
11
|
+
describe
|
12
|
+
initialize_types
|
13
|
+
end
|
14
|
+
|
15
|
+
def describe
|
16
|
+
raise Db2Query::Error, "Please describe query definitions at #{self.class.name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def queries
|
20
|
+
@queries ||= {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def query_definition(query_name, &block)
|
24
|
+
definition = Query.new(query_name)
|
25
|
+
yield definition
|
26
|
+
queries[query_name] = definition
|
27
|
+
end
|
28
|
+
|
29
|
+
def lookup(query_name)
|
30
|
+
queries.fetch(query_name)
|
31
|
+
rescue
|
32
|
+
raise Db2Query::QueryDefinitionError.new(name, query_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def lookup_query(*args)
|
36
|
+
query_name, sql = query_definitions(args)
|
37
|
+
lookup(query_name).tap do |query|
|
38
|
+
query.define_sql(sql)
|
39
|
+
query.argument_keys.each do |key|
|
40
|
+
key, key_def = query_arg_key(query, key)
|
41
|
+
query.argument_types.store(key, data_type_instance(key_def))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def initialize_types
|
48
|
+
queries.each do |query_name, definition|
|
49
|
+
definition.columns.each do |column, col_def|
|
50
|
+
definition.types.store(column, data_type_instance(col_def))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def new_data_type(klass, options)
|
56
|
+
options.nil? ? klass.new : klass.new(**options)
|
57
|
+
rescue Exception => e
|
58
|
+
raise Db2Query::Error, e.message
|
59
|
+
end
|
60
|
+
|
61
|
+
def data_type_instance(column_definition)
|
62
|
+
data_type, options = column_definition
|
63
|
+
klass = @types_map.fetch(data_type)
|
64
|
+
new_data_type(klass, options)
|
65
|
+
rescue
|
66
|
+
raise Db2Query::Error, "Not supported `#{data_type}` data type"
|
67
|
+
end
|
68
|
+
|
69
|
+
def fetch_query_name(args)
|
70
|
+
placeholder = args.pop
|
71
|
+
placeholder.fetch(:query_name)
|
72
|
+
rescue
|
73
|
+
raise Db2Query::ImplementationError.new
|
74
|
+
end
|
75
|
+
|
76
|
+
def query_definitions(args)
|
77
|
+
case args.first
|
78
|
+
when Array
|
79
|
+
query_name = fetch_query_name(args.first)
|
80
|
+
[query_name, args.last]
|
81
|
+
else args
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def query_arg_key(query, key)
|
86
|
+
[key, unless arguments_map[query.query_name].nil?
|
87
|
+
arguments_map[query.query_name][key]
|
88
|
+
else
|
89
|
+
query.columns[key]
|
90
|
+
end]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/db2_query/error.rb
CHANGED
@@ -1,16 +1,81 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Db2Query
|
4
4
|
class Error < StandardError
|
5
5
|
end
|
6
6
|
|
7
|
-
class
|
8
|
-
def initialize(
|
9
|
-
|
10
|
-
@
|
11
|
-
|
7
|
+
class ArgumentError < StandardError
|
8
|
+
def initialize(given, expected)
|
9
|
+
@given = given
|
10
|
+
@expected = expected
|
11
|
+
super(message)
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
def message
|
15
|
+
"Wrong number of arguments (given #{@given}, expected #{@expected})"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ColumnError < StandardError
|
20
|
+
def initialize(def_cols, res_cols)
|
21
|
+
@def_cols = def_cols
|
22
|
+
@res_cols = res_cols
|
23
|
+
super(message)
|
24
|
+
end
|
25
|
+
|
26
|
+
def message
|
27
|
+
"Wrong number of columns (query definitions #{@def_cols}, query result #{@res_cols})"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class ConnectionError < StandardError
|
32
|
+
def initialize(odbc_message)
|
33
|
+
@odbc_message = odbc_message
|
34
|
+
super(message)
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
"Unable to activate ODBC DSN connection #{@odbc_message}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class ExtensionError < StandardError
|
43
|
+
end
|
44
|
+
|
45
|
+
class ImplementationError < StandardError
|
46
|
+
def message
|
47
|
+
"Method `fetch`, `fetch_list`, and `exec_query` can only be implemented inside a lambda query"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class ListTypeError < StandardError
|
52
|
+
end
|
53
|
+
|
54
|
+
class MissingListError < StandardError
|
55
|
+
end
|
56
|
+
|
57
|
+
class QueryDefinitionError < StandardError
|
58
|
+
def initialize(klass, query_name = nil, column = nil)
|
59
|
+
@klass = klass
|
60
|
+
@query_name = query_name
|
61
|
+
@column = column
|
62
|
+
super(message)
|
63
|
+
end
|
64
|
+
|
65
|
+
def message
|
66
|
+
if @query_name.nil?
|
67
|
+
"Definitions::#{@klass}Definitions file not found."
|
68
|
+
elsif @column.nil?
|
69
|
+
"No query definition found for #{@klass}:#{@query_name}"
|
70
|
+
else
|
71
|
+
"Column `#{@column}` not found at `#{@klass} query:#{@query_name}` Query Definitions."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class QueryMethodError < StandardError
|
77
|
+
def message
|
78
|
+
"The query body needs to be callable or is a SQL statement string"
|
79
|
+
end
|
15
80
|
end
|
16
81
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module FieldType
|
5
|
+
DEFAULT_FIELD_TYPES = {
|
6
|
+
binary: Db2Query::Type::Binary,
|
7
|
+
boolean: Db2Query::Type::Boolean,
|
8
|
+
string: Db2Query::Type::String,
|
9
|
+
varchar: Db2Query::Type::String,
|
10
|
+
longvarchar: Db2Query::Type::String,
|
11
|
+
decimal: Db2Query::Type::Decimal,
|
12
|
+
integer: Db2Query::Type::Integer,
|
13
|
+
date: Db2Query::Type::Date,
|
14
|
+
time: Db2Query::Type::Time,
|
15
|
+
timestamp: Db2Query::Type::Timestamp
|
16
|
+
}
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.send(:extend, ClassMethods)
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
mattr_reader :field_types_map
|
24
|
+
@@field_types_map = nil
|
25
|
+
|
26
|
+
def set_field_types(types = DEFAULT_FIELD_TYPES)
|
27
|
+
@@field_types_map = types
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|