sequel 3.21.0 → 3.36.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 (311) hide show
  1. data/CHANGELOG +855 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +23 -7
  4. data/Rakefile +42 -24
  5. data/bin/sequel +26 -8
  6. data/doc/active_record.rdoc +1 -0
  7. data/doc/advanced_associations.rdoc +171 -11
  8. data/doc/association_basics.rdoc +293 -43
  9. data/doc/dataset_basics.rdoc +5 -5
  10. data/doc/dataset_filtering.rdoc +8 -0
  11. data/doc/mass_assignment.rdoc +56 -0
  12. data/doc/migration.rdoc +85 -552
  13. data/doc/model_hooks.rdoc +78 -27
  14. data/doc/object_model.rdoc +541 -0
  15. data/doc/opening_databases.rdoc +97 -50
  16. data/doc/prepared_statements.rdoc +40 -14
  17. data/doc/querying.rdoc +28 -4
  18. data/doc/reflection.rdoc +30 -4
  19. data/doc/release_notes/3.22.0.txt +39 -0
  20. data/doc/release_notes/3.23.0.txt +172 -0
  21. data/doc/release_notes/3.24.0.txt +420 -0
  22. data/doc/release_notes/3.25.0.txt +88 -0
  23. data/doc/release_notes/3.26.0.txt +88 -0
  24. data/doc/release_notes/3.27.0.txt +82 -0
  25. data/doc/release_notes/3.28.0.txt +304 -0
  26. data/doc/release_notes/3.29.0.txt +459 -0
  27. data/doc/release_notes/3.30.0.txt +135 -0
  28. data/doc/release_notes/3.31.0.txt +146 -0
  29. data/doc/release_notes/3.32.0.txt +202 -0
  30. data/doc/release_notes/3.33.0.txt +157 -0
  31. data/doc/release_notes/3.34.0.txt +671 -0
  32. data/doc/release_notes/3.35.0.txt +144 -0
  33. data/doc/release_notes/3.36.0.txt +245 -0
  34. data/doc/schema_modification.rdoc +572 -0
  35. data/doc/sharding.rdoc +95 -3
  36. data/doc/testing.rdoc +129 -0
  37. data/doc/thread_safety.rdoc +17 -0
  38. data/doc/transactions.rdoc +137 -0
  39. data/doc/virtual_rows.rdoc +51 -2
  40. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  41. data/lib/sequel/adapters/ado.rb +40 -18
  42. data/lib/sequel/adapters/amalgalite.rb +17 -9
  43. data/lib/sequel/adapters/db2.rb +175 -86
  44. data/lib/sequel/adapters/dbi.rb +15 -15
  45. data/lib/sequel/adapters/do/mysql.rb +17 -11
  46. data/lib/sequel/adapters/do/postgres.rb +1 -57
  47. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  48. data/lib/sequel/adapters/do.rb +18 -36
  49. data/lib/sequel/adapters/firebird.rb +27 -208
  50. data/lib/sequel/adapters/ibmdb.rb +453 -0
  51. data/lib/sequel/adapters/informix.rb +6 -23
  52. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  53. data/lib/sequel/adapters/jdbc/db2.rb +47 -0
  54. data/lib/sequel/adapters/jdbc/derby.rb +287 -0
  55. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  56. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  57. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  58. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  59. data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  61. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  62. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
  64. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  65. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  66. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  67. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  68. data/lib/sequel/adapters/jdbc.rb +265 -94
  69. data/lib/sequel/adapters/mock.rb +361 -0
  70. data/lib/sequel/adapters/mysql.rb +118 -222
  71. data/lib/sequel/adapters/mysql2.rb +58 -57
  72. data/lib/sequel/adapters/odbc/mssql.rb +15 -7
  73. data/lib/sequel/adapters/odbc.rb +28 -9
  74. data/lib/sequel/adapters/openbase.rb +3 -5
  75. data/lib/sequel/adapters/oracle.rb +349 -53
  76. data/lib/sequel/adapters/postgres.rb +356 -107
  77. data/lib/sequel/adapters/shared/access.rb +32 -9
  78. data/lib/sequel/adapters/shared/db2.rb +342 -0
  79. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  80. data/lib/sequel/adapters/shared/informix.rb +53 -0
  81. data/lib/sequel/adapters/shared/mssql.rb +335 -118
  82. data/lib/sequel/adapters/shared/mysql.rb +340 -76
  83. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  84. data/lib/sequel/adapters/shared/oracle.rb +243 -45
  85. data/lib/sequel/adapters/shared/postgres.rb +524 -279
  86. data/lib/sequel/adapters/shared/progress.rb +5 -8
  87. data/lib/sequel/adapters/shared/sqlite.rb +265 -89
  88. data/lib/sequel/adapters/sqlite.rb +101 -39
  89. data/lib/sequel/adapters/swift/mysql.rb +9 -12
  90. data/lib/sequel/adapters/swift/postgres.rb +9 -74
  91. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  92. data/lib/sequel/adapters/swift.rb +8 -7
  93. data/lib/sequel/adapters/tinytds.rb +161 -21
  94. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  95. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  96. data/lib/sequel/ast_transformer.rb +194 -0
  97. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  98. data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
  99. data/lib/sequel/connection_pool/single.rb +5 -0
  100. data/lib/sequel/connection_pool/threaded.rb +38 -14
  101. data/lib/sequel/connection_pool.rb +10 -2
  102. data/lib/sequel/core.rb +118 -11
  103. data/lib/sequel/database/connecting.rb +38 -28
  104. data/lib/sequel/database/dataset.rb +4 -4
  105. data/lib/sequel/database/dataset_defaults.rb +63 -2
  106. data/lib/sequel/database/logging.rb +7 -2
  107. data/lib/sequel/database/misc.rb +150 -46
  108. data/lib/sequel/database/query.rb +215 -65
  109. data/lib/sequel/database/schema_generator.rb +64 -20
  110. data/lib/sequel/database/schema_methods.rb +212 -54
  111. data/lib/sequel/dataset/actions.rb +322 -85
  112. data/lib/sequel/dataset/features.rb +96 -8
  113. data/lib/sequel/dataset/graph.rb +38 -11
  114. data/lib/sequel/dataset/misc.rb +50 -23
  115. data/lib/sequel/dataset/mutation.rb +12 -7
  116. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  117. data/lib/sequel/dataset/query.rb +237 -44
  118. data/lib/sequel/dataset/sql.rb +698 -278
  119. data/lib/sequel/dataset.rb +8 -0
  120. data/lib/sequel/exceptions.rb +4 -0
  121. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  122. data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
  123. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  124. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
  125. data/lib/sequel/extensions/migration.rb +97 -11
  126. data/lib/sequel/extensions/named_timezones.rb +5 -0
  127. data/lib/sequel/extensions/null_dataset.rb +90 -0
  128. data/lib/sequel/extensions/pg_array.rb +460 -0
  129. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  130. data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
  131. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  132. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  133. data/lib/sequel/extensions/pg_inet.rb +89 -0
  134. data/lib/sequel/extensions/pg_json.rb +178 -0
  135. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  136. data/lib/sequel/extensions/pretty_table.rb +5 -71
  137. data/lib/sequel/extensions/query.rb +1 -1
  138. data/lib/sequel/extensions/query_literals.rb +79 -0
  139. data/lib/sequel/extensions/schema_caching.rb +76 -0
  140. data/lib/sequel/extensions/schema_dumper.rb +251 -37
  141. data/lib/sequel/extensions/select_remove.rb +35 -0
  142. data/lib/sequel/extensions/server_block.rb +139 -0
  143. data/lib/sequel/extensions/sql_expr.rb +4 -110
  144. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  145. data/lib/sequel/extensions/to_dot.rb +95 -83
  146. data/lib/sequel/model/associations.rb +1187 -393
  147. data/lib/sequel/model/base.rb +578 -170
  148. data/lib/sequel/model/errors.rb +1 -1
  149. data/lib/sequel/model/exceptions.rb +5 -1
  150. data/lib/sequel/model/inflections.rb +1 -1
  151. data/lib/sequel/model.rb +30 -11
  152. data/lib/sequel/no_core_ext.rb +2 -0
  153. data/lib/sequel/plugins/active_model.rb +13 -1
  154. data/lib/sequel/plugins/association_pks.rb +22 -4
  155. data/lib/sequel/plugins/caching.rb +25 -18
  156. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  157. data/lib/sequel/plugins/composition.rb +44 -12
  158. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  159. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  160. data/lib/sequel/plugins/dirty.rb +214 -0
  161. data/lib/sequel/plugins/eager_each.rb +59 -0
  162. data/lib/sequel/plugins/force_encoding.rb +6 -6
  163. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  164. data/lib/sequel/plugins/identity_map.rb +123 -8
  165. data/lib/sequel/plugins/instance_filters.rb +10 -0
  166. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  167. data/lib/sequel/plugins/json_serializer.rb +58 -6
  168. data/lib/sequel/plugins/list.rb +12 -2
  169. data/lib/sequel/plugins/many_through_many.rb +79 -28
  170. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  171. data/lib/sequel/plugins/nested_attributes.rb +139 -63
  172. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  173. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  174. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  175. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  176. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  177. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  178. data/lib/sequel/plugins/schema.rb +7 -2
  179. data/lib/sequel/plugins/serialization.rb +98 -49
  180. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  181. data/lib/sequel/plugins/sharding.rb +21 -54
  182. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  183. data/lib/sequel/plugins/static_cache.rb +99 -0
  184. data/lib/sequel/plugins/subclasses.rb +10 -2
  185. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  186. data/lib/sequel/plugins/timestamps.rb +1 -1
  187. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  188. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  189. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  190. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  191. data/lib/sequel/sql.rb +526 -59
  192. data/lib/sequel/timezones.rb +57 -38
  193. data/lib/sequel/version.rb +1 -1
  194. data/spec/adapters/db2_spec.rb +146 -0
  195. data/spec/adapters/firebird_spec.rb +1 -1
  196. data/spec/adapters/mssql_spec.rb +142 -40
  197. data/spec/adapters/mysql_spec.rb +380 -234
  198. data/spec/adapters/oracle_spec.rb +67 -77
  199. data/spec/adapters/postgres_spec.rb +1050 -212
  200. data/spec/adapters/spec_helper.rb +8 -5
  201. data/spec/adapters/sqlite_spec.rb +139 -27
  202. data/spec/core/connection_pool_spec.rb +196 -93
  203. data/spec/core/database_spec.rb +879 -510
  204. data/spec/core/dataset_spec.rb +1415 -1086
  205. data/spec/core/expression_filters_spec.rb +554 -109
  206. data/spec/core/mock_adapter_spec.rb +449 -0
  207. data/spec/core/object_graph_spec.rb +86 -114
  208. data/spec/core/schema_generator_spec.rb +4 -4
  209. data/spec/core/schema_spec.rb +482 -38
  210. data/spec/core/spec_helper.rb +6 -48
  211. data/spec/extensions/active_model_spec.rb +13 -0
  212. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  213. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  214. data/spec/extensions/association_dependencies_spec.rb +15 -25
  215. data/spec/extensions/association_pks_spec.rb +66 -32
  216. data/spec/extensions/association_proxies_spec.rb +4 -4
  217. data/spec/extensions/caching_spec.rb +47 -51
  218. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  219. data/spec/extensions/columns_introspection_spec.rb +91 -0
  220. data/spec/extensions/composition_spec.rb +18 -13
  221. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
  222. data/spec/extensions/dataset_associations_spec.rb +199 -0
  223. data/spec/extensions/defaults_setter_spec.rb +64 -0
  224. data/spec/extensions/dirty_spec.rb +155 -0
  225. data/spec/extensions/eager_each_spec.rb +34 -0
  226. data/spec/extensions/force_encoding_spec.rb +4 -2
  227. data/spec/extensions/hook_class_methods_spec.rb +69 -92
  228. data/spec/extensions/identity_map_spec.rb +131 -22
  229. data/spec/extensions/inflector_spec.rb +0 -4
  230. data/spec/extensions/instance_filters_spec.rb +11 -21
  231. data/spec/extensions/instance_hooks_spec.rb +72 -0
  232. data/spec/extensions/json_serializer_spec.rb +49 -6
  233. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  234. data/spec/extensions/list_spec.rb +48 -39
  235. data/spec/extensions/many_through_many_spec.rb +283 -250
  236. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  237. data/spec/extensions/migration_spec.rb +140 -35
  238. data/spec/extensions/named_timezones_spec.rb +29 -11
  239. data/spec/extensions/nested_attributes_spec.rb +251 -89
  240. data/spec/extensions/null_dataset_spec.rb +85 -0
  241. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  242. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  243. data/spec/extensions/pg_array_spec.rb +196 -0
  244. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  245. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  246. data/spec/extensions/pg_hstore_spec.rb +195 -0
  247. data/spec/extensions/pg_inet_spec.rb +44 -0
  248. data/spec/extensions/pg_json_spec.rb +101 -0
  249. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  250. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  251. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  252. data/spec/extensions/prepared_statements_spec.rb +87 -0
  253. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  254. data/spec/extensions/pretty_table_spec.rb +7 -6
  255. data/spec/extensions/query_literals_spec.rb +168 -0
  256. data/spec/extensions/query_spec.rb +6 -0
  257. data/spec/extensions/rcte_tree_spec.rb +50 -43
  258. data/spec/extensions/schema_caching_spec.rb +41 -0
  259. data/spec/extensions/schema_dumper_spec.rb +429 -22
  260. data/spec/extensions/schema_spec.rb +25 -21
  261. data/spec/extensions/select_remove_spec.rb +38 -0
  262. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  263. data/spec/extensions/serialization_spec.rb +85 -43
  264. data/spec/extensions/server_block_spec.rb +90 -0
  265. data/spec/extensions/sharding_spec.rb +69 -143
  266. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  267. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  268. data/spec/extensions/spec_helper.rb +22 -61
  269. data/spec/extensions/sql_expr_spec.rb +29 -60
  270. data/spec/extensions/static_cache_spec.rb +145 -0
  271. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  272. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  273. data/spec/extensions/timestamps_spec.rb +6 -6
  274. data/spec/extensions/to_dot_spec.rb +4 -7
  275. data/spec/extensions/touch_spec.rb +13 -14
  276. data/spec/extensions/tree_spec.rb +11 -26
  277. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  278. data/spec/extensions/update_primary_key_spec.rb +30 -24
  279. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  280. data/spec/extensions/validation_helpers_spec.rb +16 -35
  281. data/spec/extensions/xml_serializer_spec.rb +29 -4
  282. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  283. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  284. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  285. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  286. data/spec/integration/associations_test.rb +659 -21
  287. data/spec/integration/database_test.rb +9 -3
  288. data/spec/integration/dataset_test.rb +605 -91
  289. data/spec/integration/eager_loader_test.rb +19 -21
  290. data/spec/integration/migrator_test.rb +2 -3
  291. data/spec/integration/model_test.rb +81 -2
  292. data/spec/integration/plugin_test.rb +454 -143
  293. data/spec/integration/prepared_statement_test.rb +263 -128
  294. data/spec/integration/schema_test.rb +309 -43
  295. data/spec/integration/spec_helper.rb +40 -30
  296. data/spec/integration/timezone_test.rb +38 -12
  297. data/spec/integration/transaction_test.rb +183 -8
  298. data/spec/integration/type_test.rb +18 -4
  299. data/spec/model/association_reflection_spec.rb +201 -7
  300. data/spec/model/associations_spec.rb +1067 -661
  301. data/spec/model/base_spec.rb +329 -95
  302. data/spec/model/dataset_methods_spec.rb +7 -27
  303. data/spec/model/eager_loading_spec.rb +677 -676
  304. data/spec/model/hooks_spec.rb +349 -67
  305. data/spec/model/model_spec.rb +240 -168
  306. data/spec/model/plugins_spec.rb +24 -13
  307. data/spec/model/record_spec.rb +490 -232
  308. data/spec/model/spec_helper.rb +14 -71
  309. data/spec/model/validations_spec.rb +11 -0
  310. data/spec/rcov.opts +2 -0
  311. metadata +178 -80
