viking-sequel 3.10.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 (237) hide show
  1. data/CHANGELOG +3134 -0
  2. data/COPYING +19 -0
  3. data/README.rdoc +723 -0
  4. data/Rakefile +193 -0
  5. data/bin/sequel +196 -0
  6. data/doc/advanced_associations.rdoc +644 -0
  7. data/doc/cheat_sheet.rdoc +218 -0
  8. data/doc/dataset_basics.rdoc +106 -0
  9. data/doc/dataset_filtering.rdoc +158 -0
  10. data/doc/opening_databases.rdoc +296 -0
  11. data/doc/prepared_statements.rdoc +104 -0
  12. data/doc/reflection.rdoc +84 -0
  13. data/doc/release_notes/1.0.txt +38 -0
  14. data/doc/release_notes/1.1.txt +143 -0
  15. data/doc/release_notes/1.3.txt +101 -0
  16. data/doc/release_notes/1.4.0.txt +53 -0
  17. data/doc/release_notes/1.5.0.txt +155 -0
  18. data/doc/release_notes/2.0.0.txt +298 -0
  19. data/doc/release_notes/2.1.0.txt +271 -0
  20. data/doc/release_notes/2.10.0.txt +328 -0
  21. data/doc/release_notes/2.11.0.txt +215 -0
  22. data/doc/release_notes/2.12.0.txt +534 -0
  23. data/doc/release_notes/2.2.0.txt +253 -0
  24. data/doc/release_notes/2.3.0.txt +88 -0
  25. data/doc/release_notes/2.4.0.txt +106 -0
  26. data/doc/release_notes/2.5.0.txt +137 -0
  27. data/doc/release_notes/2.6.0.txt +157 -0
  28. data/doc/release_notes/2.7.0.txt +166 -0
  29. data/doc/release_notes/2.8.0.txt +171 -0
  30. data/doc/release_notes/2.9.0.txt +97 -0
  31. data/doc/release_notes/3.0.0.txt +221 -0
  32. data/doc/release_notes/3.1.0.txt +406 -0
  33. data/doc/release_notes/3.10.0.txt +286 -0
  34. data/doc/release_notes/3.2.0.txt +268 -0
  35. data/doc/release_notes/3.3.0.txt +192 -0
  36. data/doc/release_notes/3.4.0.txt +325 -0
  37. data/doc/release_notes/3.5.0.txt +510 -0
  38. data/doc/release_notes/3.6.0.txt +366 -0
  39. data/doc/release_notes/3.7.0.txt +179 -0
  40. data/doc/release_notes/3.8.0.txt +151 -0
  41. data/doc/release_notes/3.9.0.txt +233 -0
  42. data/doc/schema.rdoc +36 -0
  43. data/doc/sharding.rdoc +113 -0
  44. data/doc/virtual_rows.rdoc +205 -0
  45. data/lib/sequel.rb +1 -0
  46. data/lib/sequel/adapters/ado.rb +90 -0
  47. data/lib/sequel/adapters/ado/mssql.rb +30 -0
  48. data/lib/sequel/adapters/amalgalite.rb +176 -0
  49. data/lib/sequel/adapters/db2.rb +139 -0
  50. data/lib/sequel/adapters/dbi.rb +113 -0
  51. data/lib/sequel/adapters/do.rb +188 -0
  52. data/lib/sequel/adapters/do/mysql.rb +49 -0
  53. data/lib/sequel/adapters/do/postgres.rb +91 -0
  54. data/lib/sequel/adapters/do/sqlite.rb +40 -0
  55. data/lib/sequel/adapters/firebird.rb +283 -0
  56. data/lib/sequel/adapters/informix.rb +77 -0
  57. data/lib/sequel/adapters/jdbc.rb +587 -0
  58. data/lib/sequel/adapters/jdbc/as400.rb +58 -0
  59. data/lib/sequel/adapters/jdbc/h2.rb +133 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
  61. data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
  62. data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
  64. data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
  65. data/lib/sequel/adapters/mysql.rb +421 -0
  66. data/lib/sequel/adapters/odbc.rb +143 -0
  67. data/lib/sequel/adapters/odbc/mssql.rb +42 -0
  68. data/lib/sequel/adapters/openbase.rb +64 -0
  69. data/lib/sequel/adapters/oracle.rb +131 -0
  70. data/lib/sequel/adapters/postgres.rb +504 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +490 -0
  72. data/lib/sequel/adapters/shared/mysql.rb +498 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +195 -0
  74. data/lib/sequel/adapters/shared/postgres.rb +830 -0
  75. data/lib/sequel/adapters/shared/progress.rb +44 -0
  76. data/lib/sequel/adapters/shared/sqlite.rb +389 -0
  77. data/lib/sequel/adapters/sqlite.rb +224 -0
  78. data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
  79. data/lib/sequel/connection_pool.rb +99 -0
  80. data/lib/sequel/connection_pool/sharded_single.rb +84 -0
  81. data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
  82. data/lib/sequel/connection_pool/single.rb +29 -0
  83. data/lib/sequel/connection_pool/threaded.rb +150 -0
  84. data/lib/sequel/core.rb +293 -0
  85. data/lib/sequel/core_sql.rb +241 -0
  86. data/lib/sequel/database.rb +1079 -0
  87. data/lib/sequel/database/schema_generator.rb +327 -0
  88. data/lib/sequel/database/schema_methods.rb +203 -0
  89. data/lib/sequel/database/schema_sql.rb +320 -0
  90. data/lib/sequel/dataset.rb +32 -0
  91. data/lib/sequel/dataset/actions.rb +441 -0
  92. data/lib/sequel/dataset/features.rb +86 -0
  93. data/lib/sequel/dataset/graph.rb +254 -0
  94. data/lib/sequel/dataset/misc.rb +119 -0
  95. data/lib/sequel/dataset/mutation.rb +64 -0
  96. data/lib/sequel/dataset/prepared_statements.rb +227 -0
  97. data/lib/sequel/dataset/query.rb +709 -0
  98. data/lib/sequel/dataset/sql.rb +996 -0
  99. data/lib/sequel/exceptions.rb +51 -0
  100. data/lib/sequel/extensions/blank.rb +43 -0
  101. data/lib/sequel/extensions/inflector.rb +242 -0
  102. data/lib/sequel/extensions/looser_typecasting.rb +21 -0
  103. data/lib/sequel/extensions/migration.rb +239 -0
  104. data/lib/sequel/extensions/named_timezones.rb +61 -0
  105. data/lib/sequel/extensions/pagination.rb +100 -0
  106. data/lib/sequel/extensions/pretty_table.rb +82 -0
  107. data/lib/sequel/extensions/query.rb +52 -0
  108. data/lib/sequel/extensions/schema_dumper.rb +271 -0
  109. data/lib/sequel/extensions/sql_expr.rb +122 -0
  110. data/lib/sequel/extensions/string_date_time.rb +46 -0
  111. data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
  112. data/lib/sequel/metaprogramming.rb +9 -0
  113. data/lib/sequel/model.rb +120 -0
  114. data/lib/sequel/model/associations.rb +1514 -0
  115. data/lib/sequel/model/base.rb +1069 -0
  116. data/lib/sequel/model/default_inflections.rb +45 -0
  117. data/lib/sequel/model/errors.rb +39 -0
  118. data/lib/sequel/model/exceptions.rb +21 -0
  119. data/lib/sequel/model/inflections.rb +162 -0
  120. data/lib/sequel/model/plugins.rb +70 -0
  121. data/lib/sequel/plugins/active_model.rb +59 -0
  122. data/lib/sequel/plugins/association_dependencies.rb +103 -0
  123. data/lib/sequel/plugins/association_proxies.rb +41 -0
  124. data/lib/sequel/plugins/boolean_readers.rb +53 -0
  125. data/lib/sequel/plugins/caching.rb +141 -0
  126. data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
  127. data/lib/sequel/plugins/composition.rb +138 -0
  128. data/lib/sequel/plugins/force_encoding.rb +72 -0
  129. data/lib/sequel/plugins/hook_class_methods.rb +126 -0
  130. data/lib/sequel/plugins/identity_map.rb +116 -0
  131. data/lib/sequel/plugins/instance_filters.rb +98 -0
  132. data/lib/sequel/plugins/instance_hooks.rb +57 -0
  133. data/lib/sequel/plugins/lazy_attributes.rb +77 -0
  134. data/lib/sequel/plugins/many_through_many.rb +208 -0
  135. data/lib/sequel/plugins/nested_attributes.rb +206 -0
  136. data/lib/sequel/plugins/optimistic_locking.rb +81 -0
  137. data/lib/sequel/plugins/rcte_tree.rb +281 -0
  138. data/lib/sequel/plugins/schema.rb +66 -0
  139. data/lib/sequel/plugins/serialization.rb +166 -0
  140. data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
  141. data/lib/sequel/plugins/subclasses.rb +45 -0
  142. data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
  143. data/lib/sequel/plugins/timestamps.rb +87 -0
  144. data/lib/sequel/plugins/touch.rb +118 -0
  145. data/lib/sequel/plugins/typecast_on_load.rb +72 -0
  146. data/lib/sequel/plugins/validation_class_methods.rb +405 -0
  147. data/lib/sequel/plugins/validation_helpers.rb +223 -0
  148. data/lib/sequel/sql.rb +1020 -0
  149. data/lib/sequel/timezones.rb +161 -0
  150. data/lib/sequel/version.rb +12 -0
  151. data/lib/sequel_core.rb +1 -0
  152. data/lib/sequel_model.rb +1 -0
  153. data/spec/adapters/firebird_spec.rb +407 -0
  154. data/spec/adapters/informix_spec.rb +97 -0
  155. data/spec/adapters/mssql_spec.rb +403 -0
  156. data/spec/adapters/mysql_spec.rb +1019 -0
  157. data/spec/adapters/oracle_spec.rb +286 -0
  158. data/spec/adapters/postgres_spec.rb +969 -0
  159. data/spec/adapters/spec_helper.rb +51 -0
  160. data/spec/adapters/sqlite_spec.rb +432 -0
  161. data/spec/core/connection_pool_spec.rb +808 -0
  162. data/spec/core/core_sql_spec.rb +417 -0
  163. data/spec/core/database_spec.rb +1662 -0
  164. data/spec/core/dataset_spec.rb +3827 -0
  165. data/spec/core/expression_filters_spec.rb +595 -0
  166. data/spec/core/object_graph_spec.rb +296 -0
  167. data/spec/core/schema_generator_spec.rb +159 -0
  168. data/spec/core/schema_spec.rb +830 -0
  169. data/spec/core/spec_helper.rb +56 -0
  170. data/spec/core/version_spec.rb +7 -0
  171. data/spec/extensions/active_model_spec.rb +76 -0
  172. data/spec/extensions/association_dependencies_spec.rb +127 -0
  173. data/spec/extensions/association_proxies_spec.rb +50 -0
  174. data/spec/extensions/blank_spec.rb +67 -0
  175. data/spec/extensions/boolean_readers_spec.rb +92 -0
  176. data/spec/extensions/caching_spec.rb +250 -0
  177. data/spec/extensions/class_table_inheritance_spec.rb +252 -0
  178. data/spec/extensions/composition_spec.rb +194 -0
  179. data/spec/extensions/force_encoding_spec.rb +117 -0
  180. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  181. data/spec/extensions/identity_map_spec.rb +202 -0
  182. data/spec/extensions/inflector_spec.rb +181 -0
  183. data/spec/extensions/instance_filters_spec.rb +55 -0
  184. data/spec/extensions/instance_hooks_spec.rb +133 -0
  185. data/spec/extensions/lazy_attributes_spec.rb +153 -0
  186. data/spec/extensions/looser_typecasting_spec.rb +39 -0
  187. data/spec/extensions/many_through_many_spec.rb +884 -0
  188. data/spec/extensions/migration_spec.rb +332 -0
  189. data/spec/extensions/named_timezones_spec.rb +72 -0
  190. data/spec/extensions/nested_attributes_spec.rb +396 -0
  191. data/spec/extensions/optimistic_locking_spec.rb +100 -0
  192. data/spec/extensions/pagination_spec.rb +99 -0
  193. data/spec/extensions/pretty_table_spec.rb +91 -0
  194. data/spec/extensions/query_spec.rb +85 -0
  195. data/spec/extensions/rcte_tree_spec.rb +205 -0
  196. data/spec/extensions/schema_dumper_spec.rb +357 -0
  197. data/spec/extensions/schema_spec.rb +127 -0
  198. data/spec/extensions/serialization_spec.rb +209 -0
  199. data/spec/extensions/single_table_inheritance_spec.rb +96 -0
  200. data/spec/extensions/spec_helper.rb +91 -0
  201. data/spec/extensions/sql_expr_spec.rb +89 -0
  202. data/spec/extensions/string_date_time_spec.rb +93 -0
  203. data/spec/extensions/subclasses_spec.rb +52 -0
  204. data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
  205. data/spec/extensions/thread_local_timezones_spec.rb +45 -0
  206. data/spec/extensions/timestamps_spec.rb +150 -0
  207. data/spec/extensions/touch_spec.rb +155 -0
  208. data/spec/extensions/typecast_on_load_spec.rb +69 -0
  209. data/spec/extensions/validation_class_methods_spec.rb +984 -0
  210. data/spec/extensions/validation_helpers_spec.rb +438 -0
  211. data/spec/integration/associations_test.rb +281 -0
  212. data/spec/integration/database_test.rb +26 -0
  213. data/spec/integration/dataset_test.rb +963 -0
  214. data/spec/integration/eager_loader_test.rb +734 -0
  215. data/spec/integration/model_test.rb +130 -0
  216. data/spec/integration/plugin_test.rb +814 -0
  217. data/spec/integration/prepared_statement_test.rb +213 -0
  218. data/spec/integration/schema_test.rb +361 -0
  219. data/spec/integration/spec_helper.rb +73 -0
  220. data/spec/integration/timezone_test.rb +55 -0
  221. data/spec/integration/transaction_test.rb +122 -0
  222. data/spec/integration/type_test.rb +96 -0
  223. data/spec/model/association_reflection_spec.rb +175 -0
  224. data/spec/model/associations_spec.rb +2633 -0
  225. data/spec/model/base_spec.rb +418 -0
  226. data/spec/model/dataset_methods_spec.rb +78 -0
  227. data/spec/model/eager_loading_spec.rb +1391 -0
  228. data/spec/model/hooks_spec.rb +240 -0
  229. data/spec/model/inflector_spec.rb +26 -0
  230. data/spec/model/model_spec.rb +593 -0
  231. data/spec/model/plugins_spec.rb +236 -0
  232. data/spec/model/record_spec.rb +1500 -0
  233. data/spec/model/spec_helper.rb +97 -0
  234. data/spec/model/validations_spec.rb +153 -0
  235. data/spec/rcov.opts +6 -0
  236. data/spec/spec_config.rb.example +10 -0
  237. metadata +346 -0
