fluiddb2 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +165 -0
- data/README.md +10 -0
- data/lib/fluiddb2/firebird.rb +126 -0
- data/lib/fluiddb2/mock.rb +103 -0
- data/lib/fluiddb2/mysql.rb +89 -0
- data/lib/fluiddb2/mysql2.rb +92 -0
- data/lib/fluiddb2/pgsql.rb +128 -0
- data/lib/fluiddb2/sqlite.rb +111 -0
- data/lib/fluiddb2/tiny_tds.rb +139 -0
- data/lib/fluiddb2.rb +210 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7d3233bc931c69ea807e944dd613485b0f10212c
|
4
|
+
data.tar.gz: 3c14618c2e985e2a1e419ebffa298dd05b6afccd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 96a412a1de13c85d00e0fe36ed6bcb144fff9c9a38bb8a48f7e45592793bb1da83b1f104dea45d4c743bebb2448c4cd4c3cef4ad468046cd4a83c6c03cb01dde
|
7
|
+
data.tar.gz: 3204ac238c68f9a31121de945ae4f5dd3070b0f10732b9deb741623e224c3f5062cbfd64e6cbe62be0be30233600590ac0fde34446275a507380c72073bad799
|
data/LICENSE
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
GNU LESSER GENERAL PUBLIC LICENSE
|
2
|
+
Version 3, 29 June 2007
|
3
|
+
|
4
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
5
|
+
Everyone is permitted to copy and distribute verbatim copies
|
6
|
+
of this license document, but changing it is not allowed.
|
7
|
+
|
8
|
+
|
9
|
+
This version of the GNU Lesser General Public License incorporates
|
10
|
+
the terms and conditions of version 3 of the GNU General Public
|
11
|
+
License, supplemented by the additional permissions listed below.
|
12
|
+
|
13
|
+
0. Additional Definitions.
|
14
|
+
|
15
|
+
As used herein, "this License" refers to version 3 of the GNU Lesser
|
16
|
+
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
17
|
+
General Public License.
|
18
|
+
|
19
|
+
"The Library" refers to a covered work governed by this License,
|
20
|
+
other than an Application or a Combined Work as defined below.
|
21
|
+
|
22
|
+
An "Application" is any work that makes use of an interface provided
|
23
|
+
by the Library, but which is not otherwise based on the Library.
|
24
|
+
Defining a subclass of a class defined by the Library is deemed a mode
|
25
|
+
of using an interface provided by the Library.
|
26
|
+
|
27
|
+
A "Combined Work" is a work produced by combining or linking an
|
28
|
+
Application with the Library. The particular version of the Library
|
29
|
+
with which the Combined Work was made is also called the "Linked
|
30
|
+
Version".
|
31
|
+
|
32
|
+
The "Minimal Corresponding Source" for a Combined Work means the
|
33
|
+
Corresponding Source for the Combined Work, excluding any source code
|
34
|
+
for portions of the Combined Work that, considered in isolation, are
|
35
|
+
based on the Application, and not on the Linked Version.
|
36
|
+
|
37
|
+
The "Corresponding Application Code" for a Combined Work means the
|
38
|
+
object code and/or source code for the Application, including any data
|
39
|
+
and utility programs needed for reproducing the Combined Work from the
|
40
|
+
Application, but excluding the System Libraries of the Combined Work.
|
41
|
+
|
42
|
+
1. Exception to Section 3 of the GNU GPL.
|
43
|
+
|
44
|
+
You may convey a covered work under sections 3 and 4 of this License
|
45
|
+
without being bound by section 3 of the GNU GPL.
|
46
|
+
|
47
|
+
2. Conveying Modified Versions.
|
48
|
+
|
49
|
+
If you modify a copy of the Library, and, in your modifications, a
|
50
|
+
facility refers to a function or data to be supplied by an Application
|
51
|
+
that uses the facility (other than as an argument passed when the
|
52
|
+
facility is invoked), then you may convey a copy of the modified
|
53
|
+
version:
|
54
|
+
|
55
|
+
a) under this License, provided that you make a good faith effort to
|
56
|
+
ensure that, in the event an Application does not supply the
|
57
|
+
function or data, the facility still operates, and performs
|
58
|
+
whatever part of its purpose remains meaningful, or
|
59
|
+
|
60
|
+
b) under the GNU GPL, with none of the additional permissions of
|
61
|
+
this License applicable to that copy.
|
62
|
+
|
63
|
+
3. Object Code Incorporating Material from Library Header Files.
|
64
|
+
|
65
|
+
The object code form of an Application may incorporate material from
|
66
|
+
a header file that is part of the Library. You may convey such object
|
67
|
+
code under terms of your choice, provided that, if the incorporated
|
68
|
+
material is not limited to numerical parameters, data structure
|
69
|
+
layouts and accessors, or small macros, inline functions and templates
|
70
|
+
(ten or fewer lines in length), you do both of the following:
|
71
|
+
|
72
|
+
a) Give prominent notice with each copy of the object code that the
|
73
|
+
Library is used in it and that the Library and its use are
|
74
|
+
covered by this License.
|
75
|
+
|
76
|
+
b) Accompany the object code with a copy of the GNU GPL and this license
|
77
|
+
document.
|
78
|
+
|
79
|
+
4. Combined Works.
|
80
|
+
|
81
|
+
You may convey a Combined Work under terms of your choice that,
|
82
|
+
taken together, effectively do not restrict modification of the
|
83
|
+
portions of the Library contained in the Combined Work and reverse
|
84
|
+
engineering for debugging such modifications, if you also do each of
|
85
|
+
the following:
|
86
|
+
|
87
|
+
a) Give prominent notice with each copy of the Combined Work that
|
88
|
+
the Library is used in it and that the Library and its use are
|
89
|
+
covered by this License.
|
90
|
+
|
91
|
+
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
92
|
+
document.
|
93
|
+
|
94
|
+
c) For a Combined Work that displays copyright notices during
|
95
|
+
execution, include the copyright notice for the Library among
|
96
|
+
these notices, as well as a reference directing the user to the
|
97
|
+
copies of the GNU GPL and this license document.
|
98
|
+
|
99
|
+
d) Do one of the following:
|
100
|
+
|
101
|
+
0) Convey the Minimal Corresponding Source under the terms of this
|
102
|
+
License, and the Corresponding Application Code in a form
|
103
|
+
suitable for, and under terms that permit, the user to
|
104
|
+
recombine or relink the Application with a modified version of
|
105
|
+
the Linked Version to produce a modified Combined Work, in the
|
106
|
+
manner specified by section 6 of the GNU GPL for conveying
|
107
|
+
Corresponding Source.
|
108
|
+
|
109
|
+
1) Use a suitable shared library mechanism for linking with the
|
110
|
+
Library. A suitable mechanism is one that (a) uses at run time
|
111
|
+
a copy of the Library already present on the user's computer
|
112
|
+
system, and (b) will operate properly with a modified version
|
113
|
+
of the Library that is interface-compatible with the Linked
|
114
|
+
Version.
|
115
|
+
|
116
|
+
e) Provide Installation Information, but only if you would otherwise
|
117
|
+
be required to provide such information under section 6 of the
|
118
|
+
GNU GPL, and only to the extent that such information is
|
119
|
+
necessary to install and execute a modified version of the
|
120
|
+
Combined Work produced by recombining or relinking the
|
121
|
+
Application with a modified version of the Linked Version. (If
|
122
|
+
you use option 4d0, the Installation Information must accompany
|
123
|
+
the Minimal Corresponding Source and Corresponding Application
|
124
|
+
Code. If you use option 4d1, you must provide the Installation
|
125
|
+
Information in the manner specified by section 6 of the GNU GPL
|
126
|
+
for conveying Corresponding Source.)
|
127
|
+
|
128
|
+
5. Combined Libraries.
|
129
|
+
|
130
|
+
You may place library facilities that are a work based on the
|
131
|
+
Library side by side in a single library together with other library
|
132
|
+
facilities that are not Applications and are not covered by this
|
133
|
+
License, and convey such a combined library under terms of your
|
134
|
+
choice, if you do both of the following:
|
135
|
+
|
136
|
+
a) Accompany the combined library with a copy of the same work based
|
137
|
+
on the Library, uncombined with any other library facilities,
|
138
|
+
conveyed under the terms of this License.
|
139
|
+
|
140
|
+
b) Give prominent notice with the combined library that part of it
|
141
|
+
is a work based on the Library, and explaining where to find the
|
142
|
+
accompanying uncombined form of the same work.
|
143
|
+
|
144
|
+
6. Revised Versions of the GNU Lesser General Public License.
|
145
|
+
|
146
|
+
The Free Software Foundation may publish revised and/or new versions
|
147
|
+
of the GNU Lesser General Public License from time to time. Such new
|
148
|
+
versions will be similar in spirit to the present version, but may
|
149
|
+
differ in detail to address new problems or concerns.
|
150
|
+
|
151
|
+
Each version is given a distinguishing version number. If the
|
152
|
+
Library as you received it specifies that a certain numbered version
|
153
|
+
of the GNU Lesser General Public License "or any later version"
|
154
|
+
applies to it, you have the option of following the terms and
|
155
|
+
conditions either of that published version or of any later version
|
156
|
+
published by the Free Software Foundation. If the Library as you
|
157
|
+
received it does not specify a version number of the GNU Lesser
|
158
|
+
General Public License, you may choose any version of the GNU Lesser
|
159
|
+
General Public License ever published by the Free Software Foundation.
|
160
|
+
|
161
|
+
If the Library as you received it specifies that a proxy can decide
|
162
|
+
whether future versions of the GNU Lesser General Public License shall
|
163
|
+
apply, that proxy's public statement of acceptance of any version is
|
164
|
+
permanent authorization for you to choose that version for the
|
165
|
+
Library.
|
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'FluidDb2'
|
2
|
+
require 'fb'
|
3
|
+
include Fb
|
4
|
+
|
5
|
+
module FluidDb2
|
6
|
+
# Firebird
|
7
|
+
class Firebird < Base
|
8
|
+
# Connect to Db.
|
9
|
+
#
|
10
|
+
# @param [String] uri a location for the resource to which we will attach,
|
11
|
+
# eg mysql://user:pass@127.0.0.1/foo
|
12
|
+
def connect
|
13
|
+
uri = @uri
|
14
|
+
|
15
|
+
user = uri.user || 'sysdba'
|
16
|
+
password = uri.password || 'masterkey'
|
17
|
+
port = uri.port || 3050
|
18
|
+
|
19
|
+
path = uri.path
|
20
|
+
path = path.slice(1, uri.path.length - 1) if path.slice(0, 3) == '/C:'
|
21
|
+
path = URI.unescape(path)
|
22
|
+
|
23
|
+
# The Database class acts as a factory for Connections.
|
24
|
+
# It can also create and drop databases.
|
25
|
+
db = Database.new(:database => "#{uri.host}/#{port}:#{path}",
|
26
|
+
:username => user,
|
27
|
+
:password => password)
|
28
|
+
# :database is the only parameter without a default.
|
29
|
+
# Let's connect to the database, creating it if it doesn't already exist.
|
30
|
+
@connection = db.connect rescue db.create.connect
|
31
|
+
end
|
32
|
+
|
33
|
+
def close
|
34
|
+
@connection.close
|
35
|
+
end
|
36
|
+
|
37
|
+
def query_for_array(sql, params = [])
|
38
|
+
sql = format_to_sql(sql, params)
|
39
|
+
list = @connection.query(:hash, sql)
|
40
|
+
|
41
|
+
case list.length
|
42
|
+
when -1
|
43
|
+
fail FluidDb2::ConnectionError
|
44
|
+
when 0
|
45
|
+
fail FluidDb2::NoDataFoundError
|
46
|
+
when 1
|
47
|
+
return list[0]
|
48
|
+
else
|
49
|
+
fail FluidDb2::TooManyRowsError
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def query_for_value(sql, params = [])
|
54
|
+
sql = format_to_sql(sql, params)
|
55
|
+
results = @connection.query(sql)
|
56
|
+
|
57
|
+
case results.length
|
58
|
+
when -1
|
59
|
+
fail FluidDb::ConnectionError
|
60
|
+
when 0
|
61
|
+
fail FluidDb::NoDataFoundError
|
62
|
+
when 1
|
63
|
+
return results[0][0]
|
64
|
+
else
|
65
|
+
fail FluidDb::TooManyRowsError
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def query_for_resultset(sql, params = [])
|
70
|
+
sql = format_to_sql(sql, params)
|
71
|
+
list = @connection.query(:hash, sql)
|
72
|
+
|
73
|
+
case list.length
|
74
|
+
when -1
|
75
|
+
fail FluidDb::ConnectionError
|
76
|
+
else
|
77
|
+
return list
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def execute(sql, params = [], expected_affected_rows = nil)
|
82
|
+
sql = format_to_sql(sql, params)
|
83
|
+
verbose_log "#{self.class.name}.execute. #{sql}"
|
84
|
+
affected_rows = @connection.execute(sql)
|
85
|
+
|
86
|
+
if !expected_affected_rows.nil? && affected_rows != expected_affected_rows
|
87
|
+
fail ExpectedAffectedRowsError,
|
88
|
+
"Expected affected rows, #{expected_affected_rows}, Actual affected rows, #{affected_rows}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def exec_params(sql, params, expected_affected_rows = nil)
|
93
|
+
parts = sql.split('?')
|
94
|
+
sql = ''
|
95
|
+
parts.each_with_index do |p, idx|
|
96
|
+
sql += p
|
97
|
+
sql += "$#{idx + 1}" if idx < parts.length - 1
|
98
|
+
end
|
99
|
+
affected_rows = @connection.exec_params(sql, params)
|
100
|
+
|
101
|
+
if !expected_affected_rows.nil? && affected_rows != expected_affected_rows
|
102
|
+
fail ExpectedAffectedRowsError,
|
103
|
+
"Expected affected rows, #{expected_affected_rows}, Actual affected rows, #{affected_rows}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def insert(_sql, _params)
|
108
|
+
fail 'Firebird uses SEQUENCES, so possibly easier to use 2 executes'
|
109
|
+
end
|
110
|
+
|
111
|
+
# Transaction Semantics
|
112
|
+
def begin
|
113
|
+
@connection.transaction
|
114
|
+
end
|
115
|
+
|
116
|
+
# Transaction Semantics
|
117
|
+
def commit
|
118
|
+
@connection.commit
|
119
|
+
end
|
120
|
+
|
121
|
+
# Transaction Semantics
|
122
|
+
def rollback
|
123
|
+
@connection.rollback
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'FluidDb2'
|
2
|
+
|
3
|
+
module FluidDb2
|
4
|
+
class SqlNotMatchedError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
# A constant way of enabling testing for FluidDb
|
8
|
+
class Mock < Base
|
9
|
+
attr_reader :hash
|
10
|
+
|
11
|
+
def initialize(_uri)
|
12
|
+
@hash = {}
|
13
|
+
@verbose = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def verbose
|
17
|
+
@verbose = true
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def connect
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_sql_from_hash(sql)
|
28
|
+
fail SqlNotMatchedError, sql unless @hash.key?(sql)
|
29
|
+
|
30
|
+
@hash[sql]
|
31
|
+
end
|
32
|
+
|
33
|
+
def query_for_array(sql, params = [])
|
34
|
+
sql = format_to_sql(sql, params)
|
35
|
+
puts "FluidDb::Mock.query_for_array. sql: #{sql}" if @verbose == true
|
36
|
+
|
37
|
+
results = get_sql_from_hash(sql)
|
38
|
+
case results.length
|
39
|
+
when 0
|
40
|
+
fail FluidDb::NoDataFoundError
|
41
|
+
when 1
|
42
|
+
return results.first
|
43
|
+
else
|
44
|
+
fail FluidDb::TooManyRowsError
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def query_for_value(sql, params = [])
|
49
|
+
sql = format_to_sql(sql, params)
|
50
|
+
puts "FluidDb::Mock.queryForValue. sql: #{sql}" if @verbose == true
|
51
|
+
|
52
|
+
results = get_sql_from_hash(sql)
|
53
|
+
case results.length
|
54
|
+
when 0
|
55
|
+
fail FluidDb::NoDataFoundError
|
56
|
+
when 1
|
57
|
+
return results.first.first[1]
|
58
|
+
else
|
59
|
+
fail FluidDb::TooManyRowsError
|
60
|
+
end
|
61
|
+
@hash[sql]
|
62
|
+
end
|
63
|
+
|
64
|
+
def query_for_resultset(sql, params = [])
|
65
|
+
sql = format_to_sql(sql, params)
|
66
|
+
puts "FluidDb::Mock.queryForResultset. sql: #{sql}" if @verbose == true
|
67
|
+
get_sql_from_hash(sql)
|
68
|
+
end
|
69
|
+
|
70
|
+
def execute(sql, params = [], _expected_affected_rows = nil)
|
71
|
+
sql = format_to_sql(sql, params)
|
72
|
+
puts "FluidDb::Mock.execute. sql: #{sql}" if @verbose == true
|
73
|
+
get_sql_from_hash(sql)
|
74
|
+
end
|
75
|
+
|
76
|
+
def insert(_sql, _params)
|
77
|
+
fail 'Mock uses SEQUENCES, so possibly easier to use 2 executes'
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_sql(sql, result)
|
81
|
+
raise TypeError.new( "Expecting an Array of Hashes, eg [{'field1'=>1, 'field2'=>2}]. Note, the Array may be empty" ) unless result.is_a? Array
|
82
|
+
|
83
|
+
@hash[sql] = result
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_sql_with_params(sql, params, result)
|
87
|
+
sql = format_to_sql(sql, params)
|
88
|
+
add_sql(sql, result)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Transaction Semantics
|
92
|
+
def begin
|
93
|
+
end
|
94
|
+
|
95
|
+
# Transaction Semantics
|
96
|
+
def commit
|
97
|
+
end
|
98
|
+
|
99
|
+
# Transaction Semantics
|
100
|
+
def rollback
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'FluidDb2'
|
2
|
+
require 'mysql'
|
3
|
+
|
4
|
+
module FluidDb2
|
5
|
+
# Mysql
|
6
|
+
class Mysql < Base
|
7
|
+
# Connect to Db.
|
8
|
+
#
|
9
|
+
# @param [String] uri a location for the resource to which we will attach,
|
10
|
+
# eg mysql://user:pass@127.0.0.1/foo
|
11
|
+
def connect
|
12
|
+
uri = @uri
|
13
|
+
database = uri.path.sub('/', '')
|
14
|
+
|
15
|
+
@connection = ::Mysql.new uri.host, uri.user, uri.password, database, nil, nil, ::Mysql::CLIENT_FOUND_ROWS
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@connection.close
|
20
|
+
end
|
21
|
+
|
22
|
+
def query_for_array(sql, params = [])
|
23
|
+
sql = format_to_sql(sql, params)
|
24
|
+
results = @connection.query(sql)
|
25
|
+
|
26
|
+
case results.num_rows
|
27
|
+
when -1
|
28
|
+
fail FluidDb::ConnectionError
|
29
|
+
when 0
|
30
|
+
fail FluidDb::NoDataFoundError
|
31
|
+
when 1
|
32
|
+
r = results.fetch_hash
|
33
|
+
return r
|
34
|
+
else
|
35
|
+
fail FluidDb::TooManyRowsError
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def query_for_value(sql, params = [])
|
40
|
+
sql = format_to_sql(sql, params)
|
41
|
+
results = @connection.query(sql)
|
42
|
+
|
43
|
+
case results.num_rows
|
44
|
+
when -1
|
45
|
+
fail FluidDb::ConnectionError
|
46
|
+
when 0
|
47
|
+
fail FluidDb::NoDataFoundError
|
48
|
+
when 1
|
49
|
+
r = nil
|
50
|
+
results.each do |row|
|
51
|
+
r = row
|
52
|
+
end
|
53
|
+
return r[0]
|
54
|
+
else
|
55
|
+
fail FluidDb::TooManyRowsError
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def query_for_resultset(sql, params = [])
|
60
|
+
sql = format_to_sql(sql, params)
|
61
|
+
results = @connection.query(sql)
|
62
|
+
|
63
|
+
case results.num_rows
|
64
|
+
when -1
|
65
|
+
fail FluidDb::ConnectionError
|
66
|
+
else
|
67
|
+
list = []
|
68
|
+
results.each_hash do |row|
|
69
|
+
list.push row
|
70
|
+
end
|
71
|
+
return list
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def execute(sql, params = [], expected_affected_rows = nil)
|
76
|
+
sql = format_to_sql(sql, params)
|
77
|
+
@connection.query(sql)
|
78
|
+
|
79
|
+
if !expected_affected_rows.nil? && @connection.affected_rows != expected_affected_rows
|
80
|
+
fail ExpectedAffectedRowsError, "Expected affected rows, #{expected_affected_rows}, Actual affected rows, #{@connection.affected_rows}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def insert(sql, params)
|
85
|
+
execute(sql, params)
|
86
|
+
@connection.insert_id
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'FluidDb2'
|
2
|
+
require 'mysql2'
|
3
|
+
|
4
|
+
module FluidDb2
|
5
|
+
class Mysql2 < Base
|
6
|
+
# Connect to Db.
|
7
|
+
#
|
8
|
+
# @param [String] uri a location for the resource to which we will attach,
|
9
|
+
# eg mysql://user:pass@127.0.0.1/foo
|
10
|
+
def connect
|
11
|
+
uri = @uri
|
12
|
+
@connection = ::Mysql2::Client.new(:host => uri.host,
|
13
|
+
:database => uri.path.sub('/', ''),
|
14
|
+
:username => uri.user,
|
15
|
+
:flags => ::Mysql2::Client::FOUND_ROWS)
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@connection.close
|
20
|
+
end
|
21
|
+
|
22
|
+
def query_for_array(sql, params = [])
|
23
|
+
sql = format_to_sql(sql, params)
|
24
|
+
results = @connection.query(sql)
|
25
|
+
|
26
|
+
case results.count
|
27
|
+
when -1
|
28
|
+
fail FluidDb::ConnectionError
|
29
|
+
when 0
|
30
|
+
fail FluidDb::NoDataFoundError
|
31
|
+
when 1
|
32
|
+
r = nil
|
33
|
+
results.each do |row|
|
34
|
+
r = row
|
35
|
+
end
|
36
|
+
return r
|
37
|
+
else
|
38
|
+
fail FluidDb::TooManyRowsError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def query_for_value(sql, params = [])
|
43
|
+
sql = format_to_sql(sql, params)
|
44
|
+
results = @connection.query(sql, :as => :array)
|
45
|
+
|
46
|
+
case results.count
|
47
|
+
when -1
|
48
|
+
fail FluidDb::ConnectionError
|
49
|
+
when 0
|
50
|
+
fail FluidDb::NoDataFoundError
|
51
|
+
when 1
|
52
|
+
r = nil
|
53
|
+
results.each do |row|
|
54
|
+
r = row
|
55
|
+
end
|
56
|
+
return r[0]
|
57
|
+
else
|
58
|
+
fail FluidDb::TooManyRowsError
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def query_for_resultset(sql, params = [])
|
63
|
+
sql = format_to_sql(sql, params)
|
64
|
+
results = @connection.query(sql)
|
65
|
+
|
66
|
+
case results.count
|
67
|
+
when -1
|
68
|
+
fail FluidDb::ConnectionError
|
69
|
+
else
|
70
|
+
list = []
|
71
|
+
results.each do |row|
|
72
|
+
list.push row
|
73
|
+
end
|
74
|
+
return list
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def execute(sql, params = [], expected_affected_rows = nil)
|
79
|
+
sql = format_to_sql(sql, params)
|
80
|
+
@connection.query(sql)
|
81
|
+
|
82
|
+
if !expected_affected_rows.nil? && @connection.affected_rows != expected_affected_rows
|
83
|
+
raise ExpectedAffectedRowsError.new( "Expected affected rows, #{expected_affected_rows}, Actual affected rows, #{@connection.affected_rows}")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def insert(sql, params)
|
88
|
+
execute(sql, params)
|
89
|
+
@connection.last_id
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'FluidDb2'
|
2
|
+
require 'pg'
|
3
|
+
|
4
|
+
module FluidDb2
|
5
|
+
# Pgsql
|
6
|
+
class Pgsql < Base
|
7
|
+
# Connect to Db.
|
8
|
+
#
|
9
|
+
# @param [String] uri a location for the resource to which we will attach,
|
10
|
+
# eg mysql://user:pass@127.0.0.1/foo
|
11
|
+
def connect
|
12
|
+
uri = @uri
|
13
|
+
host = uri.host
|
14
|
+
dbname = uri.path.sub('/', '')
|
15
|
+
|
16
|
+
hash = Hash['host', host, 'dbname', dbname]
|
17
|
+
hash['port'] = uri.port unless uri.port.nil?
|
18
|
+
hash['user'] = uri.user unless uri.user.nil?
|
19
|
+
hash['password'] = uri.password unless uri.password.nil?
|
20
|
+
|
21
|
+
@connection = PG.connect(hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
@connection.close
|
26
|
+
end
|
27
|
+
|
28
|
+
def query_for_array(sql, params = [])
|
29
|
+
sql = FluidDb2.format_to_sql(sql, params)
|
30
|
+
results = @connection.exec(sql)
|
31
|
+
|
32
|
+
case results.num_tuples
|
33
|
+
when -1
|
34
|
+
fail FluidDb2::ConnectionError
|
35
|
+
when 0
|
36
|
+
fail FluidDb2::NoDataFoundError
|
37
|
+
when 1
|
38
|
+
return FluidDb2.convert_tuple_to_hash(results.fields, results, 0)
|
39
|
+
else
|
40
|
+
fail FluidDb2::TooManyRowsError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def query_for_value(sql, params = [])
|
45
|
+
sql = FluidDb2.format_to_sql(sql, params)
|
46
|
+
results = @connection.exec(sql)
|
47
|
+
|
48
|
+
case results.num_tuples
|
49
|
+
when -1
|
50
|
+
fail FluidDb2::ConnectionError
|
51
|
+
when 0
|
52
|
+
fail FluidDb2::NoDataFoundError
|
53
|
+
when 1
|
54
|
+
return results.getvalue(0, 0)
|
55
|
+
else
|
56
|
+
fail FluidDb2::TooManyRowsError
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def query_for_resultset(sql, params = [])
|
61
|
+
sql = FluidDb2.format_to_sql(sql, params)
|
62
|
+
results = @connection.exec(sql)
|
63
|
+
|
64
|
+
case results.num_tuples
|
65
|
+
when -1
|
66
|
+
fail FluidDb2::ConnectionError
|
67
|
+
else
|
68
|
+
list = []
|
69
|
+
fields = results.fields
|
70
|
+
0.upto(results.ntuples - 1) do |nbr|
|
71
|
+
list.push FluidDb2.convert_tuple_to_hash(fields, results, nbr)
|
72
|
+
end
|
73
|
+
|
74
|
+
return list
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def execute(sql, params = [], expected_affected_rows = nil)
|
79
|
+
sql = FluidDb2.format_to_sql(sql, params)
|
80
|
+
|
81
|
+
verbose_log "#{self.class.name}.execute. #{sql}"
|
82
|
+
r = @connection.exec(sql)
|
83
|
+
|
84
|
+
if !expected_affected_rows.nil? && r.cmd_tuples != expected_affected_rows
|
85
|
+
fail ExpectedAffectedRowsError, "Expected affected rows, #{expected_affected_rows}, Actual affected rows, #{r.cmd_tuples}"
|
86
|
+
end
|
87
|
+
rescue PG::Error => e
|
88
|
+
raise DuplicateKeyError(e.message) unless e.message.index('duplicate key value violates unique constraint').nil?
|
89
|
+
raise e
|
90
|
+
end
|
91
|
+
|
92
|
+
def exec_params(sql, params = [], expected_affected_rows = nil)
|
93
|
+
parts = sql.split('?')
|
94
|
+
sql = ''
|
95
|
+
parts.each_with_index do |p, idx|
|
96
|
+
sql += p
|
97
|
+
sql += "$#{idx + 1}" if idx < parts.length - 1
|
98
|
+
end
|
99
|
+
r = @connection.exec_params(sql, params)
|
100
|
+
|
101
|
+
if !expected_affected_rows.nil? and r.cmd_tuples != expected_affected_rows
|
102
|
+
fail ExpectedAffectedRowsError, "Expected affected rows, #{expected_affected_rows}, Actual affected rows, #{r.cmd_tuples}"
|
103
|
+
end
|
104
|
+
rescue PG::Error => e
|
105
|
+
raise DuplicateKeyError(e.message) unless e.message.index("duplicate key value violates unique constraint").nil?
|
106
|
+
raise e
|
107
|
+
end
|
108
|
+
|
109
|
+
# Transaction Semantics
|
110
|
+
def begin
|
111
|
+
@connection.exec('BEGIN', [])
|
112
|
+
end
|
113
|
+
|
114
|
+
# Transaction Semantics
|
115
|
+
def commit
|
116
|
+
@connection.exec('COMMIT', [])
|
117
|
+
end
|
118
|
+
|
119
|
+
# Transaction Semantics
|
120
|
+
def rollback
|
121
|
+
@connection.exec('ROLLBACK', [])
|
122
|
+
end
|
123
|
+
|
124
|
+
def insert(_sql, _params)
|
125
|
+
fail 'Pgsql uses SEQUENCES, so possibly easier to use 2 executes'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'FluidDb2'
|
2
|
+
require 'sqlite3'
|
3
|
+
|
4
|
+
module FluidDb2
|
5
|
+
# SQLite
|
6
|
+
class SQLite < Base
|
7
|
+
# Connect to Db.
|
8
|
+
#
|
9
|
+
# @param [String] uri a location for the resource to which we will attach,
|
10
|
+
# eg mysql://user:pass@127.0.0.1/foo
|
11
|
+
def connect
|
12
|
+
uri = @uri
|
13
|
+
@connection = SQLite3::Database.new uri.path
|
14
|
+
end
|
15
|
+
|
16
|
+
def close
|
17
|
+
@connection.close
|
18
|
+
end
|
19
|
+
|
20
|
+
def query_for_array(sql, params = [])
|
21
|
+
sql = format_to_sql(sql, params)
|
22
|
+
@connection.results_as_hash = true
|
23
|
+
results = @connection.execute(sql)
|
24
|
+
|
25
|
+
case results.length
|
26
|
+
when -1
|
27
|
+
fail FluidDb::ConnectionError
|
28
|
+
when 0
|
29
|
+
fail FluidDb::NoDataFoundError
|
30
|
+
when 1
|
31
|
+
return results[0]
|
32
|
+
else
|
33
|
+
fail FluidDb::TooManyRowsError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def query_for_value(sql, params = [])
|
38
|
+
sql = format_to_sql(sql, params)
|
39
|
+
@connection.results_as_hash = false
|
40
|
+
results = @connection.execute(sql)
|
41
|
+
|
42
|
+
case results.length
|
43
|
+
when -1
|
44
|
+
fail FluidDb::ConnectionError
|
45
|
+
when 0
|
46
|
+
fail FluidDb::NoDataFoundError
|
47
|
+
when 1
|
48
|
+
return results[0][0]
|
49
|
+
else
|
50
|
+
fail FluidDb::TooManyRowsError
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def query_for_resultset(sql, params = [])
|
55
|
+
sql = format_to_sql(sql, params)
|
56
|
+
@connection.results_as_hash = true
|
57
|
+
results = @connection.execute(sql)
|
58
|
+
|
59
|
+
case results.length
|
60
|
+
when -1
|
61
|
+
fail FluidDb::ConnectionError
|
62
|
+
else
|
63
|
+
return results
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def execute(sql, params = [], expected_affected_rows = nil)
|
68
|
+
sql = format_to_sql(sql, params)
|
69
|
+
|
70
|
+
verbose_log "#{self.class.name}.execute. #{sql}"
|
71
|
+
r = @connection.execute(sql)
|
72
|
+
|
73
|
+
if !expected_affected_rows.nil? && r.changes != expected_affected_rows
|
74
|
+
fail ExpectedAffectedRowsError, "Expected affected rows, #{expected_affected_rows}, Actual affected rows, #{r.cmd_tuples}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def exec_params(sql, params = [], expected_affected_rows = nil)
|
79
|
+
parts = sql.split('?')
|
80
|
+
sql = ''
|
81
|
+
parts.each_with_index do |p, idx|
|
82
|
+
sql += p
|
83
|
+
sql += "$#{idx + 1}" if idx < parts.length - 1
|
84
|
+
end
|
85
|
+
r = @connection.exec_params(sql, params)
|
86
|
+
|
87
|
+
if !expected_affected_rows.nil? && r.changes != expected_affected_rows
|
88
|
+
fail ExpectedAffectedRowsError, "Expected affected rows, #{expected_affected_rows}, Actual affected rows, #{r.cmd_tuples}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Transaction Semantics
|
93
|
+
def begin
|
94
|
+
@connection.transaction
|
95
|
+
end
|
96
|
+
|
97
|
+
# Transaction Semantics
|
98
|
+
def commit
|
99
|
+
@connection.commit
|
100
|
+
end
|
101
|
+
|
102
|
+
# Transaction Semantics
|
103
|
+
def rollback
|
104
|
+
@connection.rollback
|
105
|
+
end
|
106
|
+
|
107
|
+
def insert(_sql, _params)
|
108
|
+
fail 'SQLite uses SEQUENCES, so possibly easier to use 2 executes'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'FluidDb2'
|
2
|
+
require 'tiny_tds'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module FluidDb2
|
6
|
+
class TinyTds < Base
|
7
|
+
|
8
|
+
# Connect to Db.
|
9
|
+
#
|
10
|
+
# @param [String] uri a location for the resource to which we will attach,
|
11
|
+
# eg tinytds://<user>:<pass>@<dataserver>/<database>
|
12
|
+
def connect
|
13
|
+
uri = @uri
|
14
|
+
|
15
|
+
dataserver = uri.host
|
16
|
+
database = uri.path.sub('/', '')
|
17
|
+
username = URI.unescape(uri.user)
|
18
|
+
password = uri.password
|
19
|
+
|
20
|
+
if dataserver == '' || database == ''
|
21
|
+
fail '*** You need to specify both a dataserver and a database for ' \
|
22
|
+
'the tinytds driver. Expected format: ' \
|
23
|
+
'tinytds://<user>:<pass>@<dataserver>/<database>\n' \
|
24
|
+
'*** The specified dataserver should have an entry in ' \
|
25
|
+
'/etc/freetds/freetds.conf'
|
26
|
+
end
|
27
|
+
|
28
|
+
if username == '' || password == ''
|
29
|
+
puts '*** Warning - you will normally need to specify both a username ' \
|
30
|
+
'and password for the tinytds driver to work correctly.'
|
31
|
+
end
|
32
|
+
|
33
|
+
hash = Hash[:username, username,
|
34
|
+
:password, password,
|
35
|
+
:database, database,
|
36
|
+
:dataserver, dataserver]
|
37
|
+
fail_over_data_server = nil
|
38
|
+
unless uri.query.nil?
|
39
|
+
cgi = CGI.parse(uri.query)
|
40
|
+
hash[:timeout] = cgi['timeout'][0].to_i if cgi.key?('timeout')
|
41
|
+
if cgi.key?('host')
|
42
|
+
hash.delete(:dataserver)
|
43
|
+
hash[:host] = dataserver
|
44
|
+
end
|
45
|
+
|
46
|
+
fail_over_data_server =
|
47
|
+
cgi['failoverdataserver'][0] if cgi.key?('failoverdataserver')
|
48
|
+
end
|
49
|
+
|
50
|
+
begin
|
51
|
+
@connection = ::TinyTds::Client.new(hash)
|
52
|
+
rescue ::TinyTds::Error => e
|
53
|
+
# Message for an incorrect password,
|
54
|
+
# Login failed. The login is from an untrusted domain and cannot be used
|
55
|
+
# with Windows authentication.
|
56
|
+
# Message for unavailable db
|
57
|
+
# Cannot open user default database. Login failed.
|
58
|
+
if e.message == 'Cannot open user default database. Login failed.' &&
|
59
|
+
!fail_over_data_server.nil?
|
60
|
+
hash[:dataserver] = fail_over_data_server
|
61
|
+
@connection = ::TinyTds::Client.new(hash)
|
62
|
+
else
|
63
|
+
raise e
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
fail 'Unable to connect to the database' unless @connection.active?
|
68
|
+
end
|
69
|
+
|
70
|
+
def close
|
71
|
+
@connection.close
|
72
|
+
end
|
73
|
+
|
74
|
+
def escape_string(input)
|
75
|
+
@connection.escape(input)
|
76
|
+
end
|
77
|
+
|
78
|
+
def query_for_array(sql, params = [])
|
79
|
+
sql = format_to_sql(sql, params)
|
80
|
+
results = @connection.execute(sql)
|
81
|
+
|
82
|
+
count = 0
|
83
|
+
tuple = ''
|
84
|
+
results.each do |row|
|
85
|
+
count += 1
|
86
|
+
fail FluidDb2::TooManyRowsError if count > 1
|
87
|
+
tuple = row
|
88
|
+
end
|
89
|
+
fail FluidDb2::NoDataFoundError if count == 0
|
90
|
+
tuple
|
91
|
+
end
|
92
|
+
|
93
|
+
def query_for_value(sql, params = [])
|
94
|
+
sql = format_to_sql(sql, params)
|
95
|
+
results = @connection.execute(sql)
|
96
|
+
|
97
|
+
count = 0
|
98
|
+
value = ''
|
99
|
+
results.each do |row|
|
100
|
+
count += 1
|
101
|
+
fail FluidDb2::TooManyRowsError if count > 1
|
102
|
+
value = row[results.fields[0]]
|
103
|
+
end
|
104
|
+
|
105
|
+
fail FluidDb2::NoDataFoundError if count == 0
|
106
|
+
|
107
|
+
value
|
108
|
+
end
|
109
|
+
|
110
|
+
def query_for_resultset(sql, params = [])
|
111
|
+
sql = format_to_sql(sql, params)
|
112
|
+
results = @connection.execute(sql)
|
113
|
+
|
114
|
+
list = []
|
115
|
+
results.each do |row|
|
116
|
+
list << row
|
117
|
+
end
|
118
|
+
|
119
|
+
list
|
120
|
+
end
|
121
|
+
|
122
|
+
def execute(sql, params = [], expected_affected_rows = nil)
|
123
|
+
sql = format_to_sql(sql, params)
|
124
|
+
r = @connection.execute(sql)
|
125
|
+
r.each
|
126
|
+
|
127
|
+
if !expected_affected_rows.nil? &&
|
128
|
+
r.affected_rows != expected_affected_rows
|
129
|
+
msg = "Expected affected rows, #{expected_affected_rows}, " \
|
130
|
+
"Actual affected rows, #{r.affected_rows}"
|
131
|
+
fail ExpectedAffectedRowsError, msg
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def insert(_sql, _params)
|
136
|
+
fail 'Not implemented'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/lib/fluiddb2.rb
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
require 'fluiddb/db'
|
6
|
+
|
7
|
+
# FluidDb2
|
8
|
+
module FluidDb2
|
9
|
+
class ConnectionError < StandardError
|
10
|
+
end
|
11
|
+
class NoDataFoundError < StandardError
|
12
|
+
end
|
13
|
+
class TooManyRowsError < StandardError
|
14
|
+
end
|
15
|
+
class ParamTypeNotSupportedError < StandardError
|
16
|
+
end
|
17
|
+
class ExpectedAffectedRowsError < StandardError
|
18
|
+
end
|
19
|
+
class IncorrectNumberOfParametersError < StandardError
|
20
|
+
end
|
21
|
+
class DuplicateKeyError < StandardError
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.db(uri)
|
25
|
+
uri = URI.parse(uri) if uri.is_a? String
|
26
|
+
|
27
|
+
case uri.scheme
|
28
|
+
when 'mysql'
|
29
|
+
require 'fluiddb2/mysql'
|
30
|
+
return FluidDb2::Mysql.new(uri)
|
31
|
+
when 'mysql2'
|
32
|
+
require 'fluiddb2/mysql2'
|
33
|
+
return FluidDb2::Mysql2.new(uri)
|
34
|
+
when 'pgsql'
|
35
|
+
require 'fluiddb2/pgsql'
|
36
|
+
return FluidDb2::Pgsql.new(uri)
|
37
|
+
when 'fb'
|
38
|
+
require 'fluiddb2/firebird'
|
39
|
+
return FluidDb2::Firebird.new(uri)
|
40
|
+
when 'mock'
|
41
|
+
require 'fluiddb2/Mock'
|
42
|
+
return FluidDb2::Mock.new(uri)
|
43
|
+
when 'tinytds'
|
44
|
+
require 'fluiddb2/tiny_tds'
|
45
|
+
return FluidDb2::TinyTds.new(uri)
|
46
|
+
when 'sqlite'
|
47
|
+
require 'fluiddb2/sqlite'
|
48
|
+
return FluidDb2::SQLite.new(uri)
|
49
|
+
else
|
50
|
+
abort("Scheme, #{uri.scheme}, not recognised when configuring creating " \
|
51
|
+
'db connection')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.splice_sql(sql, params)
|
56
|
+
fail IncorrectNumberOfParametersError if params.length != sql.count('?')
|
57
|
+
|
58
|
+
sql_out = ''
|
59
|
+
sql.split('?').each_with_index do |s, idx|
|
60
|
+
sql_out += s
|
61
|
+
sql_out += params[idx] unless params[idx].nil?
|
62
|
+
end
|
63
|
+
|
64
|
+
sql_out
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.escape_string(input)
|
68
|
+
input.split("'").join("''")
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.format_to_sql(sql, params = nil)
|
72
|
+
return sql if params.nil? || params.count == 0
|
73
|
+
|
74
|
+
params.each_with_index do |v, idx|
|
75
|
+
if v.is_a? String
|
76
|
+
v = "'#{escape_string(v)}'"
|
77
|
+
elsif v.is_a? DateTime
|
78
|
+
v = "'" + v.strftime('%Y-%m-%d %H:%M:%S.%6N %z') + "'"
|
79
|
+
elsif v.is_a? Time
|
80
|
+
v = "'" + v.strftime('%Y-%m-%d %H:%M:%S.%6N %z') + "'"
|
81
|
+
elsif v.is_a? Date
|
82
|
+
v = "'#{v}'"
|
83
|
+
elsif v.is_a? Numeric
|
84
|
+
v = v.to_s
|
85
|
+
elsif v.is_a? TrueClass
|
86
|
+
v = 'true'
|
87
|
+
elsif v.is_a? FalseClass
|
88
|
+
v = 'false'
|
89
|
+
elsif v.nil?
|
90
|
+
v = 'NULL'
|
91
|
+
else
|
92
|
+
fail ParamTypeNotSupportedError,
|
93
|
+
"Name of unknown param type, #{v.class.name}, for sql, #{sql}"
|
94
|
+
end
|
95
|
+
params[idx] = v
|
96
|
+
end
|
97
|
+
|
98
|
+
sql_out = splice_sql(sql, params)
|
99
|
+
if @verbose == true
|
100
|
+
puts self.class.name
|
101
|
+
puts sql
|
102
|
+
puts params.join(',')
|
103
|
+
puts sql_out
|
104
|
+
end
|
105
|
+
|
106
|
+
sql_out
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.convert_tuple_to_hash(fields, tuple, j)
|
110
|
+
hash = {}
|
111
|
+
0.upto(fields.length - 1).each do |i|
|
112
|
+
hash[fields[i].to_s] = tuple.getvalue(j, i)
|
113
|
+
end
|
114
|
+
|
115
|
+
hash
|
116
|
+
end
|
117
|
+
|
118
|
+
# Base
|
119
|
+
class Base
|
120
|
+
attr_writer :verbose
|
121
|
+
attr_reader :connection
|
122
|
+
|
123
|
+
# Constructor.
|
124
|
+
#
|
125
|
+
# @param [String] uri a location for the resource to which we will attach,
|
126
|
+
# eg mysql://user:pass@127.0.0.1/foo
|
127
|
+
def initialize(uri)
|
128
|
+
if uri.is_a? String
|
129
|
+
@uri = URI.parse(uri)
|
130
|
+
else
|
131
|
+
@uri = uri
|
132
|
+
end
|
133
|
+
|
134
|
+
connect
|
135
|
+
|
136
|
+
@verbose = !ENV['VERBOSE'].nil?
|
137
|
+
end
|
138
|
+
|
139
|
+
def verbose_log(string)
|
140
|
+
puts string if @verbose == true
|
141
|
+
end
|
142
|
+
|
143
|
+
def connect
|
144
|
+
fail NotImplementedError, "You must implement 'connect'."
|
145
|
+
end
|
146
|
+
|
147
|
+
def close
|
148
|
+
fail NotImplementedError, "You must implement 'close'."
|
149
|
+
end
|
150
|
+
|
151
|
+
def reconnect
|
152
|
+
close
|
153
|
+
connect
|
154
|
+
end
|
155
|
+
|
156
|
+
# Return a single row from the database, given the sql parameter.
|
157
|
+
# Throws an error for no data.
|
158
|
+
# Throws an error for more than 1 row
|
159
|
+
#
|
160
|
+
# @param [String] sql The SELECT statement to run
|
161
|
+
# @param [Array] parama The parameters to be added to the sql query. Ruby
|
162
|
+
# types are used to determine formatting and escaping.
|
163
|
+
def query_for_array(_sql, _params)
|
164
|
+
fail NotImplementedError, "You must implement 'queryForArray'."
|
165
|
+
end
|
166
|
+
|
167
|
+
# Return a single value is returned from a single row from the database,
|
168
|
+
# given the sql parameter.
|
169
|
+
# Throws an error for no data.
|
170
|
+
# Throws an error for more than 1 row
|
171
|
+
#
|
172
|
+
# @param [String] sql The SELECT statement to run
|
173
|
+
# @param [Array] parama The parameters to be added to the sql query. Ruby
|
174
|
+
# types are used to determine formatting and escaping.
|
175
|
+
def query_for_value(_sql, _params)
|
176
|
+
fail NotImplementedError, "You must implement 'queryForValue'."
|
177
|
+
end
|
178
|
+
|
179
|
+
def query_for_resultset(_sql, _params)
|
180
|
+
fail NotImplementedError, "You must implement 'queryForResultset'."
|
181
|
+
end
|
182
|
+
|
183
|
+
# Execute an insert, update or delete, then check the impact that statement
|
184
|
+
# has on the data.
|
185
|
+
#
|
186
|
+
# @param [String] sql The SELECT statement to run
|
187
|
+
# @param [Array] parama The parameters to be added to the sql query. Ruby
|
188
|
+
# types are used to determine formatting and escaping.
|
189
|
+
# @param [String] expected_affected_rows The number of rows that should
|
190
|
+
# have been updated.
|
191
|
+
def execute(_sql, _params, _expected_affected_rows)
|
192
|
+
fail NotImplementedError, "You must implement 'execute'."
|
193
|
+
end
|
194
|
+
|
195
|
+
# Transaction Semantics
|
196
|
+
def begin
|
197
|
+
@connection.execute('BEGIN', [])
|
198
|
+
end
|
199
|
+
|
200
|
+
# Transaction Semantics
|
201
|
+
def commit
|
202
|
+
@connection.execute('COMMIT', [])
|
203
|
+
end
|
204
|
+
|
205
|
+
# Transaction Semantics
|
206
|
+
def rollback
|
207
|
+
@connection.execute('ROLLBACK', [])
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluiddb2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Guy Irvine
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-30 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A semantic layer for db interaction
|
14
|
+
email: guy@guyirvine.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/fluiddb2/firebird.rb
|
20
|
+
- lib/fluiddb2/mock.rb
|
21
|
+
- lib/fluiddb2/mysql.rb
|
22
|
+
- lib/fluiddb2/mysql2.rb
|
23
|
+
- lib/fluiddb2/pgsql.rb
|
24
|
+
- lib/fluiddb2/sqlite.rb
|
25
|
+
- lib/fluiddb2/tiny_tds.rb
|
26
|
+
- lib/fluiddb2.rb
|
27
|
+
- LICENSE
|
28
|
+
- README.md
|
29
|
+
homepage: http://rubygems.org/gems/fluiddb2
|
30
|
+
licenses: []
|
31
|
+
metadata: {}
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 2.0.14.1
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: FluidDB
|
52
|
+
test_files: []
|