@@ -39,6 +39,48 @@ module Sequel
39
39
  convert_output_timestamp(v, Sequel.database_timezone)
40
40
  end
41
41
 
42
+ # Converts the object to the given +output_timezone+.
43
+ def convert_output_timestamp(v, output_timezone)
44
+ if output_timezone
45
+ if v.is_a?(DateTime)
46
+ case output_timezone
47
+ when :utc
48
+ v.new_offset(0)
49
+ when :local
50
+ v.new_offset(local_offset_for_datetime(v))
51
+ else
52
+ convert_output_datetime_other(v, output_timezone)
53
+ end
54
+ else
55
+ v.send(output_timezone == :utc ? :getutc : :getlocal)
56
+ end
57
+ else
58
+ v
59
+ end
60
+ end
61
+
62
+ # Converts the given object from the given input timezone to the
63
+ # +application_timezone+ using +convert_input_timestamp+ and
64
+ # +convert_output_timestamp+.
65
+ def convert_timestamp(v, input_timezone)
66
+ begin
67
+ if v.is_a?(Date) && !v.is_a?(DateTime)
68
+ # Dates handled specially as they are assumed to already be in the application_timezone
69
+ if datetime_class == DateTime
70
+ DateTime.civil(v.year, v.month, v.day, 0, 0, 0, application_timezone == :local ? (defined?(Rational) ? Rational(Time.local(v.year, v.month, v.day).utc_offset, 86400) : Time.local(v.year, v.month, v.day).utc_offset/86400.0) : 0)
71
+ else
72
+ Time.send(application_timezone == :utc ? :utc : :local, v.year, v.month, v.day)
73
+ end
74
+ else
75
+ convert_output_timestamp(convert_input_timestamp(v, input_timezone), application_timezone)
76
+ end
77
+ rescue InvalidValue
78
+ raise
79
+ rescue => e
80
+ raise convert_exception_class(e, InvalidValue)
81
+ end
82
+ end
83
+
42
84
  # Convert the given object into an object of <tt>Sequel.datetime_class</tt> in the
