db2_query 0.2.3 → 0.3.3
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/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
|