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.
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