43
85
  # +application_timezone+. Used when coverting datetime/timestamp columns
44
86
  # returned by the database.
@@ -103,12 +145,24 @@ module Sequel
103
145
  v2
104
146
  end
105
147
  when Array
106
- y, mo, d, h, mi, s = v
148
+ y, mo, d, h, mi, s, ns, off = v
107
149
  if datetime_class == DateTime
108
- convert_input_datetime_no_offset(DateTime.civil(y, mo, d, h, mi, s, 0), input_timezone)
150
+ s += (defined?(Rational) ? Rational(ns, 1000000000) : ns/1000000000.0) if ns
151
+ if off
152
+ DateTime.civil(y, mo, d, h, mi, s, off)
153
+ else
154
+ convert_input_datetime_no_offset(DateTime.civil(y, mo, d, h, mi, s), input_timezone)
155
+ end
109
156
  else
110
- Time.send(input_timezone == :utc ? :utc : :local, y, mo, d, h, mi, s)
157
+ Time.send(input_timezone == :utc ? :utc : :local, y, mo, d, h, mi, s, (ns ? ns / 1000.0 : 0))
158
+ end
159
+ when Hash
160
+ ary = [:year, :month, :day, :hour, :minute, :second, :nanos].map{|x| (v[x] || v[x.to_s]).to_i}
161
+ if (offset = (v[:offset] || v['offset']))
162
+ ary << offset
111
163
  end
