datamapper 0.2.3 → 0.2.4
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/example.rb +5 -5
- data/lib/data_mapper/adapters/abstract_adapter.rb +2 -2
- data/lib/data_mapper/adapters/data_object_adapter.rb +141 -147
- data/lib/data_mapper/adapters/mysql_adapter.rb +14 -1
- data/lib/data_mapper/adapters/postgresql_adapter.rb +123 -18
- data/lib/data_mapper/adapters/sql/coersion.rb +21 -9
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +36 -19
- data/lib/data_mapper/adapters/sql/mappings/column.rb +111 -17
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +27 -0
- data/lib/data_mapper/adapters/sql/mappings/table.rb +256 -29
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +93 -8
- data/lib/data_mapper/associations/belongs_to_association.rb +53 -54
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +157 -25
- data/lib/data_mapper/associations/has_many_association.rb +45 -15
- data/lib/data_mapper/associations/has_n_association.rb +79 -20
- data/lib/data_mapper/associations/has_one_association.rb +2 -2
- data/lib/data_mapper/associations/reference.rb +1 -1
- data/lib/data_mapper/auto_migrations.rb +40 -0
- data/lib/data_mapper/base.rb +201 -98
- data/lib/data_mapper/context.rb +16 -10
- data/lib/data_mapper/database.rb +22 -11
- data/lib/data_mapper/dependency_queue.rb +28 -0
- data/lib/data_mapper/embedded_value.rb +61 -17
- data/lib/data_mapper/property.rb +4 -0
- data/lib/data_mapper/support/active_record_impersonation.rb +13 -5
- data/lib/data_mapper/support/errors.rb +5 -0
- data/lib/data_mapper/support/serialization.rb +8 -4
- data/lib/data_mapper/validatable_extensions/errors.rb +12 -0
- data/lib/data_mapper/validatable_extensions/macros.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validatable_instance_methods.rb +62 -0
- data/lib/data_mapper/validatable_extensions/validation_base.rb +18 -0
- data/lib/data_mapper/validatable_extensions/validations/formats/email.rb +43 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_acceptance_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_confirmation_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_each.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_format_of.rb +28 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_length_of.rb +15 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_numericality_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_presence_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_true_for.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb +33 -0
- data/lib/data_mapper/validations.rb +20 -0
- data/lib/data_mapper.rb +39 -34
- data/performance.rb +24 -18
- data/plugins/dataobjects/do_rb +0 -0
- data/rakefile.rb +12 -2
- data/spec/active_record_impersonation_spec.rb +133 -0
- data/spec/acts_as_tree_spec.rb +25 -9
- data/spec/associations_spec.rb +124 -4
- data/spec/attributes_spec.rb +13 -0
- data/spec/auto_migrations_spec.rb +44 -0
- data/spec/base_spec.rb +189 -1
- data/spec/column_spec.rb +85 -7
- data/spec/conditions_spec.rb +2 -2
- data/spec/dependency_spec.rb +25 -0
- data/spec/embedded_value_spec.rb +123 -3
- data/spec/fixtures/animals.yaml +1 -0
- data/spec/fixtures/careers.yaml +5 -0
- data/spec/fixtures/comments.yaml +1 -0
- data/spec/fixtures/people.yaml +14 -9
- data/spec/fixtures/projects.yaml +4 -0
- data/spec/fixtures/sections.yaml +5 -0
- data/spec/fixtures/serializers.yaml +6 -0
- data/spec/fixtures/users.yaml +1 -0
- data/spec/load_command_spec.rb +5 -4
- data/spec/mock_adapter.rb +2 -2
- data/spec/models/animal.rb +2 -1
- data/spec/models/animals_exhibit.rb +2 -2
- data/spec/models/career.rb +6 -0
- data/spec/models/comment.rb +4 -0
- data/spec/models/exhibit.rb +4 -0
- data/spec/models/person.rb +3 -13
- data/spec/models/project.rb +1 -1
- data/spec/models/serializer.rb +3 -0
- data/spec/models/user.rb +4 -0
- data/spec/models/zoo.rb +8 -1
- data/spec/natural_key_spec.rb +36 -0
- data/spec/paranoia_spec.rb +36 -0
- data/spec/property_spec.rb +70 -0
- data/spec/schema_spec.rb +10 -2
- data/spec/serialization_spec.rb +6 -3
- data/spec/serialize_spec.rb +19 -0
- data/spec/single_table_inheritance_spec.rb +7 -1
- data/spec/spec_helper.rb +26 -8
- data/spec/table_spec.rb +33 -0
- data/spec/validates_confirmation_of_spec.rb +20 -4
- data/spec/validates_format_of_spec.rb +22 -8
- data/spec/validates_length_of_spec.rb +26 -13
- data/spec/validates_uniqueness_of_spec.rb +18 -5
- data/spec/validations_spec.rb +55 -10
- data/tasks/fixtures.rb +13 -7
- metadata +189 -153
- data/lib/data_mapper/validations/confirmation_validator.rb +0 -53
- data/lib/data_mapper/validations/contextual_validations.rb +0 -50
- data/lib/data_mapper/validations/format_validator.rb +0 -85
- data/lib/data_mapper/validations/formats/email.rb +0 -78
- data/lib/data_mapper/validations/generic_validator.rb +0 -22
- data/lib/data_mapper/validations/length_validator.rb +0 -76
- data/lib/data_mapper/validations/required_field_validator.rb +0 -41
- data/lib/data_mapper/validations/unique_validator.rb +0 -56
- data/lib/data_mapper/validations/validation_errors.rb +0 -37
- data/lib/data_mapper/validations/validation_helper.rb +0 -77
- data/plugins/dataobjects/REVISION +0 -1
- data/plugins/dataobjects/Rakefile +0 -9
- data/plugins/dataobjects/do.rb +0 -348
- data/plugins/dataobjects/do_mysql.rb +0 -212
- data/plugins/dataobjects/do_postgres.rb +0 -196
- data/plugins/dataobjects/do_sqlite3.rb +0 -157
- data/plugins/dataobjects/spec/do_spec.rb +0 -150
- data/plugins/dataobjects/spec/spec_helper.rb +0 -81
- data/plugins/dataobjects/swig_mysql/extconf.rb +0 -45
- data/plugins/dataobjects/swig_mysql/mysql_c.c +0 -16602
- data/plugins/dataobjects/swig_mysql/mysql_c.i +0 -67
- data/plugins/dataobjects/swig_mysql/mysql_supp.i +0 -46
- data/plugins/dataobjects/swig_postgres/extconf.rb +0 -29
- data/plugins/dataobjects/swig_postgres/postgres_c.c +0 -8185
- data/plugins/dataobjects/swig_postgres/postgres_c.i +0 -73
- data/plugins/dataobjects/swig_sqlite/extconf.rb +0 -9
- data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +0 -4725
- data/plugins/dataobjects/swig_sqlite/sqlite_c.i +0 -168
- data/tasks/drivers.rb +0 -20
@@ -1,196 +0,0 @@
|
|
1
|
-
require 'postgres_c'
|
2
|
-
require 'do'
|
3
|
-
|
4
|
-
module DataObject
|
5
|
-
module Postgres
|
6
|
-
TYPES = Hash[*Postgres_c.constants.select {|x| x.include?("OID")}.map {|x| [Postgres_c.const_get(x), x.gsub(/_?OID$/, "")]}.flatten]
|
7
|
-
QUOTE_STRING = "'"
|
8
|
-
QUOTE_COLUMN = "\""
|
9
|
-
|
10
|
-
class Connection < DataObject::Connection
|
11
|
-
attr_reader :db
|
12
|
-
|
13
|
-
def initialize(connection_string)
|
14
|
-
@state = STATE_CLOSED
|
15
|
-
@connection_string = connection_string
|
16
|
-
end
|
17
|
-
|
18
|
-
def open
|
19
|
-
@db = Postgres_c.PQconnectdb(@connection_string)
|
20
|
-
if Postgres_c.PQstatus(@db) != Postgres_c::CONNECTION_OK
|
21
|
-
raise ConnectionFailed, "The connection with connection string #{@connection_string} failed\n#{Postgres_c.PQerrorMessage(@db)}"
|
22
|
-
end
|
23
|
-
@state = STATE_OPEN
|
24
|
-
true
|
25
|
-
end
|
26
|
-
|
27
|
-
def close
|
28
|
-
Postgres_c.PQfinish(@db)
|
29
|
-
@state = STATE_CLOSED
|
30
|
-
true
|
31
|
-
end
|
32
|
-
|
33
|
-
def create_command(text)
|
34
|
-
Command.new(self, text)
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
class Reader < DataObject::Reader
|
40
|
-
|
41
|
-
def initialize(db, reader)
|
42
|
-
@reader = reader
|
43
|
-
case Postgres_c.PQresultStatus(reader)
|
44
|
-
when Postgres_c::PGRES_COMMAND_OK
|
45
|
-
@records_affected = Postgres_c.PQcmdTuples(reader).to_i
|
46
|
-
close
|
47
|
-
when Postgres_c::PGRES_TUPLES_OK
|
48
|
-
@fields, @field_types = [], []
|
49
|
-
@field_count = Postgres_c.PQnfields(@reader)
|
50
|
-
i = 0
|
51
|
-
while(i < @field_count)
|
52
|
-
@field_types.push(Postgres_c.PQftype(@reader, i))
|
53
|
-
@fields.push(Postgres_c.PQfname(@reader, i))
|
54
|
-
i += 1
|
55
|
-
end
|
56
|
-
@rows = Postgres_c.PQntuples(@reader)
|
57
|
-
@has_rows = @rows > 0
|
58
|
-
@cursor = 0
|
59
|
-
@state = STATE_OPEN
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def real_close
|
64
|
-
Postgres_c.PQclear(@reader)
|
65
|
-
end
|
66
|
-
|
67
|
-
def data_type_name(col)
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
def name(col)
|
72
|
-
super
|
73
|
-
Postgres_c.PQfname(@reader, col)
|
74
|
-
end
|
75
|
-
|
76
|
-
def get_index(name)
|
77
|
-
super
|
78
|
-
@fields.index(name)
|
79
|
-
end
|
80
|
-
|
81
|
-
def null?(idx)
|
82
|
-
super
|
83
|
-
Postgres_c.PQgetisnull(@reader, @cursor, idx) != 0
|
84
|
-
end
|
85
|
-
|
86
|
-
def item(idx)
|
87
|
-
super
|
88
|
-
val = Postgres_c.PQgetvalue(@reader, @cursor, idx)
|
89
|
-
typecast(val, @field_types[idx])
|
90
|
-
end
|
91
|
-
|
92
|
-
def each
|
93
|
-
return unless has_rows?
|
94
|
-
|
95
|
-
while(true) do
|
96
|
-
yield
|
97
|
-
break unless self.next
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def next
|
102
|
-
super
|
103
|
-
if @cursor >= @rows - 1
|
104
|
-
@cursor = nil
|
105
|
-
close
|
106
|
-
return nil
|
107
|
-
end
|
108
|
-
@cursor += 1
|
109
|
-
true
|
110
|
-
end
|
111
|
-
|
112
|
-
protected
|
113
|
-
def native_type(col)
|
114
|
-
TYPES[Postgres_c.PQftype(@reader, col)]
|
115
|
-
end
|
116
|
-
|
117
|
-
def typecast(val, field_type)
|
118
|
-
return nil if val.nil?
|
119
|
-
case TYPES[field_type]
|
120
|
-
when "BOOL"
|
121
|
-
val == "t"
|
122
|
-
when "INT2", "INT4", "OID", "TID", "XID", "CID", "INT8"
|
123
|
-
val.to_i
|
124
|
-
when "FLOAT4", "FLOAT8", "NUMERIC", "CASH"
|
125
|
-
val.to_f
|
126
|
-
when "TIMESTAMP", "TIMETZ", "TIMESTAMPTZ"
|
127
|
-
DateTime.parse(val) rescue nil
|
128
|
-
when "TIME"
|
129
|
-
DateTime.parse(val).to_time rescue nil
|
130
|
-
when "DATE"
|
131
|
-
Date.parse(val) rescue nil
|
132
|
-
else
|
133
|
-
val
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
class ResultData < DataObject::ResultData
|
140
|
-
|
141
|
-
def last_insert_row
|
142
|
-
@last_insert_row ||= begin
|
143
|
-
reader = @conn.create_command("select lastval()").execute_reader
|
144
|
-
reader.item(0).to_i
|
145
|
-
rescue QueryError
|
146
|
-
raise NoInsertError, "You tried to get the last inserted row without doing an insert\n#{Postgres_c.PQerrorMessage(@conn.db)}"
|
147
|
-
ensure
|
148
|
-
reader and reader.close
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
class Command < DataObject::Command
|
155
|
-
|
156
|
-
def execute_reader(*args)
|
157
|
-
super
|
158
|
-
sql = escape_sql(args)
|
159
|
-
@connection.logger.debug { sql }
|
160
|
-
ptr = Postgres_c.PQexec(@connection.db, sql)
|
161
|
-
unless [Postgres_c::PGRES_COMMAND_OK, Postgres_c::PGRES_TUPLES_OK].include?(Postgres_c.PQresultStatus(ptr))
|
162
|
-
raise QueryError, "Your query failed.\n#{Postgres_c.PQerrorMessage(@connection.db)}QUERY: \"#{sql}\""
|
163
|
-
else
|
164
|
-
reader = Reader.new(@connection.db, ptr)
|
165
|
-
if block_given?
|
166
|
-
return_value = yield(reader)
|
167
|
-
reader.close
|
168
|
-
return_value
|
169
|
-
else
|
170
|
-
reader
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def execute_non_query(*args)
|
176
|
-
super
|
177
|
-
sql = escape_sql(args)
|
178
|
-
@connection.logger.debug { sql }
|
179
|
-
results = Postgres_c.PQexec(@connection.db, sql)
|
180
|
-
status = Postgres_c.PQresultStatus(results)
|
181
|
-
if status == Postgres_c::PGRES_TUPLES_OK
|
182
|
-
Postgres_c.PQclear(results)
|
183
|
-
raise QueryError, "Your query failed or you tried to execute a SELECT query through execute_non_reader\n#{Postgres_c.PQerrorMessage(@connection.db)}\nQUERY: \"#{sql}\""
|
184
|
-
elsif status != Postgres_c::PGRES_COMMAND_OK
|
185
|
-
Postgres_c.PQclear(results)
|
186
|
-
raise QueryError, "Your query failed.\n#{Postgres_c.PQerrorMessage(@connection.db)}\nQUERY: \"#{sql}\""
|
187
|
-
end
|
188
|
-
rows_affected = Postgres_c.PQcmdTuples(results).to_i
|
189
|
-
Postgres_c.PQclear(results)
|
190
|
-
ResultData.new(@connection, rows_affected)
|
191
|
-
end
|
192
|
-
|
193
|
-
end
|
194
|
-
|
195
|
-
end
|
196
|
-
end
|
@@ -1,157 +0,0 @@
|
|
1
|
-
require 'sqlite3_c'
|
2
|
-
require 'do'
|
3
|
-
|
4
|
-
module DataObject
|
5
|
-
module Sqlite3
|
6
|
-
|
7
|
-
QUOTE_STRING = "\""
|
8
|
-
QUOTE_COLUMN = "'"
|
9
|
-
|
10
|
-
class Connection < DataObject::Connection
|
11
|
-
|
12
|
-
attr_reader :db
|
13
|
-
|
14
|
-
def initialize(connection_string)
|
15
|
-
@state = STATE_CLOSED
|
16
|
-
@connection_string = connection_string
|
17
|
-
@conn = Hash[*connection_string.split(" ").map {|x| x.split("=")}.flatten]["dbname"]
|
18
|
-
end
|
19
|
-
|
20
|
-
def open
|
21
|
-
r, d = Sqlite3_c.sqlite3_open(@conn)
|
22
|
-
unless r == Sqlite3_c::SQLITE_OK
|
23
|
-
raise ConnectionFailed, "The connection with connection string #{@connection_string} failed\n#{Sqlite3_c.sqlite3_errmsg(d)}"
|
24
|
-
else
|
25
|
-
@db = d
|
26
|
-
end
|
27
|
-
@state = STATE_OPEN
|
28
|
-
true
|
29
|
-
end
|
30
|
-
|
31
|
-
def close
|
32
|
-
Sqlite3_c.sqlite3_close(@db)
|
33
|
-
@state = STATE_CLOSED
|
34
|
-
true
|
35
|
-
end
|
36
|
-
|
37
|
-
def create_command(text)
|
38
|
-
logger.debug { text }
|
39
|
-
Command.new(self, text)
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
class Reader < DataObject::Reader
|
45
|
-
|
46
|
-
def initialize(db, reader)
|
47
|
-
@reader = reader
|
48
|
-
result = Sqlite3_c.sqlite3_step(reader)
|
49
|
-
rows_affected, field_count = Sqlite3_c.sqlite3_changes(db), Sqlite3_c.sqlite3_column_count(reader)
|
50
|
-
if field_count == 0
|
51
|
-
@records_affected = rows_affected
|
52
|
-
close
|
53
|
-
else
|
54
|
-
@field_count = field_count
|
55
|
-
@fields, @field_types = [], []
|
56
|
-
i = 0
|
57
|
-
while(i < @field_count)
|
58
|
-
@field_types.push(Sqlite3_c.sqlite3_column_type(reader, i))
|
59
|
-
@fields.push(Sqlite3_c.sqlite3_column_name(reader, i))
|
60
|
-
i += 1
|
61
|
-
end
|
62
|
-
case result
|
63
|
-
when Sqlite3_c::SQLITE_BUSY, Sqlite3_c::SQLITE_ERROR, Sqlite3_c::SQLITE_MISUSE
|
64
|
-
raise ReaderError, "An error occurred while trying to get the next row\n#{Sqlite3_c.sqlite3_errmsg(db)}"
|
65
|
-
else
|
66
|
-
@has_rows = result == Sqlite3_c::SQLITE_ROW
|
67
|
-
@state = STATE_OPEN
|
68
|
-
close unless @has_rows
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def real_close
|
74
|
-
Sqlite3_c.sqlite3_finalize(@reader)
|
75
|
-
end
|
76
|
-
|
77
|
-
def name(idx)
|
78
|
-
super
|
79
|
-
@fields[idx]
|
80
|
-
end
|
81
|
-
|
82
|
-
def get_index(name)
|
83
|
-
super
|
84
|
-
@fields.index(name)
|
85
|
-
end
|
86
|
-
|
87
|
-
def null?(idx)
|
88
|
-
super
|
89
|
-
item(idx).nil?
|
90
|
-
end
|
91
|
-
|
92
|
-
def item(idx)
|
93
|
-
super
|
94
|
-
case @field_types[idx]
|
95
|
-
when 1 # SQLITE_INTEGER
|
96
|
-
Sqlite3_c.sqlite3_column_int(@reader, idx).to_i
|
97
|
-
when 2 # SQLITE_FLOAT
|
98
|
-
Sqlite3_c.sqlite3_column_double(@reader, idx)
|
99
|
-
else
|
100
|
-
Sqlite3_c.sqlite3_column_text(@reader, idx)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def each
|
105
|
-
return unless has_rows?
|
106
|
-
|
107
|
-
while(true) do
|
108
|
-
yield
|
109
|
-
break unless Sqlite3_c.sqlite3_step(@reader) == Sqlite3_c::SQLITE_ROW
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
end
|
114
|
-
|
115
|
-
class Command < DataObject::Command
|
116
|
-
|
117
|
-
def execute_reader(*args)
|
118
|
-
super
|
119
|
-
sql = escape_sql(args)
|
120
|
-
result, ptr = Sqlite3_c.sqlite3_prepare_v2(@connection.db, sql, sql.size + 1)
|
121
|
-
unless result == Sqlite3_c::SQLITE_OK
|
122
|
-
raise QueryError, "Your query failed.\n#{Sqlite3_c.sqlite3_errmsg(@connection.db)}\nQUERY: \"#{sql}\""
|
123
|
-
else
|
124
|
-
reader = Reader.new(@connection.db, ptr)
|
125
|
-
|
126
|
-
if block_given?
|
127
|
-
return_value = yield(reader)
|
128
|
-
reader.close
|
129
|
-
return_value
|
130
|
-
else
|
131
|
-
reader
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def execute_non_query(*args)
|
137
|
-
super
|
138
|
-
sql = escape_sql(args)
|
139
|
-
result, reader = Sqlite3_c.sqlite3_prepare_v2(@connection.db, sql, -1)
|
140
|
-
unless result == Sqlite3_c::SQLITE_OK
|
141
|
-
Sqlite3_c.sqlite3_finalize(reader)
|
142
|
-
raise QueryError, "Your query failed.\n#{Sqlite3_c.sqlite3_errmsg(@connection.db)}\nQUERY: \"#{sql}\""
|
143
|
-
else
|
144
|
-
exec_result = Sqlite3_c.sqlite3_step(reader)
|
145
|
-
Sqlite3_c.sqlite3_finalize(reader)
|
146
|
-
if exec_result == Sqlite3_c::SQLITE_DONE
|
147
|
-
ResultData.new(@connection, Sqlite3_c.sqlite3_changes(@connection.db), Sqlite3_c.sqlite3_last_insert_rowid(@connection.db))
|
148
|
-
else
|
149
|
-
raise QueryError, "Your query failed or you tried to execute a SELECT query through execute_non_reader\n#{Sqlite3_c.sqlite3_errmsg(@connection.db)}\nQUERY: \"#{@text}\""
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
end
|
155
|
-
|
156
|
-
end
|
157
|
-
end
|
@@ -1,150 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
-
|
3
|
-
describe "Connectable", :shared => true do
|
4
|
-
before :each do
|
5
|
-
@c = $adapter_module::Connection.new($connection_string)
|
6
|
-
@c.open
|
7
|
-
end
|
8
|
-
|
9
|
-
after :each do
|
10
|
-
@c.close
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "DO::Connection" do
|
15
|
-
it_should_behave_like "Connectable"
|
16
|
-
|
17
|
-
it "should be able to be opened" do
|
18
|
-
@c.should be_is_a($adapter_module::Connection)
|
19
|
-
@c.state.should == 0
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should be able to create a related command" do
|
23
|
-
@c.open
|
24
|
-
cmd = @c.create_command("select * from table1")
|
25
|
-
cmd.connection.should == @c
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
describe "DO::Command" do
|
31
|
-
it_should_behave_like "Connectable"
|
32
|
-
|
33
|
-
def delete_3
|
34
|
-
cmd = @c.create_command("DELETE from table1 where id > 2")
|
35
|
-
cmd.execute_non_query
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should be able to be executed if it's a select" do
|
39
|
-
cmd = @c.create_command("select * from table1")
|
40
|
-
r = cmd.execute_reader
|
41
|
-
r.has_rows?.should be_true
|
42
|
-
r.close
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should be able to be executed if it's not a select" do
|
46
|
-
begin
|
47
|
-
cmd = @c.create_command("INSERT into table1(#{$escape}int#{$escape}) VALUES(7)")
|
48
|
-
result = cmd.execute_non_query
|
49
|
-
result.to_i.should == 1
|
50
|
-
result.class.to_s.should include("ResultData")
|
51
|
-
result.last_insert_row.should == 3
|
52
|
-
ensure
|
53
|
-
delete_3
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
it "should throw an error if a select is passed to execute_non_query" do
|
58
|
-
cmd = @c.create_command("SELECT * from table1")
|
59
|
-
lambda { cmd.execute_non_query }.should raise_error(DataObject::QueryError)
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should immediately close the reader and populate records_affected if a modification is passed to execute_reader" do
|
63
|
-
if $adapter_module.to_s == "DataObject::Postgres"
|
64
|
-
cmd = @c.create_command("INSERT into table1(#{$escaped_columns}) VALUES(NULL, now(), false, now(), NULL)")
|
65
|
-
else
|
66
|
-
cmd = @c.create_command("INSERT into table1(#{$escaped_columns}) VALUES(NULL, CURRENT_TIME, 0, CURRENT_DATE, NULL)")
|
67
|
-
end
|
68
|
-
r = cmd.execute_reader
|
69
|
-
r.records_affected.should == 1
|
70
|
-
lambda { r.name(0) }.should raise_error(DataObject::ReaderClosed)
|
71
|
-
delete_3
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
describe "DO::Reader" do
|
77
|
-
|
78
|
-
before :each do
|
79
|
-
@c = $adapter_module::Connection.new($connection_string)
|
80
|
-
@c.open
|
81
|
-
cmd = @c.create_command("select * from table1")
|
82
|
-
@r = cmd.execute_reader
|
83
|
-
end
|
84
|
-
|
85
|
-
after :each do
|
86
|
-
@c.close
|
87
|
-
end
|
88
|
-
|
89
|
-
it "should be able to get the field count" do
|
90
|
-
@r.field_count.should == 6
|
91
|
-
end
|
92
|
-
|
93
|
-
it "should be able to get field names" do
|
94
|
-
@r.name(0).should == "id"
|
95
|
-
@r.name(1).should == "int"
|
96
|
-
@r.name(2).should == "time"
|
97
|
-
@r.name(3).should == "bool"
|
98
|
-
@r.name(4).should == "date"
|
99
|
-
@r.name(5).should == "str"
|
100
|
-
@r.name(6).should == nil
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should be able to get field indexes" do
|
104
|
-
@r.get_index("id").should == 0
|
105
|
-
@r.get_index("int").should == 1
|
106
|
-
@r.get_index("time").should == 2
|
107
|
-
@r.get_index("bool").should == 3
|
108
|
-
@r.get_index("date").should == 4
|
109
|
-
@r.get_index("foo").should == nil
|
110
|
-
end
|
111
|
-
|
112
|
-
it "should be able to determine whether a particular field is null" do
|
113
|
-
@r.null?(0).should == false
|
114
|
-
@r.null?(1).should == true
|
115
|
-
end
|
116
|
-
|
117
|
-
it "should be able to get a typecasted version of a particular field" do
|
118
|
-
case $adapter_module.to_s
|
119
|
-
when "DataObject::Sqlite3"
|
120
|
-
@r.item(0).should == 1
|
121
|
-
@r.item(1).should == nil
|
122
|
-
@r.item(2).class.should == String
|
123
|
-
@r.item(3).should == 0
|
124
|
-
@r.item(4).class.should == String
|
125
|
-
when "DataObject::Mysql"
|
126
|
-
@r.item(0).should == 1
|
127
|
-
@r.item(1).should == nil
|
128
|
-
@r.item(2).class.should == DateTime
|
129
|
-
@r.item(3).should == false
|
130
|
-
@r.item(4).class.should == Date
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
it "should allow the use of the object being returned even after the reader is closed" do
|
135
|
-
val = @r.item(5)
|
136
|
-
val.should == "foo"
|
137
|
-
end
|
138
|
-
|
139
|
-
it "should be able to get to the next row" do
|
140
|
-
@r.next.should == true
|
141
|
-
@r.item(0).should == 2
|
142
|
-
end
|
143
|
-
|
144
|
-
it "should return nil and close the reader when the cursor reaches the end" do
|
145
|
-
@r.next
|
146
|
-
@r.next.should == nil
|
147
|
-
lambda { @r.name(0) }.should raise_error(DataObject::ReaderClosed)
|
148
|
-
end
|
149
|
-
|
150
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'spec'
|
2
|
-
$:.push File.join(File.dirname(__FILE__), '..')
|
3
|
-
require 'do'
|
4
|
-
|
5
|
-
adapter = (ENV["ADAPTER"] || "sqlite3").dup
|
6
|
-
|
7
|
-
require "do_#{adapter}"
|
8
|
-
|
9
|
-
adapter_module = adapter.dup
|
10
|
-
adapter_module[0] = adapter_module[0].chr.upcase
|
11
|
-
$adapter_module = DataObject.const_get(adapter_module)
|
12
|
-
|
13
|
-
$connection_string = case adapter
|
14
|
-
when "sqlite3"
|
15
|
-
"dbname=do_rb"
|
16
|
-
when "mysql"
|
17
|
-
"socket=/tmp/mysql.sock user=root dbname=do_rb"
|
18
|
-
when "postgres"
|
19
|
-
"dbname=do_rb"
|
20
|
-
end
|
21
|
-
|
22
|
-
$escape = $adapter_module::QUOTE_COLUMN
|
23
|
-
$escaped_columns = ["int", "time", "bool", "date", "str"].map {|x| "#{$escape}#{x}#{$escape}"}.join(", ")
|
24
|
-
$quote = quote = $adapter_module::QUOTE_STRING
|
25
|
-
|
26
|
-
begin
|
27
|
-
c = $adapter_module::Connection.new($connection_string)
|
28
|
-
c.open
|
29
|
-
cmd = c.create_command("DROP TABLE table1")
|
30
|
-
cmd.execute_non_query rescue nil
|
31
|
-
if adapter == "mysql"
|
32
|
-
sql = <<-SQL
|
33
|
-
CREATE TABLE table1 (
|
34
|
-
`id` serial NOT NULL,
|
35
|
-
`int` int(11) default NULL,
|
36
|
-
`time` timestamp,
|
37
|
-
`bool` tinyint(1) default NULL,
|
38
|
-
`date` date default NULL,
|
39
|
-
`str` varchar(20) default NULL,
|
40
|
-
PRIMARY KEY (`id`)
|
41
|
-
);
|
42
|
-
SQL
|
43
|
-
elsif adapter == "sqlite3"
|
44
|
-
sql = <<-SQL
|
45
|
-
CREATE TABLE table1 (
|
46
|
-
`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
47
|
-
`int` int(11) default NULL,
|
48
|
-
`time` timestamp,
|
49
|
-
`bool` tinyint(1) default NULL,
|
50
|
-
`date` date default NULL,
|
51
|
-
`str` varchar(20) default NULL
|
52
|
-
);
|
53
|
-
SQL
|
54
|
-
elsif adapter == "postgres"
|
55
|
-
sql = <<-SQL
|
56
|
-
CREATE TABLE table1 (
|
57
|
-
"id" serial NOT NULL,
|
58
|
-
"int" integer default NULL,
|
59
|
-
"time" timestamp,
|
60
|
-
"bool" boolean default NULL,
|
61
|
-
"date" date default NULL,
|
62
|
-
"str" varchar(20) default NULL,
|
63
|
-
PRIMARY KEY ("id")
|
64
|
-
);
|
65
|
-
SQL
|
66
|
-
end
|
67
|
-
cmd2 = c.create_command(sql)
|
68
|
-
cmd2.execute_non_query
|
69
|
-
insert1 = adapter == "postgres" ?
|
70
|
-
"INSERT into table1(#{$escaped_columns}) VALUES(NULL, #{quote}#{Time.now.to_s_db}#{quote}, false, #{quote}#{Date.today.to_s}#{quote}, #{quote}foo#{quote})" :
|
71
|
-
"INSERT into table1(#{$escaped_columns}) VALUES(NULL, #{quote}#{Time.now.to_s_db}#{quote}, 0, #{quote}#{Date.today.to_s}#{quote}, #{quote}foo#{quote})"
|
72
|
-
cmd3 = c.create_command(insert1)
|
73
|
-
cmd3.execute_non_query
|
74
|
-
insert2 = adapter == "postgres" ?
|
75
|
-
"INSERT into table1(#{$escaped_columns}) VALUES(17, #{quote}#{Time.now.to_s_db}#{quote}, true, NULL, NULL)" :
|
76
|
-
"INSERT into table1(#{$escaped_columns}) VALUES(17, #{quote}#{Time.now.to_s_db}#{quote}, 1, NULL, NULL)"
|
77
|
-
cmd4 = c.create_command(insert2)
|
78
|
-
cmd4.execute_non_query
|
79
|
-
ensure
|
80
|
-
c.close if defined?(c) && c
|
81
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'mkmf'
|
2
|
-
require 'open3'
|
3
|
-
|
4
|
-
def config_value(type)
|
5
|
-
ENV["MYSQL_#{type.upcase}"] || mysql_config(type)
|
6
|
-
end
|
7
|
-
|
8
|
-
def mysql_config(type)
|
9
|
-
|
10
|
-
sin, sout, serr = Open3.popen3("mysql_config5 --#{type}")
|
11
|
-
|
12
|
-
unless serr.read.empty?
|
13
|
-
sin, sout, serr = Open3.popen3("mysql_config --#{type}")
|
14
|
-
end
|
15
|
-
|
16
|
-
unless serr.read.empty?
|
17
|
-
raise "mysql_config not found"
|
18
|
-
end
|
19
|
-
|
20
|
-
sout.readline.chomp[2..-1]
|
21
|
-
end
|
22
|
-
|
23
|
-
$inc, $lib = dir_config('mysql', config_value('include'), config_value('libs_r'))
|
24
|
-
|
25
|
-
def have_build_env
|
26
|
-
libs = ['m', 'z', 'socket', 'nsl']
|
27
|
-
while not find_library('mysqlclient', 'mysql_query', config_value('libs'), $lib, "#{$lib}/mysql") do
|
28
|
-
exit 1 if libs.empty?
|
29
|
-
have_library(libs.shift)
|
30
|
-
end
|
31
|
-
true
|
32
|
-
# have_header('mysql.h')
|
33
|
-
end
|
34
|
-
|
35
|
-
required_libraries = [] #%w(m z socket nsl)
|
36
|
-
desired_functions = %w(mysql_ssl_set)
|
37
|
-
# compat_functions = %w(PQescapeString PQexecParams)
|
38
|
-
|
39
|
-
if have_build_env
|
40
|
-
$CFLAGS << ' -Wall '
|
41
|
-
dir_config("mysql_c")
|
42
|
-
create_makefile("mysql_c")
|
43
|
-
else
|
44
|
-
puts 'Could not find MySQL build environment (libraries & headers): Makefile not created'
|
45
|
-
end
|