datamapper 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/CHANGELOG +65 -0
  2. data/README +193 -1
  3. data/do_performance.rb +153 -0
  4. data/environment.rb +45 -0
  5. data/example.rb +119 -22
  6. data/lib/data_mapper.rb +36 -16
  7. data/lib/data_mapper/adapters/abstract_adapter.rb +8 -0
  8. data/lib/data_mapper/adapters/data_object_adapter.rb +360 -0
  9. data/lib/data_mapper/adapters/mysql_adapter.rb +30 -179
  10. data/lib/data_mapper/adapters/postgresql_adapter.rb +90 -199
  11. data/lib/data_mapper/adapters/sql/coersion.rb +32 -3
  12. data/lib/data_mapper/adapters/sql/commands/conditions.rb +97 -128
  13. data/lib/data_mapper/adapters/sql/commands/load_command.rb +234 -231
  14. data/lib/data_mapper/adapters/sql/commands/loader.rb +99 -0
  15. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +30 -0
  16. data/lib/data_mapper/adapters/sql/mappings/column.rb +68 -6
  17. data/lib/data_mapper/adapters/sql/mappings/schema.rb +6 -3
  18. data/lib/data_mapper/adapters/sql/mappings/table.rb +71 -42
  19. data/lib/data_mapper/adapters/sql/quoting.rb +8 -2
  20. data/lib/data_mapper/adapters/sqlite3_adapter.rb +32 -201
  21. data/lib/data_mapper/associations.rb +21 -7
  22. data/lib/data_mapper/associations/belongs_to_association.rb +96 -80
  23. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +158 -67
  24. data/lib/data_mapper/associations/has_many_association.rb +96 -78
  25. data/lib/data_mapper/associations/has_n_association.rb +64 -0
  26. data/lib/data_mapper/associations/has_one_association.rb +49 -79
  27. data/lib/data_mapper/associations/reference.rb +47 -0
  28. data/lib/data_mapper/base.rb +216 -50
  29. data/lib/data_mapper/callbacks.rb +71 -24
  30. data/lib/data_mapper/{session.rb → context.rb} +20 -8
  31. data/lib/data_mapper/database.rb +176 -45
  32. data/lib/data_mapper/embedded_value.rb +65 -0
  33. data/lib/data_mapper/identity_map.rb +12 -4
  34. data/lib/data_mapper/support/active_record_impersonation.rb +12 -8
  35. data/lib/data_mapper/support/enumerable.rb +8 -0
  36. data/lib/data_mapper/support/serialization.rb +13 -0
  37. data/lib/data_mapper/support/string.rb +1 -12
  38. data/lib/data_mapper/support/symbol.rb +3 -0
  39. data/lib/data_mapper/validations/unique_validator.rb +1 -2
  40. data/lib/data_mapper/validations/validation_helper.rb +18 -1
  41. data/performance.rb +109 -34
  42. data/plugins/can_has_sphinx/LICENSE +23 -0
  43. data/plugins/can_has_sphinx/README +4 -0
  44. data/plugins/can_has_sphinx/REVISION +1 -0
  45. data/plugins/can_has_sphinx/Rakefile +22 -0
  46. data/plugins/can_has_sphinx/init.rb +1 -0
  47. data/plugins/can_has_sphinx/install.rb +1 -0
  48. data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +123 -0
  49. data/plugins/can_has_sphinx/lib/sphinx.rb +460 -0
  50. data/plugins/can_has_sphinx/scripts/sphinx.sh +47 -0
  51. data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +41 -0
  52. data/plugins/dataobjects/REVISION +1 -0
  53. data/plugins/dataobjects/Rakefile +7 -0
  54. data/plugins/dataobjects/do.rb +246 -0
  55. data/plugins/dataobjects/do_mysql.rb +179 -0
  56. data/plugins/dataobjects/do_postgres.rb +181 -0
  57. data/plugins/dataobjects/do_sqlite3.rb +153 -0
  58. data/plugins/dataobjects/spec/do_spec.rb +150 -0
  59. data/plugins/dataobjects/spec/spec_helper.rb +81 -0
  60. data/plugins/dataobjects/swig_mysql/do_mysql.bundle +0 -0
  61. data/plugins/dataobjects/swig_mysql/extconf.rb +33 -0
  62. data/plugins/dataobjects/swig_mysql/mysql_c.c +18800 -0
  63. data/plugins/dataobjects/swig_mysql/mysql_c.i +8 -0
  64. data/plugins/dataobjects/swig_mysql/mysql_supp.i +46 -0
  65. data/plugins/dataobjects/swig_postgres/Makefile +146 -0
  66. data/plugins/dataobjects/swig_postgres/extconf.rb +29 -0
  67. data/plugins/dataobjects/swig_postgres/postgres_c.bundle +0 -0
  68. data/plugins/dataobjects/swig_postgres/postgres_c.c +8185 -0
  69. data/plugins/dataobjects/swig_postgres/postgres_c.i +73 -0
  70. data/plugins/dataobjects/swig_sqlite/db +0 -0
  71. data/plugins/dataobjects/swig_sqlite/extconf.rb +9 -0
  72. data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +4725 -0
  73. data/plugins/dataobjects/swig_sqlite/sqlite_c.i +168 -0
  74. data/rakefile.rb +45 -23
  75. data/spec/acts_as_tree_spec.rb +39 -0
  76. data/spec/associations_spec.rb +220 -0
  77. data/spec/attributes_spec.rb +15 -0
  78. data/spec/base_spec.rb +44 -0
  79. data/spec/callbacks_spec.rb +45 -0
  80. data/spec/can_has_sphinx.rb +6 -0
  81. data/spec/coersion_spec.rb +34 -0
  82. data/spec/conditions_spec.rb +49 -0
  83. data/spec/conversions_to_yaml_spec.rb +17 -0
  84. data/spec/count_command_spec.rb +11 -0
  85. data/spec/delete_command_spec.rb +1 -1
  86. data/spec/embedded_value_spec.rb +23 -0
  87. data/spec/fixtures/animals_exhibits.yaml +2 -0
  88. data/spec/fixtures/people.yaml +18 -1
  89. data/spec/{legacy.rb → legacy_spec.rb} +3 -3
  90. data/spec/load_command_spec.rb +157 -20
  91. data/spec/magic_columns_spec.rb +9 -0
  92. data/spec/mock_adapter.rb +20 -0
  93. data/spec/models/animal.rb +1 -1
  94. data/spec/models/animals_exhibit.rb +6 -0
  95. data/spec/models/exhibit.rb +2 -0
  96. data/spec/models/person.rb +26 -1
  97. data/spec/models/project.rb +19 -0
  98. data/spec/models/sales_person.rb +1 -0
  99. data/spec/models/section.rb +6 -0
  100. data/spec/models/zoo.rb +3 -1
  101. data/spec/query_spec.rb +9 -0
  102. data/spec/save_command_spec.rb +65 -1
  103. data/spec/schema_spec.rb +89 -0
  104. data/spec/single_table_inheritance_spec.rb +27 -0
  105. data/spec/spec_helper.rb +9 -55
  106. data/spec/{symbolic_operators.rb → symbolic_operators_spec.rb} +9 -5
  107. data/spec/{validates_confirmation_of.rb → validates_confirmation_of_spec.rb} +4 -3
  108. data/spec/{validates_format_of.rb → validates_format_of_spec.rb} +5 -4
  109. data/spec/{validates_length_of.rb → validates_length_of_spec.rb} +8 -7
  110. data/spec/{validates_uniqueness_of.rb → validates_uniqueness_of_spec.rb} +7 -10
  111. data/spec/{validations.rb → validations_spec.rb} +24 -6
  112. data/tasks/drivers.rb +20 -0
  113. data/tasks/fixtures.rb +42 -0
  114. metadata +181 -42
  115. data/lib/data_mapper/adapters/sql/commands/advanced_load_command.rb +0 -140
  116. data/lib/data_mapper/adapters/sql/commands/delete_command.rb +0 -113
  117. data/lib/data_mapper/adapters/sql/commands/save_command.rb +0 -141
  118. data/lib/data_mapper/adapters/sql/commands/table_exists_command.rb +0 -33
  119. data/lib/data_mapper/adapters/sql_adapter.rb +0 -163
  120. data/lib/data_mapper/associations/advanced_has_many_association.rb +0 -55
  121. data/lib/data_mapper/support/blank_slate.rb +0 -3
  122. data/lib/data_mapper/support/proc.rb +0 -69
  123. data/lib/data_mapper/support/struct.rb +0 -26
  124. data/lib/data_mapper/unit_of_work.rb +0 -38
  125. data/spec/basic_finder.rb +0 -67
  126. data/spec/belongs_to.rb +0 -47
  127. data/spec/has_and_belongs_to_many.rb +0 -25
  128. data/spec/has_many.rb +0 -34
  129. data/spec/new_record.rb +0 -24
  130. data/spec/sub_select.rb +0 -16
  131. data/spec/support/string_spec.rb +0 -7