164
+ convert_input_timestamp(ary, input_timezone)
165
+ convert_input_timestamp(ary, input_timezone)
112
166
  when Time
113
167
  if datetime_class == DateTime
114
168
  v.respond_to?(:to_datetime) ? v.to_datetime : string_to_datetime(v.iso8601)
@@ -121,8 +175,6 @@ module Sequel
121
175
  else
122
176
  v.respond_to?(:to_time) ? v.to_time : string_to_datetime(v.to_s)
123
177
  end
124
- when Date
125
- convert_input_timestamp(v.to_s, input_timezone)
126
178
  else
127
179
  raise InvalidValue, "Invalid convert_input_timestamp type: #{v.inspect}"
128
180
  end
@@ -135,39 +187,6 @@ module Sequel
135
187
  raise InvalidValue, "Invalid output_timezone: #{output_timezone.inspect}"
136
188
  end
137
189
 
138
- # Converts the object to the given +output_timezone+.
139
- def convert_output_timestamp(v, output_timezone)
140
- if output_timezone
141
- if v.is_a?(DateTime)
142
- case output_timezone
143
- when :utc
144
- v.new_offset(0)
145
- when :local
146
- v.new_offset(local_offset_for_datetime(v))
147
- else
148
- convert_output_datetime_other(v, output_timezone)
149
- end
150
- else
151
- v.send(output_timezone == :utc ? :getutc : :getlocal)
152
- end
153
- else
154
- v
155
- end
156
- end
157
-
158
- # Converts the given object from the given input timezone to the
159
- # +application_timezone+ using +convert_input_timestamp+ and
160
- # +convert_output_timestamp+.
161
- def convert_timestamp(v, input_timezone)
162
- begin
163
- convert_output_timestamp(convert_input_timestamp(v, input_timezone), Sequel.application_timezone)
164
- rescue InvalidValue
165
- raise
166
- rescue => e
167
- raise convert_exception_class(e, InvalidValue)
168
- end
169
- end
170
-
171
190
  # Convert the timezone setter argument. Returns argument given by default,
172
191
  # exists for easier overriding in extensions.
173
192
  def convert_timezone_setter_arg(tz)
@@ -3,7 +3,7 @@ module Sequel
3
3
  MAJOR = 3
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 21
6
+ MINOR = 36
7
7
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
8
8
  # releases that fix regressions from previous versions.
