datamapper 0.1.1 → 0.2.0
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.
- data/CHANGELOG +65 -0
- data/README +193 -1
- data/do_performance.rb +153 -0
- data/environment.rb +45 -0
- data/example.rb +119 -22
- data/lib/data_mapper.rb +36 -16
- data/lib/data_mapper/adapters/abstract_adapter.rb +8 -0
- data/lib/data_mapper/adapters/data_object_adapter.rb +360 -0
- data/lib/data_mapper/adapters/mysql_adapter.rb +30 -179
- data/lib/data_mapper/adapters/postgresql_adapter.rb +90 -199
- data/lib/data_mapper/adapters/sql/coersion.rb +32 -3
- data/lib/data_mapper/adapters/sql/commands/conditions.rb +97 -128
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +234 -231
- data/lib/data_mapper/adapters/sql/commands/loader.rb +99 -0
- data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +30 -0
- data/lib/data_mapper/adapters/sql/mappings/column.rb +68 -6
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +6 -3
- data/lib/data_mapper/adapters/sql/mappings/table.rb +71 -42
- data/lib/data_mapper/adapters/sql/quoting.rb +8 -2
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +32 -201
- data/lib/data_mapper/associations.rb +21 -7
- data/lib/data_mapper/associations/belongs_to_association.rb +96 -80
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +158 -67
- data/lib/data_mapper/associations/has_many_association.rb +96 -78
- data/lib/data_mapper/associations/has_n_association.rb +64 -0
- data/lib/data_mapper/associations/has_one_association.rb +49 -79
- data/lib/data_mapper/associations/reference.rb +47 -0
- data/lib/data_mapper/base.rb +216 -50
- data/lib/data_mapper/callbacks.rb +71 -24
- data/lib/data_mapper/{session.rb → context.rb} +20 -8
- data/lib/data_mapper/database.rb +176 -45
- data/lib/data_mapper/embedded_value.rb +65 -0
- data/lib/data_mapper/identity_map.rb +12 -4
- data/lib/data_mapper/support/active_record_impersonation.rb +12 -8
- data/lib/data_mapper/support/enumerable.rb +8 -0
- data/lib/data_mapper/support/serialization.rb +13 -0
- data/lib/data_mapper/support/string.rb +1 -12
- data/lib/data_mapper/support/symbol.rb +3 -0
- data/lib/data_mapper/validations/unique_validator.rb +1 -2
- data/lib/data_mapper/validations/validation_helper.rb +18 -1
- data/performance.rb +109 -34
- data/plugins/can_has_sphinx/LICENSE +23 -0
- data/plugins/can_has_sphinx/README +4 -0
- data/plugins/can_has_sphinx/REVISION +1 -0
- data/plugins/can_has_sphinx/Rakefile +22 -0
- data/plugins/can_has_sphinx/init.rb +1 -0
- data/plugins/can_has_sphinx/install.rb +1 -0
- data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +123 -0
- data/plugins/can_has_sphinx/lib/sphinx.rb +460 -0
- data/plugins/can_has_sphinx/scripts/sphinx.sh +47 -0
- data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +41 -0
- data/plugins/dataobjects/REVISION +1 -0
- data/plugins/dataobjects/Rakefile +7 -0
- data/plugins/dataobjects/do.rb +246 -0
- data/plugins/dataobjects/do_mysql.rb +179 -0
- data/plugins/dataobjects/do_postgres.rb +181 -0
- data/plugins/dataobjects/do_sqlite3.rb +153 -0
- data/plugins/dataobjects/spec/do_spec.rb +150 -0
- data/plugins/dataobjects/spec/spec_helper.rb +81 -0
- data/plugins/dataobjects/swig_mysql/do_mysql.bundle +0 -0
- data/plugins/dataobjects/swig_mysql/extconf.rb +33 -0
- data/plugins/dataobjects/swig_mysql/mysql_c.c +18800 -0
- data/plugins/dataobjects/swig_mysql/mysql_c.i +8 -0
- data/plugins/dataobjects/swig_mysql/mysql_supp.i +46 -0
- data/plugins/dataobjects/swig_postgres/Makefile +146 -0
- data/plugins/dataobjects/swig_postgres/extconf.rb +29 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.bundle +0 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.c +8185 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.i +73 -0
- data/plugins/dataobjects/swig_sqlite/db +0 -0
- data/plugins/dataobjects/swig_sqlite/extconf.rb +9 -0
- data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +4725 -0
- data/plugins/dataobjects/swig_sqlite/sqlite_c.i +168 -0
- data/rakefile.rb +45 -23
- data/spec/acts_as_tree_spec.rb +39 -0
- data/spec/associations_spec.rb +220 -0
- data/spec/attributes_spec.rb +15 -0
- data/spec/base_spec.rb +44 -0
- data/spec/callbacks_spec.rb +45 -0
- data/spec/can_has_sphinx.rb +6 -0
- data/spec/coersion_spec.rb +34 -0
- data/spec/conditions_spec.rb +49 -0
- data/spec/conversions_to_yaml_spec.rb +17 -0
- data/spec/count_command_spec.rb +11 -0
- data/spec/delete_command_spec.rb +1 -1
- data/spec/embedded_value_spec.rb +23 -0
- data/spec/fixtures/animals_exhibits.yaml +2 -0
- data/spec/fixtures/people.yaml +18 -1
- data/spec/{legacy.rb → legacy_spec.rb} +3 -3
- data/spec/load_command_spec.rb +157 -20
- data/spec/magic_columns_spec.rb +9 -0
- data/spec/mock_adapter.rb +20 -0
- data/spec/models/animal.rb +1 -1
- data/spec/models/animals_exhibit.rb +6 -0
- data/spec/models/exhibit.rb +2 -0
- data/spec/models/person.rb +26 -1
- data/spec/models/project.rb +19 -0
- data/spec/models/sales_person.rb +1 -0
- data/spec/models/section.rb +6 -0
- data/spec/models/zoo.rb +3 -1
- data/spec/query_spec.rb +9 -0
- data/spec/save_command_spec.rb +65 -1
- data/spec/schema_spec.rb +89 -0
- data/spec/single_table_inheritance_spec.rb +27 -0
- data/spec/spec_helper.rb +9 -55
- data/spec/{symbolic_operators.rb → symbolic_operators_spec.rb} +9 -5
- data/spec/{validates_confirmation_of.rb → validates_confirmation_of_spec.rb} +4 -3
- data/spec/{validates_format_of.rb → validates_format_of_spec.rb} +5 -4
- data/spec/{validates_length_of.rb → validates_length_of_spec.rb} +8 -7
- data/spec/{validates_uniqueness_of.rb → validates_uniqueness_of_spec.rb} +7 -10
- data/spec/{validations.rb → validations_spec.rb} +24 -6
- data/tasks/drivers.rb +20 -0
- data/tasks/fixtures.rb +42 -0
- metadata +181 -42
- data/lib/data_mapper/adapters/sql/commands/advanced_load_command.rb +0 -140
- data/lib/data_mapper/adapters/sql/commands/delete_command.rb +0 -113
- data/lib/data_mapper/adapters/sql/commands/save_command.rb +0 -141
- data/lib/data_mapper/adapters/sql/commands/table_exists_command.rb +0 -33
- data/lib/data_mapper/adapters/sql_adapter.rb +0 -163
- data/lib/data_mapper/associations/advanced_has_many_association.rb +0 -55
- data/lib/data_mapper/support/blank_slate.rb +0 -3
- data/lib/data_mapper/support/proc.rb +0 -69
- data/lib/data_mapper/support/struct.rb +0 -26
- data/lib/data_mapper/unit_of_work.rb +0 -38
- data/spec/basic_finder.rb +0 -67
- data/spec/belongs_to.rb +0 -47
- data/spec/has_and_belongs_to_many.rb +0 -25
- data/spec/has_many.rb +0 -34
- data/spec/new_record.rb +0 -24
- data/spec/sub_select.rb +0 -16
- data/spec/support/string_spec.rb +0 -7
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
#
|
|
3
|
+
# start/stop searchd server.
|
|
4
|
+
|
|
5
|
+
if ! [ -x /usr/local/bin/searchd ]; then
|
|
6
|
+
exit 0
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
case "$1" in
|
|
10
|
+
start)
|
|
11
|
+
echo -n "Starting sphinx searchd server:"
|
|
12
|
+
echo -n " searchd" ;
|
|
13
|
+
/sbin/start-stop-daemon --start --quiet --pidfile /var/run/searchd.pid --chdir /etc --exec /usr/local/bin/searchd
|
|
14
|
+
echo "."
|
|
15
|
+
;;
|
|
16
|
+
stop)
|
|
17
|
+
echo -n "Stopping sphinx searchd server:"
|
|
18
|
+
echo -n " searchd" ;
|
|
19
|
+
/sbin/start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/searchd.pid --exec /usr/local/bin/searchd
|
|
20
|
+
echo "."
|
|
21
|
+
;;
|
|
22
|
+
reload)
|
|
23
|
+
echo -n "Reloading sphinx searchd server:"
|
|
24
|
+
echo -n " searchd"
|
|
25
|
+
/sbin/start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/searchd.pid --signal 1
|
|
26
|
+
echo "."
|
|
27
|
+
;;
|
|
28
|
+
force-reload)
|
|
29
|
+
$0 reload
|
|
30
|
+
;;
|
|
31
|
+
reindex)
|
|
32
|
+
cd /etc
|
|
33
|
+
/usr/local/bin/indexer --rotate --quiet --all
|
|
34
|
+
;;
|
|
35
|
+
restart)
|
|
36
|
+
echo -n "Restarting sphinx searchd server:"
|
|
37
|
+
echo -n " searchd"
|
|
38
|
+
/sbin/start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/searchd.pid --exec /usr/local/bin/searchd
|
|
39
|
+
/sbin/start-stop-daemon --start --quiet --pidfile /var/run/searchd.pid --chdir /etc --exec /usr/local/bin/searchd
|
|
40
|
+
echo "."
|
|
41
|
+
;;
|
|
42
|
+
*)
|
|
43
|
+
echo "Usage: /etc/init.d/searchd {start|stop|reload|restart|reindex}"
|
|
44
|
+
exit 1
|
|
45
|
+
;;
|
|
46
|
+
esac
|
|
47
|
+
exit 0
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
namespace :sphinx do
|
|
2
|
+
desc "Run indexer"
|
|
3
|
+
task :index do
|
|
4
|
+
cd 'config' do
|
|
5
|
+
system 'indexer --all'
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
desc "Rotate idendexes and restart searchd server"
|
|
10
|
+
task :rotate do
|
|
11
|
+
cd 'config' do
|
|
12
|
+
system 'indexer --rotate --all'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc "Start searchd server"
|
|
17
|
+
task :start do
|
|
18
|
+
if File.exists?('/var/run/searchd.pid')
|
|
19
|
+
puts 'Sphinx searchd server is already started.'
|
|
20
|
+
else
|
|
21
|
+
cd 'config' do
|
|
22
|
+
system 'searchd'
|
|
23
|
+
puts 'Sphinx searchd server started.'
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc "Stop searchd server"
|
|
29
|
+
task :stop do
|
|
30
|
+
unless File.exists?('/var/run/searchd.pid')
|
|
31
|
+
puts 'Sphinx searchd server is not running.'
|
|
32
|
+
else
|
|
33
|
+
pid = File.read('/var/run/searchd.pid').chomp
|
|
34
|
+
system "kill #{pid}"
|
|
35
|
+
puts 'Sphinx searchd server stopped.'
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
desc "Restart searchd server"
|
|
40
|
+
task :restart => [:stop, :start]
|
|
41
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
18
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
# Thanks http://www.rubyweeklynews.org/20051120
|
|
4
|
+
class DateTime
|
|
5
|
+
def to_time
|
|
6
|
+
Time.mktime(year, mon, day, hour, min, sec)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def to_date
|
|
10
|
+
Date.new(year, mon, day)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Time
|
|
15
|
+
def to_datetime
|
|
16
|
+
DateTime.civil(year, mon, day, hour, min, sec)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_s_db
|
|
20
|
+
strftime("%Y-%m-%d %X")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
module DataObject
|
|
25
|
+
STATE_OPEN = 0
|
|
26
|
+
STATE_CLOSED = 1
|
|
27
|
+
|
|
28
|
+
class Connection
|
|
29
|
+
|
|
30
|
+
attr_reader :timeout, :database, :datasource, :server_version, :state
|
|
31
|
+
|
|
32
|
+
def initialize(connection_string)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def begin_transaction
|
|
36
|
+
# TODO: Hook this up
|
|
37
|
+
Transaction.new
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def change_database(database_name)
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def open
|
|
45
|
+
raise NotImplementedError
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def close
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def create_command(text)
|
|
53
|
+
Command.new(self, text)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def closed?
|
|
57
|
+
@state == STATE_CLOSED
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class Transaction
|
|
63
|
+
|
|
64
|
+
attr_reader :connection
|
|
65
|
+
|
|
66
|
+
def initialize(conn)
|
|
67
|
+
@connection = conn
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Commits the transaction
|
|
71
|
+
def commit
|
|
72
|
+
raise NotImplementedError
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Rolls back the transaction
|
|
76
|
+
def rollback(savepoint = nil)
|
|
77
|
+
raise NotImplementedError
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Creates a savepoint for rolling back later (not commonly supported)
|
|
81
|
+
def save(name)
|
|
82
|
+
raise NotImplementedError
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class Reader
|
|
88
|
+
include Enumerable
|
|
89
|
+
|
|
90
|
+
attr_reader :field_count, :has_rows, :records_affected, :fields
|
|
91
|
+
alias_method :has_rows?, :has_rows
|
|
92
|
+
|
|
93
|
+
def each
|
|
94
|
+
return nil unless has_rows
|
|
95
|
+
while(true) do
|
|
96
|
+
yield
|
|
97
|
+
break unless self.next
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def current_row
|
|
102
|
+
ret = []
|
|
103
|
+
field_count.times do |i|
|
|
104
|
+
ret[i] = item(i)
|
|
105
|
+
end
|
|
106
|
+
ret
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def close
|
|
110
|
+
raise NotImplementedError
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# retrieves the Ruby data type for a particular column number
|
|
114
|
+
def data_type_name(col)
|
|
115
|
+
raise ReaderClosed, "You cannot ask for metadata once the reader is closed" if state_closed?
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# retrieves the name of a particular column number
|
|
119
|
+
def name(col)
|
|
120
|
+
raise ReaderClosed, "You cannot ask for metadata once the reader is closed" if state_closed?
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# retrives the index of the column with a particular name
|
|
124
|
+
def get_index(name)
|
|
125
|
+
raise ReaderClosed, "You cannot ask for metadata once the reader is closed" if state_closed?
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def item(idx)
|
|
129
|
+
raise ReaderClosed, "You cannot ask for information once the reader is closed" if state_closed?
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# returns an array of hashes containing the following information
|
|
133
|
+
#
|
|
134
|
+
# name: the column name
|
|
135
|
+
# index: the index of the column
|
|
136
|
+
# max_size: the maximum allowed size of the data in the column
|
|
137
|
+
# precision: the precision (for column types that support it)
|
|
138
|
+
# scale: the scale (for column types that support it)
|
|
139
|
+
# unique: boolean specifying whether the values must be unique
|
|
140
|
+
# key: boolean specifying whether this column is, or is part
|
|
141
|
+
# of, the primary key
|
|
142
|
+
# catalog: the name of the database this column is part of
|
|
143
|
+
# base_name: the original name of the column (if AS was used,
|
|
144
|
+
# this will provide the original name)
|
|
145
|
+
# schema: the name of the schema (if supported)
|
|
146
|
+
# table: the name of the table this column is part of
|
|
147
|
+
# data_type: the name of the Ruby data type used
|
|
148
|
+
# allow_null: boolean specifying whether nulls are allowed
|
|
149
|
+
# db_type: the type specified by the DB
|
|
150
|
+
# aliased: boolean specifying whether the column has been
|
|
151
|
+
# renamed using AS
|
|
152
|
+
# calculated: boolean specifying whether the field is calculated
|
|
153
|
+
# serial: boolean specifying whether the field is a serial
|
|
154
|
+
# column
|
|
155
|
+
# blob: boolean specifying whether the field is a BLOB
|
|
156
|
+
# readonly: boolean specifying whether the field is readonly
|
|
157
|
+
def get_schema
|
|
158
|
+
raise ReaderClosed, "You cannot ask for metadata once the reader is closed" if state_closed?
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# specifies whether the column identified by the passed in index
|
|
162
|
+
# is null.
|
|
163
|
+
def null?(idx)
|
|
164
|
+
raise ReaderClosed, "You cannot ask for column information once the reader is closed" if state_closed?
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Consumes the next result. Returns true if a result is consumed and
|
|
168
|
+
# false if none is
|
|
169
|
+
def next
|
|
170
|
+
raise ReaderClosed, "You cannot increment the cursor once the reader is closed" if state_closed?
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
protected
|
|
174
|
+
def state_closed?
|
|
175
|
+
@state == STATE_CLOSED
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def native_type
|
|
179
|
+
raise ReaderClosed, "You cannot check the type of a column once the reader is closed" if state_closed?
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
class ResultData
|
|
185
|
+
|
|
186
|
+
def initialize(conn, affected_rows, last_insert_row = nil)
|
|
187
|
+
@conn, @affected_rows, @last_insert_row = conn, affected_rows, last_insert_row
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
attr_reader :affected_rows, :last_insert_row
|
|
191
|
+
alias_method :to_i, :affected_rows
|
|
192
|
+
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
class Schema < Array
|
|
196
|
+
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
class Command
|
|
200
|
+
|
|
201
|
+
attr_reader :text, :timeout, :connection
|
|
202
|
+
|
|
203
|
+
# initialize creates a new Command object
|
|
204
|
+
def initialize(connection, text)
|
|
205
|
+
@connection, @text = connection, text
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def execute_non_query
|
|
209
|
+
raise LostConnectionError, "the connection to the database has been lost" if @connection.closed?
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def execute_reader
|
|
213
|
+
raise LostConnectionError, "the connection to the database has been lost" if @connection.closed?
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def prepare
|
|
217
|
+
raise NotImplementedError
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
class NotImplementedError < StandardError
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
class ConnectionFailed < StandardError
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
class ReaderClosed < StandardError
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
class ReaderError < StandardError
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
class QueryError < StandardError
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
class NoInsertError < StandardError
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
class LostConnectionError < StandardError
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
class UnknownError < StandardError
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
require 'mysql_c'
|
|
2
|
+
require 'do'
|
|
3
|
+
|
|
4
|
+
module DataObject
|
|
5
|
+
module Mysql
|
|
6
|
+
TYPES = Hash[*Mysql_c.constants.select {|x| x.include?("MYSQL_TYPE")}.map {|x| [Mysql_c.const_get(x), x.gsub(/^MYSQL_TYPE_/, "")]}.flatten]
|
|
7
|
+
|
|
8
|
+
QUOTE_STRING = "\""
|
|
9
|
+
QUOTE_COLUMN = "`"
|
|
10
|
+
|
|
11
|
+
class Connection < DataObject::Connection
|
|
12
|
+
attr_reader :db
|
|
13
|
+
|
|
14
|
+
def initialize(connection_string)
|
|
15
|
+
@state = STATE_CLOSED
|
|
16
|
+
@connection_string = connection_string
|
|
17
|
+
opts = connection_string.split(" ")
|
|
18
|
+
opts.each do |opt|
|
|
19
|
+
k, v = opt.split("=")
|
|
20
|
+
raise ArgumentError, "you specified an invalid connection component: #{opt}" unless k && v
|
|
21
|
+
instance_variable_set("@#{k}", v)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def change_database(database_name)
|
|
26
|
+
@dbname = database_name
|
|
27
|
+
@connection_string.gsub(/db_name=[^ ]*/, "db_name=#{database_name}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def open
|
|
31
|
+
@db = Mysql_c.mysql_init(nil)
|
|
32
|
+
raise ConnectionFailed, "could not allocate a MySQL connection" unless @db
|
|
33
|
+
conn = Mysql_c.mysql_real_connect(@db, @host, @user, @password, @dbname, @port || 0, @socket, @flags || 0)
|
|
34
|
+
raise ConnectionFailed, "The connection with connection string #{@connection_string} failed\n#{Mysql_c.mysql_error(@db)}" unless conn
|
|
35
|
+
@state = STATE_OPEN
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def close
|
|
40
|
+
if @state == STATE_OPEN
|
|
41
|
+
Mysql_c.mysql_close(@db)
|
|
42
|
+
@state = STATE_CLOSED
|
|
43
|
+
true
|
|
44
|
+
else
|
|
45
|
+
false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def create_command(text)
|
|
50
|
+
Command.new(self, text)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class Reader < DataObject::Reader
|
|
56
|
+
|
|
57
|
+
def initialize(db, reader)
|
|
58
|
+
@reader = reader
|
|
59
|
+
unless @reader
|
|
60
|
+
if Mysql_c.mysql_field_count(db) == 0
|
|
61
|
+
@records_affected = Mysql_c.mysql_affected_rows(db)
|
|
62
|
+
close
|
|
63
|
+
else
|
|
64
|
+
raise UnknownError, "An unknown error has occured while trying to process a MySQL query.\n#{Mysql_c.mysql_error(db)}"
|
|
65
|
+
end
|
|
66
|
+
else
|
|
67
|
+
@field_count = Mysql_c.mysql_num_fields(@reader)
|
|
68
|
+
@state = STATE_OPEN
|
|
69
|
+
self.next
|
|
70
|
+
fields = Mysql_c.mysql_fetch_fields(@reader)
|
|
71
|
+
@native_fields = fields
|
|
72
|
+
raise UnknownError, "An unknown error has occured while trying to process a MySQL query. There were no fields in the resultset\n#{Mysql_c.mysql_error(db)}" unless fields
|
|
73
|
+
@fields = fields.map {|field| field.name}
|
|
74
|
+
@rows = Mysql_c.mysql_num_rows(@reader)
|
|
75
|
+
@has_rows = @rows > 0
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def close
|
|
80
|
+
if @state != STATE_CLOSED
|
|
81
|
+
Mysql_c.mysql_free_result(@reader)
|
|
82
|
+
@state = STATE_CLOSED
|
|
83
|
+
true
|
|
84
|
+
else
|
|
85
|
+
false
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def name(col)
|
|
90
|
+
super
|
|
91
|
+
@fields[col]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def get_index(name)
|
|
95
|
+
super
|
|
96
|
+
@fields.index(name)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def null?(idx)
|
|
100
|
+
super
|
|
101
|
+
@row[idx] == nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def item(idx)
|
|
105
|
+
super
|
|
106
|
+
typecast(@row[idx], idx)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def next
|
|
110
|
+
super
|
|
111
|
+
@row = Mysql_c.mysql_fetch_row(@reader)
|
|
112
|
+
close if @row.nil?
|
|
113
|
+
@row ? true : nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
protected
|
|
117
|
+
def native_type(col)
|
|
118
|
+
super
|
|
119
|
+
TYPES[@native_fields[col].type]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def typecast(val, idx)
|
|
123
|
+
return nil if val.nil?
|
|
124
|
+
field = @native_fields[idx]
|
|
125
|
+
case TYPES[field.type]
|
|
126
|
+
when "TINY"
|
|
127
|
+
if field.max_length == 1
|
|
128
|
+
val != "0"
|
|
129
|
+
else
|
|
130
|
+
val.to_i
|
|
131
|
+
end
|
|
132
|
+
when "BIT"
|
|
133
|
+
val.to_i(2)
|
|
134
|
+
when "SHORT", "LONG", "INT24", "LONGLONG"
|
|
135
|
+
val.to_i
|
|
136
|
+
when "DECIMAL", "NEWDECIMAL", "FLOAT", "DOUBLE", "YEAR"
|
|
137
|
+
val.to_f
|
|
138
|
+
when "TIMESTAMP", "DATETIME"
|
|
139
|
+
DateTime.parse(val) rescue nil
|
|
140
|
+
when "TIME"
|
|
141
|
+
DateTime.parse(val).to_time rescue nil
|
|
142
|
+
when "DATE"
|
|
143
|
+
Date.parse(val) rescue nil
|
|
144
|
+
when "NULL"
|
|
145
|
+
nil
|
|
146
|
+
else
|
|
147
|
+
val
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
class Command < DataObject::Command
|
|
155
|
+
|
|
156
|
+
def execute_reader
|
|
157
|
+
super
|
|
158
|
+
result = Mysql_c.mysql_query(@connection.db, @text)
|
|
159
|
+
# TODO: Real Error
|
|
160
|
+
raise QueryError, "Your query failed.\n#{Mysql_c.mysql_error(@connection.db)}\n#{@text}" unless result == 0
|
|
161
|
+
reader = Mysql_c.mysql_store_result(@connection.db)
|
|
162
|
+
Reader.new(@connection.db, reader)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def execute_non_query
|
|
166
|
+
super
|
|
167
|
+
result = Mysql_c.mysql_query(@connection.db, @text)
|
|
168
|
+
raise QueryError, "Your query failed.\n#{Mysql_c.mysql_error(@connection.db)}\n#{@text}" unless result == 0
|
|
169
|
+
reader = Mysql_c.mysql_store_result(@connection.db)
|
|
170
|
+
raise QueryError, "You called execute_non_query on a query: #{@text}" if reader
|
|
171
|
+
rows_affected = Mysql_c.mysql_affected_rows(@connection.db)
|
|
172
|
+
Mysql_c.mysql_free_result(reader)
|
|
173
|
+
return ResultData.new(@connection, rows_affected, Mysql_c.mysql_insert_id(@connection.db))
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
end
|
|
179
|
+
end
|