@@ -0,0 +1,181 @@
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 close
64
+ if @state != STATE_CLOSED
65
+ Postgres_c.PQclear(@reader)
66
+ @state = STATE_CLOSED
67
+ true
68
+ else
69
+ false
70
+ end
71
+ end
72
+
73
+ def data_type_name(col)
74
+
75
+ end
76
+
77
+ def name(col)
78
+ super
79
+ Postgres_c.PQfname(@reader, col)
80
+ end
81
+
82
+ def get_index(name)
83
+ super
84
+ @fields.index(name)
85
+ end
86
+
87
+ def null?(idx)
88
+ super
89
+ Postgres_c.PQgetisnull(@reader, @cursor, idx) != 0
90
+ end
91
+
92
+ def item(idx)
93
+ super
94
+ val = Postgres_c.PQgetvalue(@reader, @cursor, idx)
95
+ typecast(val, @field_types[idx])
96
+ end
97
+
98
+ def next
99
+ super
100
+ if @cursor >= @rows - 1
101
+ @cursor = nil
102
+ close
103
+ return nil
104
+ end
105
+ @cursor += 1
106
+ true
107
+ end
108
+
109
+ protected
110
+ def native_type(col)
111
+ TYPES[Postgres_c.PQftype(@reader, col)]
112
+ end
113
+
114
+ def typecast(val, field_type)
115
+ return nil if val.nil?
116
+ case TYPES[field_type]
117
+ when "BOOL"
118
+ val == "t"
119
+ when "INT2", "INT4", "OID", "TID", "XID", "CID", "INT8"
120
+ val.to_i
121
+ when "FLOAT4", "FLOAT8", "NUMERIC", "CASH"
122
+ val.to_f
123
+ when "TIMESTAMP", "TIMETZ", "TIMESTAMPTZ"
124
+ DateTime.parse(val)
125
+ when "TIME"
126
+ DateTime.parse(val).to_time
127
+ when "DATE"
128
+ Date.parse(val)
129
+ else
130
+ val
131
+ end
132
+ end
133
+
134
+ end
135
+
136
+ class ResultData < DataObject::ResultData
137
+
138
+ def last_insert_row
139
+ @last_insert_row ||= begin
140
+ reader = @conn.create_command("select lastval()").execute_reader
141
+ reader.item(0).to_i
142
+ rescue QueryError
143
+ raise NoInsertError, "You tried to get the last inserted row without doing an insert\n#{Postgres_c.PQerrorMessage(@conn.db)}"
144
+ ensure
145
+ reader and reader.close
146
+ end
147
+ end
148
+
149
+ end
150
+
151
+ class Command < DataObject::Command
152
+
153
+ def execute_reader
154
+ super
155
+ reader = Postgres_c.PQexec(@connection.db, @text)
156
+ unless [Postgres_c::PGRES_COMMAND_OK, Postgres_c::PGRES_TUPLES_OK].include?(Postgres_c.PQresultStatus(reader))
157
+ raise QueryError, "Your query failed.\n#{Postgres_c.PQerrorMessage(@connection.db)}QUERY: \"#{@text}\""
158
+ end
159
+ Reader.new(@connection.db, reader)
160
+ end
161
+
162
+ def execute_non_query
163
+ super
164
+ results = Postgres_c.PQexec(@connection.db, @text)
165
+ status = Postgres_c.PQresultStatus(results)
166
+ if status == Postgres_c::PGRES_TUPLES_OK
167
+ Postgres_c.PQclear(results)
168
+ raise QueryError, "Your query failed or you tried to execute a SELECT query through execute_non_reader\n#{Postgres_c.PQerrorMessage(@connection.db)}\nQUERY: \"#{@text}\""
169
+ elsif status != Postgres_c::PGRES_COMMAND_OK
170
+ Postgres_c.PQclear(results)
171
+ raise QueryError, "Your query failed.\n#{Postgres_c.PQerrorMessage(@connection.db)}\nQUERY: \"#{@text}\""
172
+ end
173
+ rows_affected = Postgres_c.PQcmdTuples(results).to_i
174
+ Postgres_c.PQclear(results)
175
+ ResultData.new(@connection, rows_affected)
176
+ end
177
+
178
+ end
179
+
180
+ end
181
+ end
@@ -0,0 +1,153 @@
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
+ Command.new(self, text)
39
+ end
40
+
41
+ end
42
+
43
+ class Reader < DataObject::Reader
44
+
45
+ def initialize(db, reader)
46
+ @reader = reader
47
+ result = Sqlite3_c.sqlite3_step(reader)
48
+ rows_affected, field_count = Sqlite3_c.sqlite3_changes(db), Sqlite3_c.sqlite3_column_count(reader)
49
+ if field_count == 0
50
+ @records_affected = rows_affected
51
+ close
52
+ else
53
+ @field_count = field_count
54
+ @fields, @field_types = [], []
55
+ i = 0
56
+ while(i < @field_count)
57
+ @field_types.push(Sqlite3_c.sqlite3_column_type(reader, i))
58
+ @fields.push(Sqlite3_c.sqlite3_column_name(reader, i))
59
+ i += 1
60
+ end
61
+ case result
62
+ when Sqlite3_c::SQLITE_BUSY, Sqlite3_c::SQLITE_ERROR, Sqlite3_c::SQLITE_MISUSE
63
+ raise ReaderError, "An error occurred while trying to get the next row\n#{Sqlite3_c.sqlite3_errmsg(db)}"
64
+ else
65
+ @has_rows = result == Sqlite3_c::SQLITE_ROW
66
+ @state = STATE_OPEN
67
+ close unless @has_rows
68
+ end
69
+ end
70
+ end
71
+
72
+ def close
73
+ if @state != STATE_CLOSED
74
+ Sqlite3_c.sqlite3_finalize(@reader)
75
+ @state = STATE_CLOSED
76
+ true
77
+ else
78
+ false
79
+ end
80
+ end
81
+
82
+ def name(idx)
83
+ super
84
+ @fields[idx]
85
+ end
86
+
87
+ def get_index(name)
88
+ super
89
+ @fields.index(name)
90
+ end
91
+
92
+ def null?(idx)
93
+ super
94
+ item(idx).nil?
95
+ end
96
+
97
+ def item(idx)
98
+ super
99
+ case @field_types[idx]
100
+ when 1 # SQLITE_INTEGER
101
+ Sqlite3_c.sqlite3_column_int(@reader, idx).to_i
102
+ when 2 # SQLITE_FLOAT
103
+ Sqlite3_c.sqlite3_column_double(@reader, idx)
104
+ else
105
+ Sqlite3_c.sqlite3_column_text(@reader, idx)
106
+ end
107
+ end
108
+
109
+ def next
110
+ result = Sqlite3_c.sqlite3_step(@reader)
111
+ unless result == Sqlite3_c::SQLITE_ROW
112
+ close
113
+ nil
114
+ else
115
+ true
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ class Command < DataObject::Command
122
+
123
+ def execute_reader
124
+ super
125
+ result, reader = Sqlite3_c.sqlite3_prepare_v2(@connection.db, @text, @text.size + 1)
126
+ unless result == Sqlite3_c::SQLITE_OK
127
+ raise QueryError, "Your query failed.\n#{Sqlite3_c.sqlite3_errmsg(@connection.db)}\nQUERY: \"#{@text}\""
128
+ else
129
+ Reader.new(@connection.db, reader)
130
+ end
131
+ end
132
+
133
+ def execute_non_query
134
+ super
135
+ result, reader = Sqlite3_c.sqlite3_prepare_v2(@connection.db, @text, -1)
136
+ unless result == Sqlite3_c::SQLITE_OK
137
+ Sqlite3_c.sqlite3_finalize(reader)
138
+ raise QueryError, "Your query failed.\n#{Sqlite3_c.sqlite3_errmsg(@connection.db)}\nQUERY: \"#{@text}\""
139
+ else
140
+ exec_result = Sqlite3_c.sqlite3_step(reader)
141
+ Sqlite3_c.sqlite3_finalize(reader)
142
+ if exec_result == Sqlite3_c::SQLITE_DONE
143
+ ResultData.new(@connection, Sqlite3_c.sqlite3_changes(@connection.db), Sqlite3_c.sqlite3_last_insert_rowid(@connection.db))
144
+ else
145
+ 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}\""
146
+ end
147
+ end
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+ end
@@ -0,0 +1,150 @@
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