9
9
  TINY = 0
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+ #Author: Roy L Zuo (roylzuo at gmail dot com)
4
+ #Description:
5
+
6
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
7
+
8
+ require ENV['SEQUEL_DB2_SPEC_REQUIRE'] if ENV['SEQUEL_DB2_SPEC_REQUIRE']
9
+
10
+ unless defined?(DB2_DB)
11
+ DB2_DB = Sequel.connect(ENV['SEQUEL_DB2_SPEC_DB']||DB2_URL)
12
+ end
13
+
14
+ if DB2_DB.table_exists?(:test)
15
+ DB2_DB.drop_table :test
16
+ end
17
+ INTEGRATION_DB = DB2_DB unless defined?(INTEGRATION_DB)
18
+
19
+ describe Sequel::Database do
20
+ before do
21
+ @db = DB2_DB
22
+ @db.create_table(:test){String :a}
23
+ @ds = @db[:test]
24
+ end
25
+
26
+ after do
27
+ @db.drop_table(:test)
28
+ end
29
+
30
+ specify "should provide disconnect functionality after preparing a connection" do
31
+ @ds.prepare(:first, :a).call
32
+ @db.disconnect
33
+ @db.pool.size.should == 0
34
+ end
35
+
36
+ specify "should return version correctly" do
37
+ @db.db2_version.should match(/DB2 v/i)
38
+ end
39
+ end
40
+
41
+ describe "Simple Dataset operations" do
42
+ before do
43
+ DB2_DB.create_table!(:items) do
44
+ Integer :id, :primary_key => true
45
+ Integer :number
46
+ end
47
+ @ds = DB2_DB[:items]
48
+ @ds.insert(:number=>10, :id => 1 )
49
+ end
50
+ after do
51
+ DB2_DB.drop_table(:items)
52
+ end
53
+ cspecify "should insert with a primary key specified", :mssql do
54
+ @ds.insert(:id=>100, :number=>20)
55
+ @ds.count.should == 2
56
+ @ds.order(:id).all.should == [{:id=>1, :number=>10}, {:id=>100, :number=>20}]
57
+ end
58
+ end
59
+
60
+ describe Sequel::Database do
61
+ before do
62
+ @db = DB2_DB
63
+ end
64
+ after do
65
+ @db.drop_table(:items)
66
+ end
67
+ specify "should parse primary keys from the schema properly" do
68
+ @db.create_table!(:items){Integer :number}
69
+ @db.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == []
70
+ @db.create_table!(:items){primary_key :number}
71
+ @db.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == [:number]
72
+ @db.create_table!(:items){Integer :number1, :null => false; Integer :number2, :null => false; primary_key [:number1, :number2]}
73
+ @db.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == [:number1, :number2]
74
+ end
75
+ end
76
+
77
+ describe "Sequel::IBMDB.convert_smallint_to_bool" do
78
+ before do
79
+ @db = DB2_DB
80
+ @db.create_table!(:booltest){column :b, 'smallint'; column :i, 'integer'}
81
+ @ds = @db[:booltest]
82
+ end
83
+ after do
84
+ Sequel::IBMDB.convert_smallint_to_bool = true
85
+ @db.drop_table(:booltest)
86
+ end
87
+
88
+ specify "should consider smallint datatypes as boolean if set, but not larger smallints" do
89
+ @db.schema(:booltest, :reload=>true).first.last[:type].should == :boolean
90
+ @db.schema(:booltest, :reload=>true).first.last[:db_type].should match /smallint/i
91
+ Sequel::IBMDB.convert_smallint_to_bool = false
92
+ @db.schema(:booltest, :reload=>true).first.last[:type].should == :integer
93
+ @db.schema(:booltest, :reload=>true).first.last[:db_type].should match /smallint/i
94
+ end
95
+
96
+ specify "should return smallints as bools and integers as integers when set" do
97
+ Sequel::IBMDB.convert_smallint_to_bool = true
98
+ @ds.delete
99
+ @ds << {:b=>true, :i=>10}
100
+ @ds.all.should == [{:b=>true, :i=>10}]
101
+ @ds.delete
102
+ @ds << {:b=>false, :i=>0}
103
+ @ds.all.should == [{:b=>false, :i=>0}]
104
+ @ds.delete
105
+ @ds << {:b=>true, :i=>1}
106
+ @ds.all.should == [{:b=>true, :i=>1}]
107
+ end
108
+
109
+ specify "should return all smallints as integers when unset" do
110
+ Sequel::IBMDB.convert_smallint_to_bool = false
111
+ @ds.delete
112
+ @ds << {:b=>true, :i=>10}
113
+ @ds.all.should == [{:b=>1, :i=>10}]
114
+ @ds.delete
115
+ @ds << {:b=>false, :i=>0}
116
+ @ds.all.should == [{:b=>0, :i=>0}]
117
+
118
+ @ds.delete
119
+ @ds << {:b=>1, :i=>10}
120
+ @ds.all.should == [{:b=>1, :i=>10}]
121
+ @ds.delete
122
+ @ds << {:b=>0, :i=>0}
123
+ @ds.all.should == [{:b=>0, :i=>0}]
124
+ end
125
+ end if DB2_DB.adapter_scheme == :ibmdb
126
+
127
+ describe "Simple Dataset operations in transactions" do
128
+ before do
129
+ DB2_DB.create_table!(:items_insert_in_transaction) do
130
+ Integer :id, :primary_key => true
131
+ integer :number
132
+ end
133
+ @ds = DB2_DB[:items_insert_in_transaction]
134
+ end
135
+ after do
136
+ DB2_DB.drop_table(:items_insert_in_transaction)
137
+ end
138
+
139
+ specify "should insert correctly with a primary key specified inside a transaction" do
140
+ DB2_DB.transaction do
141
+ @ds.insert(:id=>100, :number=>20)
142
+ @ds.count.should == 1
143
+ @ds.order(:id).all.should == [{:id=>100, :number=>20}]
144
+ end
145
+ end
146
+ end
@@ -247,7 +247,7 @@ end
247
247
  describe "A Firebird database" do
248
248
  before do
249
249
  @db = FIREBIRD_DB
250
- @db.drop_table(:posts) rescue nil
250
+ @db.drop_table?(:posts)
251
251
  @db.sqls.clear
252
252
  end
253
253
 
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
3
 
3
4
  require ENV['SEQUEL_MSSQL_SPEC_REQUIRE'] if ENV['SEQUEL_MSSQL_SPEC_REQUIRE']
@@ -59,15 +60,44 @@ describe "A MSSQL database" do
59
60
  end
60
61
  end
61
62
 
63
+ # This spec is currently disabled as the SQL Server 2008 R2 Express doesn't support
64
+ # full text searching. Even if full text searching is supported,
65
+ # you may need to create a full text catalog on the database first via:
66
+ # CREATE FULLTEXT CATALOG ftscd AS DEFAULT
67
+ describe "MSSQL full_text_search" do
68
+ before do
69
+ @db = MSSQL_DB
70
+ @db.drop_table?(:posts)
71
+ end
72
+ after do
73
+ @db.drop_table?(:posts)
74
+ end
75
+
76
+ specify "should support fulltext indexes and full_text_search" do
77
+ log do
78
+ @db.create_table(:posts){Integer :id, :null=>false; String :title; String :body; index :id, :name=>:fts_id_idx, :unique=>true; full_text_index :title, :key_index=>:fts_id_idx; full_text_index [:title, :body], :key_index=>:fts_id_idx}
79
+ @db[:posts].insert(:title=>'ruby rails', :body=>'y')
80
+ @db[:posts].insert(:title=>'sequel', :body=>'ruby')
81
+ @db[:posts].insert(:title=>'ruby scooby', :body=>'x')
82
+
83
+ @db[:posts].full_text_search(:title, 'rails').all.should == [{:title=>'ruby rails', :body=>'y'}]
84
+ @db[:posts].full_text_search([:title, :body], ['sequel', 'ruby']).all.should == [{:title=>'sequel', :body=>'ruby'}]
85
+
86
+ @db[:posts].full_text_search(:title, :$n).call(:select, :n=>'rails').should == [{:title=>'ruby rails', :body=>'y'}]
87
+ @db[:posts].full_text_search(:title, :$n).prepare(:select, :fts_select).call(:n=>'rails').should == [{:title=>'ruby rails', :body=>'y'}]
88
+ end
89
+ end
90
+ end if false
91
+
62
92
  describe "MSSQL Dataset#join_table" do