@@ -0,0 +1,161 @@
1
+ module Sequel
2
+ # The offset of the current time zone from UTC, in seconds.
3
+ LOCAL_DATETIME_OFFSET_SECS = Time.now.utc_offset
4
+
5
+ # The offset of the current time zone from UTC, as a fraction of a day.
6
+ LOCAL_DATETIME_OFFSET = respond_to?(:Rational, true) ? Rational(LOCAL_DATETIME_OFFSET_SECS, 60*60*24) : LOCAL_DATETIME_OFFSET_SECS/60/60/24.0
7
+
8
+ @application_timezone = nil
9
+ @database_timezone = nil
10
+ @typecast_timezone = nil
11
+
12
+ module Timezones
13
+ attr_reader :application_timezone, :database_timezone, :typecast_timezone
14
+
15
+ %w'application database typecast'.each do |t|
16
+ class_eval("def #{t}_timezone=(tz); @#{t}_timezone = convert_timezone_setter_arg(tz) end", __FILE__, __LINE__)
17
+ end
18
+
19
+ # Convert the given Time/DateTime object into the database timezone, used when
20
+ # literalizing objects in an SQL string.
21
+ def application_to_database_timestamp(v)
22
+ convert_output_timestamp(v, Sequel.database_timezone)
23
+ end
24
+
25
+ # Convert the given object into an object of Sequel.datetime_class in the
26
+ # application_timezone. Used when coverting datetime/timestamp columns
27
+ # returned by the database.
28
+ def database_to_application_timestamp(v)
29
+ convert_timestamp(v, Sequel.database_timezone)
30
+ end
31
+
32
+ # Sets the database, application, and typecasting timezones to the given timezone.
33
+ def default_timezone=(tz)
34
+ self.database_timezone = tz
35
+ self.application_timezone = tz
36
+ self.typecast_timezone = tz
37
+ end
38
+
39
+ # Convert the given object into an object of Sequel.datetime_class in the
40
+ # application_timezone. Used when typecasting values when assigning them
41
+ # to model datetime attributes.
42
+ def typecast_to_application_timestamp(v)
43
+ convert_timestamp(v, Sequel.typecast_timezone)
44
+ end
45
+
46
+ private
47
+
48
+ # Convert the given DateTime to the given input_timezone, keeping the
49
+ # same time and just modifying the timezone.
50
+ def convert_input_datetime_no_offset(v, input_timezone)
51
+ case input_timezone
52
+ when :utc, nil
53
+ v # DateTime assumes UTC if no offset is given
54
+ when :local
55
+ v.new_offset(LOCAL_DATETIME_OFFSET) - LOCAL_DATETIME_OFFSET
56
+ else
57
+ convert_input_datetime_other(v, input_timezone)
58
+ end
59
+ end
60
+
61
+ # Convert the given DateTime to the given input_timezone that is not supported
62
+ # by default (such as nil, :local, or :utc). Raises an error by default.
63
+ # Can be overridden in extensions.
64
+ def convert_input_datetime_other(v, input_timezone)
65
+ raise InvalidValue, "Invalid input_timezone: #{input_timezone.inspect}"
66
+ end
67
+
68
+ # Converts the object from a String, Array, Date, DateTime, or Time into an
69
+ # instance of Sequel.datetime_class. If given an array or a string that doesn't
70
+ # contain an offset, assume that the array/string is already in the given input_timezone.
71
+ def convert_input_timestamp(v, input_timezone)
72
+ case v
73
+ when String
74
+ v2 = Sequel.string_to_datetime(v)
75
+ if !input_timezone || Date._parse(v).has_key?(:offset)
76
+ v2
77
+ else
78
+ # Correct for potentially wrong offset if string doesn't include offset
79
+ if v2.is_a?(DateTime)
80
+ v2 = convert_input_datetime_no_offset(v2, input_timezone)
81
+ else
82
+ # Time assumes local time if no offset is given
83
+ v2 = v2.getutc + LOCAL_DATETIME_OFFSET_SECS if input_timezone == :utc
84
+ end
85
+ v2
86
+ end
87
+ when Array
88
+ y, mo, d, h, mi, s = v
89
+ if datetime_class == DateTime
90
+ convert_input_datetime_no_offset(DateTime.civil(y, mo, d, h, mi, s, 0), input_timezone)
91
+ else
92
+ Time.send(input_timezone == :utc ? :utc : :local, y, mo, d, h, mi, s)
93
+ end
94
+ when Time
95
+ if datetime_class == DateTime
96
+ v.respond_to?(:to_datetime) ? v.to_datetime : string_to_datetime(v.iso8601)
97
+ else
98
+ v
99
+ end
100
+ when DateTime
101
+ if datetime_class == DateTime
102
+ v
103
+ else
104
+ v.respond_to?(:to_time) ? v.to_time : string_to_datetime(v.to_s)
105
+ end
106
+ when Date
107
+ convert_input_timestamp(v.to_s, input_timezone)
108
+ else
109
+ raise InvalidValue, "Invalid convert_input_timestamp type: #{v.inspect}"
110
+ end
111
+ end
112
+
113
+ # Convert the given DateTime to the given output_timezone that is not supported
114
+ # by default (such as nil, :local, or :utc). Raises an error by default.
115
+ # Can be overridden in extensions.
116
+ def convert_output_datetime_other(v, output_timezone)
117
+ raise InvalidValue, "Invalid output_timezone: #{output_timezone.inspect}"
118
+ end
119
+
120
+ # Converts the object to the given output_timezone.
121
+ def convert_output_timestamp(v, output_timezone)
122
+ if output_timezone
123
+ if v.is_a?(DateTime)
124
+ case output_timezone
125
+ when :utc
126
+ v.new_offset(0)
127
+ when :local
128
+ v.new_offset(LOCAL_DATETIME_OFFSET)
129
+ else
130
+ convert_output_datetime_other(v, output_timezone)
131
+ end
132
+ else
133
+ v.send(output_timezone == :utc ? :getutc : :getlocal)
134
+ end
135
+ else
136
+ v
137
+ end
138
+ end
139
+
140
+ # Converts the given object from the given input timezone to the
141
+ # application timezone using convert_input_timestamp and
142
+ # convert_output_timestamp.
143
+ def convert_timestamp(v, input_timezone)
144
+ begin
145
+ convert_output_timestamp(convert_input_timestamp(v, input_timezone), Sequel.application_timezone)
146
+ rescue InvalidValue
147
+ raise
148
+ rescue => e
149
+ raise convert_exception_class(e, InvalidValue)
150
+ end
151
+ end
152
+
153
+ # Convert the timezone setter argument. Returns argument given by default,
154
+ # exists for easier overriding in extensions.
155
+ def convert_timezone_setter_arg(tz)
156
+ tz
157
+ end
158
+ end
159
+
160
+ extend Timezones
161
+ end
@@ -0,0 +1,12 @@
1
+ module Sequel
2
+ MAJOR = 3
3
+ MINOR = 10
4
+ TINY = 0
5
+
6
+ VERSION = [MAJOR, MINOR, TINY].join('.')
7
+
8
+ # The version of Sequel you are using, as a string (e.g. "2.11.0")
9
+ def self.version
10
+ VERSION
11
+ end
12
+ end
@@ -0,0 +1 @@
1
+ require 'sequel/core'
@@ -0,0 +1 @@
1
+ require 'sequel/model'
@@ -0,0 +1,407 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ unless defined?(FIREBIRD_DB)
4
+ FIREBIRD_URL = 'firebird://sysdba:masterkey@localhost/reality_spec' unless defined? FIREBIRD_URL
5
+ FIREBIRD_DB = Sequel.connect(ENV['SEQUEL_FB_SPEC_DB']||FIREBIRD_URL)
6
+ end
7
+ INTEGRATION_DB = FIREBIRD_DB unless defined?(INTEGRATION_DB)
8
+
9
+ def FIREBIRD_DB.sqls
10
+ (@sqls ||= [])
11
+ end
12
+ logger = Object.new
13
+ def logger.method_missing(m, msg)
14
+ FIREBIRD_DB.sqls.push(msg)
15
+ end
16
+ FIREBIRD_DB.logger = logger
17
+
18
+ FIREBIRD_DB.create_table! :test do
19
+ varchar :name, :size => 50
20
+ integer :val, :index => true
21
+ end
22
+
23
+ FIREBIRD_DB.create_table! :test2 do
24
+ integer :val
25
+ timestamp :time_stamp
26
+ end
27
+
28
+ FIREBIRD_DB.create_table! :test3 do
29
+ integer :val
30
+ timestamp :time_stamp
31
+ end
32
+
33
+ FIREBIRD_DB.create_table! :test5 do
34
+ primary_key :xid
35
+ integer :val
36
+ end
37
+
38
+ FIREBIRD_DB.create_table! :test6 do
39
+ primary_key :xid
40
+ blob :val
41
+ String :val2
42
+ varchar :val3, :size=>200
43
+ String :val4, :text=>true
44
+ end
45
+
46
+ context "A Firebird database" do
47
+ before do
48
+ @db = FIREBIRD_DB
49
+ end
50
+
51
+ specify "should provide disconnect functionality" do
52
+ @db.tables
53
+ @db.pool.size.should == 1
54
+ @db.disconnect
55
+ @db.pool.size.should == 0
56
+ end
57
+
58
+ specify "should raise Sequel::Error on error" do
59
+ proc{@db << "SELECT 1 + 'a'"}.should raise_error(Sequel::Error)
60
+ end
61
+ end
62
+
63
+ context "A Firebird dataset" do
64
+ before do
65
+ @d = FIREBIRD_DB[:test]
66
+ @d.delete # remove all records
67
+ @d.quote_identifiers = true
68
+ end
69
+
70
+ specify "should return the correct record count" do
71
+ @d.count.should == 0
72
+ @d << {:name => 'abc', :val => 123}
73
+ @d << {:name => 'abc', :val => 456}
74
+ @d << {:name => 'def', :val => 789}
75
+ @d.count.should == 3
76
+ end
77
+
78
+ specify "should return the correct records" do
79
+ @d.to_a.should == []
80
+ @d << {:name => 'abc', :val => 123}
81
+ @d << {:name => 'abc', :val => 456}
82
+ @d << {:name => 'def', :val => 789}
83
+
84
+ @d.order(:val).to_a.should == [
85
+ {:name => 'abc', :val => 123},
86
+ {:name => 'abc', :val => 456},
87
+ {:name => 'def', :val => 789}
88
+ ]
89
+ end
90
+
91
+ specify "should update records correctly" do
92
+ @d << {:name => 'abc', :val => 123}
93
+ @d << {:name => 'abc', :val => 456}
94
+ @d << {:name => 'def', :val => 789}
95
+ @d.filter(:name => 'abc').update(:val => 530)
96
+
97
+ # the third record should stay the same
98
+ # floating-point precision bullshit
99
+ @d[:name => 'def'][:val].should == 789
100
+ @d.filter(:val => 530).count.should == 2
101
+ end
102
+
103
+ specify "should delete records correctly" do
104
+ @d << {:name => 'abc', :val => 123}
105
+ @d << {:name => 'abc', :val => 456}
106
+ @d << {:name => 'def', :val => 789}
107
+ @d.filter(:name => 'abc').delete
108
+
109
+ @d.count.should == 1
110
+ @d.first[:name].should == 'def'
111
+ end
112
+
113
+ specify "should be able to literalize booleans" do
114
+ proc {@d.literal(true)}.should_not raise_error
115
+ proc {@d.literal(false)}.should_not raise_error
116
+ end
117
+
118
+ specify "should quote columns and tables using double quotes if quoting identifiers" do
119
+ @d.quote_identifiers = true
120
+ @d.select(:name).sql.should == \
121
+ 'SELECT "NAME" FROM "TEST"'
122
+
123
+ @d.select('COUNT(*)'.lit).sql.should == \
124
+ 'SELECT COUNT(*) FROM "TEST"'
125
+
126
+ @d.select(:max[:val]).sql.should == \
127
+ 'SELECT max("VAL") FROM "TEST"'
128
+
129
+ @d.select(:now[]).sql.should == \
130
+ 'SELECT now() FROM "TEST"'
131
+
132
+ @d.select(:max[:items__val]).sql.should == \
133
+ 'SELECT max("ITEMS"."VAL") FROM "TEST"'
134
+
135
+ @d.order(:name.desc).sql.should == \
136
+ 'SELECT * FROM "TEST" ORDER BY "NAME" DESC'
137
+
138
+ @d.select('TEST.NAME AS item_:name'.lit).sql.should == \
139
+ 'SELECT TEST.NAME AS item_:name FROM "TEST"'
140
+
141
+ @d.select('"NAME"'.lit).sql.should == \
142
+ 'SELECT "NAME" FROM "TEST"'
143
+
144
+ @d.select('max(TEST."NAME") AS "max_:name"'.lit).sql.should == \
145
+ 'SELECT max(TEST."NAME") AS "max_:name" FROM "TEST"'
146
+
147
+ @d.select(:test[:ABC, 'hello']).sql.should == \
148
+ "SELECT test(\"ABC\", 'hello') FROM \"TEST\""
149
+
150
+ @d.select(:test[:ABC__DEF, 'hello']).sql.should == \
151
+ "SELECT test(\"ABC\".\"DEF\", 'hello') FROM \"TEST\""
152
+
153
+ @d.select(:test[:ABC__DEF, 'hello'].as(:X2)).sql.should == \
154
+ "SELECT test(\"ABC\".\"DEF\", 'hello') AS \"X2\" FROM \"TEST\""
155
+
156
+ @d.insert_sql(:val => 333).should =~ \
157
+ /\AINSERT INTO "TEST" \("VAL"\) VALUES \(333\)( RETURNING NULL)?\z/
158
+
159
+ @d.insert_sql(:X => :Y).should =~ \
160
+ /\AINSERT INTO "TEST" \("X"\) VALUES \("Y"\)( RETURNING NULL)?\z/
161
+ end
162
+
163
+ specify "should quote fields correctly when reversing the order if quoting identifiers" do
164
+ @d.quote_identifiers = true
165
+ @d.reverse_order(:name).sql.should == \
166
+ 'SELECT * FROM "TEST" ORDER BY "NAME" DESC'
167
+
168
+ @d.reverse_order(:name.desc).sql.should == \
169
+ 'SELECT * FROM "TEST" ORDER BY "NAME" ASC'
170
+
171
+ @d.reverse_order(:name, :test.desc).sql.should == \
172
+ 'SELECT * FROM "TEST" ORDER BY "NAME" DESC, "TEST" ASC'
173
+
174
+ @d.reverse_order(:name.desc, :test).sql.should == \
175
+ 'SELECT * FROM "TEST" ORDER BY "NAME" ASC, "TEST" DESC'
176
+ end
177
+
178
+ specify "should support transactions" do
179
+ FIREBIRD_DB.transaction do
180
+ @d << {:name => 'abc', :val => 1}
181
+ end
182
+
183
+ @d.count.should == 1
184
+ end
185
+
186
+ specify "should have #transaction yield the connection" do
187
+ FIREBIRD_DB.transaction do |conn|
188
+ conn.should_not == nil
189
+ end
190
+ end
191
+
192
+ specify "should correctly rollback transactions" do
193
+ proc do
194
+ FIREBIRD_DB.transaction do
195
+ @d << {:name => 'abc', :val => 1}
196
+ raise RuntimeError, 'asdf'
197
+ end
198
+ end.should raise_error(RuntimeError)
199
+
200
+ @d.count.should == 0
201
+ end
202
+
203
+ specify "should handle returning inside of the block by committing" do
204
+ def FIREBIRD_DB.ret_commit
205
+ transaction do
206
+ self[:test] << {:name => 'abc'}
207
+ return
208
+ self[:test] << {:name => 'd'}
209
+ end
210
+ end
211
+ @d.count.should == 0
212
+ FIREBIRD_DB.ret_commit
213
+ @d.count.should == 1
214
+ FIREBIRD_DB.ret_commit
215
+ @d.count.should == 2
216
+ proc do
217
+ FIREBIRD_DB.transaction do
218
+ raise RuntimeError, 'asdf'
219
+ end
220
+ end.should raise_error(RuntimeError)
221
+
222
+ @d.count.should == 2
223
+ end
224
+
225
+ specify "should quote and upcase reserved keywords" do
226
+ @d = FIREBIRD_DB[:testing]
227
+ @d.quote_identifiers = true
228
+ @d.select(:select).sql.should == \
229
+ 'SELECT "SELECT" FROM "TESTING"'
230
+ end
231
+ end
232
+
233
+ context "A Firebird dataset with a timestamp field" do
234
+ before do
235
+ @d = FIREBIRD_DB[:test3]
236
+ @d.delete
237
+ end
238
+
239
+ specify "should store milliseconds in time fields" do
240
+ t = Time.now
241
+ @d << {:val=>1, :time_stamp=>t}
242
+ @d.literal(@d[:val =>'1'][:time_stamp]).should == @d.literal(t)
243
+ @d[:val=>'1'][:time_stamp].usec.should == t.usec - t.usec % 100
244
+ end
245
+ end
246
+
247
+ context "A Firebird database" do
248
+ before do
249
+ @db = FIREBIRD_DB
250
+ @db.drop_table(:posts) rescue nil
251
+ @db.sqls.clear
252
+ end
253
+
254
+ specify "should allow us to name the sequences" do
255
+ @db.create_table(:posts){primary_key :id, :sequence_name => "seq_test"}
256
+ @db.sqls.should == [
257
+ "DROP SEQUENCE SEQ_TEST",
258
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
259
+ "CREATE SEQUENCE SEQ_TEST",
260
+ " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_test;\n end\n end\n\n"
261
+ ]
262
+ end
263
+
264
+ specify "should allow us to set the starting position for the sequences" do
265
+ @db.create_table(:posts){primary_key :id, :sequence_start_position => 999}
266
+ @db.sqls.should == [
267
+ "DROP SEQUENCE SEQ_POSTS_ID",
268
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
269
+ "CREATE SEQUENCE SEQ_POSTS_ID",
270
+ "ALTER SEQUENCE SEQ_POSTS_ID RESTART WITH 999",
271
+ " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
272
+ ]
273
+ end
274
+
275
+ specify "should allow us to name and set the starting position for the sequences" do
276
+ @db.create_table(:posts){primary_key :id, :sequence_name => "seq_test", :sequence_start_position => 999}
277
+ @db.sqls.should == [
278
+ "DROP SEQUENCE SEQ_TEST",
279
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
280
+ "CREATE SEQUENCE SEQ_TEST",
281
+ "ALTER SEQUENCE SEQ_TEST RESTART WITH 999",
282
+ " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_test;\n end\n end\n\n"
283
+ ]
284
+ end
285
+
286
+ specify "should allow us to name the triggers" do
287
+ @db.create_table(:posts){primary_key :id, :trigger_name => "trig_test"}
288
+ @db.sqls.should == [
289
+ "DROP SEQUENCE SEQ_POSTS_ID",
290
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
291
+ "CREATE SEQUENCE SEQ_POSTS_ID",
292
+ " CREATE TRIGGER TRIG_TEST for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
293
+ ]
294
+ end
295
+
296
+ specify "should allow us to not create the sequence" do
297
+ @db.create_table(:posts){primary_key :id, :create_sequence => false}
298
+ @db.sqls.should == [
299
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
300
+ " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
301
+ ]
302
+ end
303
+
304
+ specify "should allow us to not create the trigger" do
305
+ @db.create_table(:posts){primary_key :id, :create_trigger => false}
306
+ @db.sqls.should == [
307
+ "DROP SEQUENCE SEQ_POSTS_ID",
308
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
309
+ "CREATE SEQUENCE SEQ_POSTS_ID",
310
+ ]
311
+ end
312
+
313
+ specify "should allow us to not create either the sequence nor the trigger" do
314
+ @db.create_table(:posts){primary_key :id, :create_sequence => false, :create_trigger => false}
315
+ @db.sqls.should == [
316
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )"
317
+ ]
318
+ end
319
+
320
+ specify "should support column operations" do
321
+ @db.create_table!(:test2){varchar :name, :size => 50; integer :val}
322
+ @db[:test2] << {}
323
+ @db[:test2].columns.should == [:name, :val]
324
+
325
+ @db.add_column :test2, :xyz, :varchar, :size => 50
326
+ @db[:test2].columns.should == [:name, :val, :xyz]
327
+
328
+ @db[:test2].columns.should == [:name, :val, :xyz]
329
+ @db.drop_column :test2, :xyz
330
+
331
+ @db[:test2].columns.should == [:name, :val]
332
+
333
+ @db[:test2].delete
334
+ @db.add_column :test2, :xyz, :varchar, :default => '000', :size => 50#, :create_domain => 'xyz_varchar'
335
+ @db[:test2] << {:name => 'mmm', :val => 111, :xyz => 'qqqq'}
336
+
337
+ @db[:test2].columns.should == [:name, :val, :xyz]
338
+ @db.rename_column :test2, :xyz, :zyx
339
+ @db[:test2].columns.should == [:name, :val, :zyx]
340
+ @db[:test2].first[:zyx].should == 'qqqq'
341
+
342
+ @db.add_column :test2, :xyz, :decimal, :elements => [12, 2]
343
+ @db[:test2].delete
344
+ @db[:test2] << {:name => 'mmm', :val => 111, :xyz => 56.4}
345
+ @db.set_column_type :test2, :xyz, :varchar, :size => 50
346
+
347
+ @db[:test2].first[:xyz].should == "56.40"
348
+ end
349
+
350
+ specify "should allow us to retrieve the primary key for a table" do
351
+ @db.create_table!(:test2){primary_key :id}
352
+ @db.primary_key(:test2).should == ["id"]
353
+ end
354
+ end
355
+
356
+ context "Postgres::Dataset#insert" do
357
+ before do
358
+ @ds = FIREBIRD_DB[:test5]
359
+ @ds.delete
360
+ end
361
+
362
+ specify "should using call insert_returning_sql" do
363
+ # @ds.should_receive(:single_value).once.with(:sql=>'INSERT INTO TEST5 (VAL) VALUES (10) RETURNING XID', :server=> :default)
364
+ @ds.should_receive(:single_value).once
365
+ @ds.insert(:val=>10)
366
+ end
367
+
368
+ specify "should have insert_returning_sql use the RETURNING keyword" do
369
+ @ds.insert_returning_sql(:XID, :val=>10).should == "INSERT INTO TEST5 (VAL) VALUES (10) RETURNING XID"
370
+ @ds.insert_returning_sql('*'.lit, :val=>10).should == "INSERT INTO TEST5 (VAL) VALUES (10) RETURNING *"
371
+ @ds.insert_returning_sql('NULL'.lit, :val=>10).should == "INSERT INTO TEST5 (VAL) VALUES (10) RETURNING NULL"
372
+ end
373
+
374
+ specify "should correctly return the inserted record's primary key value" do
375
+ value1 = 10
376
+ id1 = @ds.insert(:val=>value1)
377
+ @ds.first(:XID=>id1)[:val].should == value1
378
+ value2 = 20
379
+ id2 = @ds.insert(:val=>value2)
380
+ @ds.first(:XID=>id2)[:val].should == value2
381
+ end
382
+
383
+ specify "should return nil if the table has no primary key" do
384
+ ds = FIREBIRD_DB[:test]
385
+ ds.delete
386
+ ds.insert(:name=>'a').should == nil
387
+ end
388
+ end
389
+
390
+ context "Postgres::Dataset#insert" do
391
+ before do
392
+ @ds = FIREBIRD_DB[:test6]
393
+ @ds.delete
394
+ end
395
+
396
+ specify "should insert and retrieve a blob successfully" do
397
+ value1 = "\1\2\2\2\2222\2\2\2"
398
+ value2 = "abcd"
399
+ value3 = "efgh"
400
+ value4 = "ijkl"
401
+ id1 = @ds.insert(:val=>value1, :val2=>value2, :val3=>value3, :val4=>value4)
402
+ @ds.first(:XID=>id1)[:val].should == value1
403
+ @ds.first(:XID=>id1)[:val2].should == value2
404
+ @ds.first(:XID=>id1)[:val3].should == value3
405
+ @ds.first(:XID=>id1)[:val4].should == value4
406
+ end
407
+ end