63
93
  specify "should emulate the USING clause with ON" do
64
94
  MSSQL_DB[:items].join(:categories, [:id]).sql.should ==
65
- 'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON (CATEGORIES.ID = ITEMS.ID)'
66
- ['SELECT * FROM ITEMS INNER JOIN CATEGORIES ON ((CATEGORIES.ID1 = ITEMS.ID1) AND (CATEGORIES.ID2 = ITEMS.ID2))',
67
- 'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON ((CATEGORIES.ID2 = ITEMS.ID2) AND (CATEGORIES.ID1 = ITEMS.ID1))'].
68
- should include(MSSQL_DB[:items].join(:categories, [:id1, :id2]).sql)
95
+ 'SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON ([CATEGORIES].[ID] = [ITEMS].[ID])'
96
+ ['SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON (([CATEGORIES].[ID1] = [ITEMS].[ID1]) AND ([CATEGORIES].[ID2] = [ITEMS].[ID2]))',
97
+ 'SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON (([CATEGORIES].[ID2] = [ITEMS].[ID2]) AND ([CATEGORIES].[ID1] = [ITEMS].[ID1]))'].
98
+ should include(MSSQL_DB[:items].join(:categories, [:id1, :id2]).sql)
69
99
  MSSQL_DB[:items___i].join(:categories___c, [:id]).sql.should ==
70
- 'SELECT * FROM ITEMS AS I INNER JOIN CATEGORIES AS C ON (C.ID = I.ID)'
100
+ 'SELECT * FROM [ITEMS] AS [I] INNER JOIN [CATEGORIES] AS [C] ON ([C].[ID] = [I].[ID])'
71
101
  end
72
102
  end
73
103
 
@@ -79,50 +109,49 @@ describe "MSSQL Dataset#output" do
79
109
  @ds = @db[:items]
80
110
  end
81
111
  after do
82
- @db.drop_table(:items)
83
- @db.drop_table(:out)
112
+ @db.drop_table?(:items, :out)
84
113
  end
85
114
 
86
115
  specify "should format OUTPUT clauses without INTO for DELETE statements" do
87
116
  @ds.output(nil, [:deleted__name, :deleted__value]).delete_sql.should =~
88
- /DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE)/
117
+ /DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\]/
89
118
  @ds.output(nil, [:deleted.*]).delete_sql.should =~
90
- /DELETE FROM ITEMS OUTPUT DELETED.*/
119
+ /DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].*/
91
120
  end
92
121
 
93
122
  specify "should format OUTPUT clauses with INTO for DELETE statements" do
94
123
  @ds.output(:out, [:deleted__name, :deleted__value]).delete_sql.should =~
95
- /DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE) INTO OUT/
124
+ /DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\] INTO \[OUT\]/
96
125
  @ds.output(:out, {:name => :deleted__name, :value => :deleted__value}).delete_sql.should =~
97
- /DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\)/
126
+ /DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\)/
98
127
  end
99
128
 
100
129
  specify "should format OUTPUT clauses without INTO for INSERT statements" do
101
130
  @ds.output(nil, [:inserted__name, :inserted__value]).insert_sql(:name => "name", :value => 1).should =~
102
- /INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) VALUES \((N'name'|1), (N'name'|1)\)/
131
+ /INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] VALUES \((N'name'|1), (N'name'|1)\)/
103
132
  @ds.output(nil, [:inserted.*]).insert_sql(:name => "name", :value => 1).should =~
104
- /INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.* VALUES \((N'name'|1), (N'name'|1)\)/
133
+ /INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].* VALUES \((N'name'|1), (N'name'|1)\)/
105
134
  end
106
135
 
107
136
  specify "should format OUTPUT clauses with INTO for INSERT statements" do
108
137
  @ds.output(:out, [:inserted__name, :inserted__value]).insert_sql(:name => "name", :value => 1).should =~
109
- /INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) INTO OUT VALUES \((N'name'|1), (N'name'|1)\)/
138
+ /INSERT INTO \[ITEMS\] \((\[NAME\]|\[VALUE\]), (\[NAME\]|\[VALUE\])\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] INTO \[OUT\] VALUES \((N'name'|1), (N'name'|1)\)/
110
139
  @ds.output(:out, {:name => :inserted__name, :value => :inserted__value}).insert_sql(:name => "name", :value => 1).should =~
111
- /INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\) VALUES \((N'name'|1), (N'name'|1)\)/
140
+ /INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) VALUES \((N'name'|1), (N'name'|1)\)/
112
141
  end
113
142
 
114
143
  specify "should format OUTPUT clauses without INTO for UPDATE statements" do
115
144
  @ds.output(nil, [:inserted__name, :deleted__value]).update_sql(:value => 2).should =~
116
- /UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE)/
145
+ /UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\]/
117
146
  @ds.output(nil, [:inserted.*]).update_sql(:value => 2).should =~
118
- /UPDATE ITEMS SET VALUE = 2 OUTPUT INSERTED.*/
147
+ /UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[INSERTED\].*/
119
148
  end
120
149
 
121
150
  specify "should format OUTPUT clauses with INTO for UPDATE statements" do
122
151
  @ds.output(:out, [:inserted__name, :deleted__value]).update_sql(:value => 2).should =~
123
- /UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE) INTO OUT/
152
+ /UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\] INTO \[OUT\]/
124
153
  @ds.output(:out, {:name => :inserted__name, :value => :deleted__value}).update_sql(:value => 2).should =~
125
- /UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\)/
154
+ /UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\)/
126
155
  end
127
156
 
128
157
  specify "should execute OUTPUT clauses in DELETE statements" do
@@ -163,23 +192,23 @@ describe "MSSQL dataset" do
163
192
  end
164
193
 
165
194
  specify "should prepend UPDATE statements with WITH clause" do
166
- @ds1.update_sql(:x => :y).should == 'WITH T AS (SELECT * FROM X) UPDATE T SET X = Y'
167
- @ds2.update_sql(:x => :y).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) UPDATE T SET X = Y'
195
+ @ds1.update_sql(:x => :y).should == 'WITH [T] AS (SELECT * FROM [X]) UPDATE [T] SET [X] = [Y]'
196
+ @ds2.update_sql(:x => :y).should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) UPDATE [T] SET [X] = [Y]'
168
197
  end
169
198
 
170
199
  specify "should prepend DELETE statements with WITH clause" do
171
- @ds1.filter(:y => 1).delete_sql.should == 'WITH T AS (SELECT * FROM X) DELETE FROM T WHERE (Y = 1)'
172
- @ds2.filter(:y => 1).delete_sql.should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) DELETE FROM T WHERE (Y = 1)'
200
+ @ds1.filter(:y => 1).delete_sql.should == 'WITH [T] AS (SELECT * FROM [X]) DELETE FROM [T] WHERE ([Y] = 1)'
201
+ @ds2.filter(:y => 1).delete_sql.should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) DELETE FROM [T] WHERE ([Y] = 1)'
173
202
  end
174
203
 
175
204
  specify "should prepend INSERT statements with WITH clause" do
176
- @ds1.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X) INSERT INTO T SELECT * FROM T'
177
- @ds2.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) INSERT INTO T SELECT * FROM T'
205
+ @ds1.insert_sql(@db[:t]).should == 'WITH [T] AS (SELECT * FROM [X]) INSERT INTO [T] SELECT * FROM [T]'
206
+ @ds2.insert_sql(@db[:t]).should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) INSERT INTO [T] SELECT * FROM [T]'
178
207
  end
179
208
 
180
209
  specify "should move WITH clause on joined dataset to top level" do
181
- @db[:s].inner_join(@ds1).sql.should == "WITH T AS (SELECT * FROM X) SELECT * FROM S INNER JOIN (SELECT * FROM T) AS T1"
182
- @ds1.inner_join(@db[:s].with(:s, @db[:y])).sql.should == "WITH T AS (SELECT * FROM X), S AS (SELECT * FROM Y) SELECT * FROM T INNER JOIN (SELECT * FROM S) AS T1"
210
+ @db[:s].inner_join(@ds1).sql.should == "WITH [T] AS (SELECT * FROM [X]) SELECT * FROM [S] INNER JOIN (SELECT * FROM [T]) AS [T1]"
211
+ @ds1.inner_join(@db[:s].with(:s, @db[:y])).sql.should == "WITH [T] AS (SELECT * FROM [X]), [S] AS (SELECT * FROM [Y]) SELECT * FROM [T] INNER JOIN (SELECT * FROM [S]) AS [T1]"
183
212
  end
184
213
 
185
214
  describe "on #import" do
@@ -207,10 +236,10 @@ describe "MSSQL dataset" do
207
236
  @db[:items].with(:items, @db[:inventory].group(:type)).import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
208
237
  @db.import_sqls.should == [
209
238
  'BEGIN',
210
- "WITH ITEMS AS (SELECT * FROM INVENTORY GROUP BY TYPE) INSERT INTO ITEMS (X, Y) SELECT 1, 2 UNION ALL SELECT 3, 4",
239
+ "WITH [ITEMS] AS (SELECT * FROM [INVENTORY] GROUP BY [TYPE]) INSERT INTO [ITEMS] ([X], [Y]) SELECT 1, 2 UNION ALL SELECT 3, 4",
211
240
  'COMMIT',
212
241
  'BEGIN',
213
- "WITH ITEMS AS (SELECT * FROM INVENTORY GROUP BY TYPE) INSERT INTO ITEMS (X, Y) SELECT 5, 6",
242
+ "WITH [ITEMS] AS (SELECT * FROM [INVENTORY] GROUP BY [TYPE]) INSERT INTO [ITEMS] ([X], [Y]) SELECT 5, 6",
214
243
  'COMMIT'
215
244
  ]
216
245
  end
@@ -218,6 +247,23 @@ describe "MSSQL dataset" do
218
247
  end
219
248
  end
220
249
 
250
+ describe "MSSQL::Dataset#import" do
251
+ before do
252
+ @db = MSSQL_DB
253
+ @db.create_table!(:test){primary_key :x; Integer :y}
254
+ @db.sqls.clear
255
+ @ds = @db[:test]
256
+ end
257
+ after do
258
+ @db.drop_table?(:test)
259
+ end
260
+
261
+ specify "#import should work correctly with an arbitrary output value" do
262
+ @ds.output(nil, [:inserted__y, :inserted__x]).import([:y], [[3], [4]]).should == [{:y=>3, :x=>1}, {:y=>4, :x=>2}]
263
+ @ds.all.should == [{:x=>1, :y=>3}, {:x=>2, :y=>4}]
264
+ end
265
+ end
266
+
221
267
  describe "MSSQL joined datasets" do
222
268
  before do
223
269
  @db = MSSQL_DB
@@ -225,12 +271,12 @@ describe "MSSQL joined datasets" do
225
271
 
226
272
  specify "should format DELETE statements" do
227
273
  @db[:t1].inner_join(:t2, :t1__pk => :t2__pk).delete_sql.should ==
228
- "DELETE FROM T1 FROM T1 INNER JOIN T2 ON (T1.PK = T2.PK)"
274
+ "DELETE FROM [T1] FROM [T1] INNER JOIN [T2] ON ([T1].[PK] = [T2].[PK])"
229
275
  end
230
276
 
231
277
  specify "should format UPDATE statements" do
232
278
  @db[:t1].inner_join(:t2, :t1__pk => :t2__pk).update_sql(:pk => :t2__pk).should ==
233
- "UPDATE T1 SET PK = T2.PK FROM T1 INNER JOIN T2 ON (T1.PK = T2.PK)"
279
+ "UPDATE [T1] SET [PK] = [T2].[PK] FROM [T1] INNER JOIN [T2] ON ([T1].[PK] = [T2].[PK])"
234
280
  end
235
281
  end
236
282
 
@@ -244,7 +290,7 @@ describe "Offset support" do
244
290
  @ds.import [:id, :parent_id], [[1,nil],[2,nil],[3,1],[4,1],[5,3],[6,5]]
245
291
  end
246
292
  after do
247
- @db.drop_table(:i)
293
+ @db.drop_table?(:i)
248
294
  end
249
295
 
250
296
  specify "should return correct rows" do
@@ -267,8 +313,7 @@ describe "Common Table Expressions" do
267
313
  @ds.import [:id, :parent_id], [[1,nil],[2,nil],[3,1],[4,1],[5,3],[6,5]]
268
314
  end
269
315
  after do
270
- @db.drop_table(:i1)
271
- @db.drop_table(:i2)
316
+ @db.drop_table?(:i1, :i2)
272
317
  end
273
318
 
274
319
  specify "using #with should be able to update" do
@@ -338,7 +383,7 @@ describe "MSSSQL::Dataset#insert" do
338
383
  @ds = @db[:test5]
339
384
  end
340
385
  after do
341
- @db.drop_table(:test5) rescue nil
386
+ @db.drop_table?(:test5)
342
387
  end
343
388
 
344
389
  specify "should have insert_select return nil if disable_insert_output is used" do
@@ -369,7 +414,7 @@ describe "MSSSQL::Dataset#into" do
369
414
  end
370
415
 
371
416
  specify "should format SELECT statement" do
372
- @db[:t].into(:new).select_sql.should == "SELECT * INTO NEW FROM T"
417
+ @db[:t].into(:new).select_sql.should == "SELECT * INTO [NEW] FROM [T]"
373
418
  end
374
419
 
375
420
  specify "should select rows into a new table" do
@@ -377,8 +422,7 @@ describe "MSSSQL::Dataset#into" do
377
422
  @db[:t].insert(:id => 1, :value => "test")
378
423
  @db << @db[:t].into(:new).select_sql
379
424
  @db[:new].all.should == [{:id => 1, :value => "test"}]
380
- @db.drop_table(:t)
381
- @db.drop_table(:new)
425
+ @db.drop_table?(:t, :new)
382
426
  end
383
427
  end
384
428
 
@@ -387,7 +431,7 @@ describe "A MSSQL database" do
387
431
  @db = MSSQL_DB
388
432
  end
389
433
  after do
390
- @db.drop_table(:a)
434
+ @db.drop_table?(:a)
391
435
  end
392
436
 
393
437
  specify "should handle many existing types for set_column_allow_null" do
@@ -414,7 +458,7 @@ describe "MSSQL::Database#rename_table" do
414
458
  MSSQL_DB.create_table! :'foo bar' do
415
459
  text :name
416
460
  end
417
- MSSQL_DB.drop_table :baz rescue nil
461
+ MSSQL_DB.drop_table? :baz
418
462
  proc { MSSQL_DB.rename_table 'foo bar', 'baz' }.should_not raise_error
419
463
  end
420
464
 
@@ -440,3 +484,61 @@ describe "MSSQL::Dataset#count" do
440
484
  MSSQL_DB[:items].select(:name, :value).group(:name, :value).order(:name).count.should == 1
441
485
  end
442
486
  end
487
+
488
+ describe "MSSQL::Database#create_table" do
489
+ specify "should support collate with various other column options" do
490
+ MSSQL_DB.create_table!(:items){ String :name, :size => 128, :collate => :sql_latin1_general_cp1_ci_as, :default => 'foo', :null => false, :unique => true}
491
+ MSSQL_DB[:items].insert
492
+ MSSQL_DB[:items].select_map(:name).should == ["foo"]
493
+ end
494
+ end
495
+
496
+ describe "MSSQL::Database#mssql_unicode_strings = false" do
497
+ before do
498
+ MSSQL_DB.mssql_unicode_strings = false
499
+ end
500
+ after do
501
+ MSSQL_DB.drop_table?(:items)
502
+ MSSQL_DB.mssql_unicode_strings = true
503
+ end
504
+
505
+ specify "should work correctly" do
506
+ MSSQL_DB.create_table!(:items){String :name}
507
+ MSSQL_DB[:items].mssql_unicode_strings.should == false
508
+ MSSQL_DB[:items].insert(:name=>'foo')
509
+ MSSQL_DB[:items].select_map(:name).should == ['foo']
510
+ end
511
+
512
+ specify "should be overridable at the dataset level" do
513
+ MSSQL_DB.create_table!(:items){String :name}
514
+ ds = MSSQL_DB[:items]
515
+ ds.mssql_unicode_strings.should == false
516
+ ds.mssql_unicode_strings = true
517
+ ds.mssql_unicode_strings.should == true
518
+ ds.insert(:name=>'foo')
519
+ ds.select_map(:name).should == ['foo']
520
+ end
521
+ end
522
+
523
+ describe "A MSSQL database adds index with include" do
524
+ before :all do
525
+ @table_name = :test_index_include
526
+ @db = MSSQL_DB
527
+ @db.create_table! @table_name do
528
+ integer :col1
529
+ integer :col2
530
+ integer :col3
531
+ end
532
+ end
533
+
534
+ after :all do
535
+ @db.drop_table? @table_name
536
+ end
537
+
538
+ cspecify "should be able add index with include" do
539
+ @db.alter_table @table_name do
540
+ add_index [:col1], :include => [:col2,:col3]
541
+ end
542
+ @db.indexes(@table_name).should have_key("#{@table_name}_col1_index".to_sym)
543
+ end
544
+ end