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
@@ -0,0 +1,85 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "null_dataset extension" do
4
+ before do
5
+ @db = Sequel::mock(:fetch=>{:id=>1}, :autoid=>1, :numrows=>1, :columns=>[:id])
6
+ @ds = @db[:table].nullify
7
+ @i = 0
8
+ @pr = proc{|*a| @i += 1}
9
+ end
10
+ after do
11
+ @db.sqls.should == [] unless @skip_check
12
+ end
13
+
14
+ it "should make each be a noop" do
15
+ @ds.each(&@pr).should equal(@ds)
16
+ @i.should == 0
17
+ end
18
+
19
+ it "should make fetch_rows be a noop" do
20
+ @ds.fetch_rows("SELECT 1", &@pr).should == nil
21
+ @i.should == 0
22
+ end
23
+
24
+ it "should make insert be a noop" do
25
+ @ds.insert(1).should == nil
26
+ end
27
+
28
+ it "should make update be a noop" do
29
+ @ds.update(:a=>1).should == 0
30
+ end
31
+
32
+ it "should make delete be a noop" do
33
+ @ds.delete.should == 0
34
+ end
35
+
36
+ it "should make truncate be a noop" do
37
+ @ds.truncate.should == nil
38
+ end
39
+
40
+ it "should make execute_* be a noop" do
41
+ @ds.send(:execute_ddl,'FOO').should == nil
42
+ @ds.send(:execute_insert,'FOO').should == nil
43
+ @ds.send(:execute_dui,'FOO').should == nil
44
+ @ds.send(:execute,'FOO').should == nil
45
+ end
46
+
47
+ it "should have working columns" do
48
+ @skip_check = true
49
+ @ds.columns.should == [:id]
50
+ @db.sqls.should == ['SELECT * FROM table LIMIT 1']
51
+ end
52
+
53
+ it "should have count return 0" do
54
+ @ds.count.should == 0
55
+ end
56
+
57
+ it "should have empty return true" do
58
+ @ds.empty?.should == true
59
+ end
60
+
61
+ it "should make import a noop" do
62
+ @ds.import([:id], [[1], [2], [3]]).should == nil
63
+ end
64
+
65
+ it "should have nullify method returned modified receiver" do
66
+ @skip_check = true
67
+ ds = @db[:table]
68
+ ds.nullify.should_not equal(ds)
69
+ ds.each(&@pr)
70
+ @db.sqls.should == ['SELECT * FROM table']
71
+ @i.should == 1
72
+ end
73
+
74
+ it "should have null! method modify receiver" do
75
+ ds = @db[:table]
76
+ ds.nullify!.should equal(ds)
77
+ ds.each(&@pr)
78
+ @i.should == 0
79
+ end
80
+
81
+ it "should work with method chaining" do
82
+ @ds.where(:a=>1).select(:b).each(&@pr)
83
+ @i.should == 0
84
+ end
85
+ end
@@ -6,11 +6,8 @@ describe "optimistic_locking plugin" do
6
6
  end
7
7
  h = {1=>{:id=>1, :name=>'John', :lock_version=>2}}
8
8
  lv = @lv = "lock_version"
9
- @c.dataset.quote_identifiers = false
10
- @c.dataset.meta_def(:h){h}
11
- @c.dataset.meta_def(:lv){lv}
12
- @c.dataset.meta_def(:update) do |opts|
13
- case update_sql(opts)
9
+ @c.instance_dataset.numrows = @c.dataset.numrows = proc do |sql|
10
+ case sql
14
11
  when /UPDATE people SET (name|#{lv}) = ('Jim'|'Bob'|\d+), (?:name|#{lv}) = ('Jim'|'Bob'|\d+) WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
15
12
  name, nlv = $1 == 'name' ? [$2, $3] : [$3, $2]
16
13
  m = h[$4.to_i]
@@ -28,20 +25,6 @@ describe "optimistic_locking plugin" do
28
25
  else
29
26
  0
30
27
  end
31
- else
32
- puts update_sql(opts)
33
- end
34
- end
35
- @c.dataset.instance_eval do
36
- def fetch_rows(sql)
37
- m = h[1].dup
38
- v = m.delete(:lock_version)
39
- m[lv.to_sym] = v
40
- yield(m)
41
- end
42
- end
43
- @c.dataset.meta_def(:delete) do
44
- case delete_sql
45
28
  when /DELETE FROM people WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
46
29
  m = h[$1.to_i]
47
30
  if m && m[lv.to_sym] == $2.to_i
@@ -51,9 +34,15 @@ describe "optimistic_locking plugin" do
51
34
  0
52
35
  end
53
36
  else
54
- puts delete_sql
37
+ puts sql
55
38
  end
56
39
  end
40
+ @c.instance_dataset._fetch = @c.dataset._fetch = proc do |sql|
41
+ m = h[1].dup
42
+ v = m.delete(:lock_version)
43
+ m[lv.to_sym] = v
44
+ m
45
+ end
57
46
  @c.columns :id, :name, :lock_version
58
47
  @c.plugin :optimistic_locking
59
48
  end
@@ -106,6 +95,20 @@ describe "optimistic_locking plugin" do
106
95
  proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
107
96
  end
108
97
 
98
+ specify "should work correctly if attempting to refresh and save again after a failed save" do
99
+ p1 = @c[1]
100
+ p2 = @c[1]
101
+ p1.update(:name=>'Jim')
102
+ begin
103
+ p2.update(:name=>'Bob')
104
+ rescue Sequel::Plugins::OptimisticLocking::Error
105
+ p2.refresh
106
+ @c.db.sqls
107
+ proc{p2.update(:name=>'Bob')}.should_not raise_error
108
+ end
109
+ @c.db.sqls.first.should =~ /UPDATE people SET (name = 'Bob', lock_version = 4|lock_version = 4, name = 'Bob') WHERE \(\(id = 1\) AND \(lock_version = 3\)\)/
110
+ end
111
+
109
112
  specify "should increment the lock column when #modified! even if no columns are changed" do
110
113
  p1 = @c[1]
111
114
  p1.modified!
@@ -115,7 +118,7 @@ describe "optimistic_locking plugin" do
115
118
  end
116
119
 
117
120
  specify "should not increment the lock column when the update fails" do
118
- @c.dataset.meta_def(:update) { raise Exception }
121
+ @c.instance_dataset.meta_def(:update) { raise Exception }
119
122
  p1 = @c[1]
120
123
  p1.modified!
121
124
  lv = p1.lock_version
@@ -0,0 +1,105 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel::Postgres::ArrayOp" do
4
+ # Attempt to load pg_array first to test PGArray -> ArrayOp code
5
+ pg_array_loaded = begin
6
+ Sequel.extension :pg_array
7
+ true
8
+ rescue LoadError
9
+ false
10
+ end
11
+
12
+ Sequel.extension :pg_array_ops
13
+
14
+ before do
15
+ @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
16
+ @a = :a.pg_array
17
+ end
18
+
19
+ it "should support the standard mathematical operators" do
20
+ @db.literal(@a < @a).should == "(a < a)"
21
+ @db.literal(@a <= @a).should == "(a <= a)"
22
+ @db.literal(@a > @a).should == "(a > a)"
23
+ @db.literal(@a >= @a).should == "(a >= a)"
24
+ end
25
+
26
+ it "#[] should support subscript access" do
27
+ @db.literal(@a[1]).should == "a[1]"
28
+ @db.literal(@a[1][2]).should == "a[1][2]"
29
+ end
30
+
31
+ it "#any should use the ANY method" do
32
+ @db.literal(1=>@a.any).should == "(1 = ANY(a))"
33
+ end
34
+
35
+ it "#all should use the ALL method" do
36
+ @db.literal(1=>@a.all).should == "(1 = ALL(a))"
37
+ end
38
+
39
+ it "#contains should use the @> operator" do
40
+ @db.literal(@a.contains(:b)).should == "(a @> b)"
41
+ end
42
+
43
+ it "#contained_by should use the <@ operator" do
44
+ @db.literal(@a.contained_by(:b)).should == "(a <@ b)"
45
+ end
46
+
47
+ it "#overlaps should use the && operator" do
48
+ @db.literal(@a.overlaps(:b)).should == "(a && b)"
49
+ end
50
+
51
+ it "#push/concat should use the || operator in append mode" do
52
+ @db.literal(@a.push(:b)).should == "(a || b)"
53
+ @db.literal(@a.concat(:b)).should == "(a || b)"
54
+ end
55
+
56
+ it "#unshift should use the || operator in prepend mode" do
57
+ @db.literal(@a.unshift(:b)).should == "(b || a)"
58
+ end
59
+
60
+ it "#dims should use the array_dims function" do
61
+ @db.literal(@a.dims).should == "array_dims(a)"
62
+ end
63
+
64
+ it "#length should use the array_length function" do
65
+ @db.literal(@a.length).should == "array_length(a, 1)"
66
+ @db.literal(@a.length(2)).should == "array_length(a, 2)"
67
+ end
68
+
69
+ it "#length should use the array_lower function" do
70
+ @db.literal(@a.lower).should == "array_lower(a, 1)"
71
+ @db.literal(@a.lower(2)).should == "array_lower(a, 2)"
72
+ end
73
+
74
+ it "#to_string/join should use the array_to_string function" do
75
+ @db.literal(@a.to_string).should == "array_to_string(a, '', NULL)"
76
+ @db.literal(@a.join).should == "array_to_string(a, '', NULL)"
77
+ @db.literal(@a.join(':')).should == "array_to_string(a, ':', NULL)"
78
+ @db.literal(@a.join(':', '*')).should == "array_to_string(a, ':', '*')"
79
+ end
80
+
81
+ it "#unnest should use the unnest function" do
82
+ @db.literal(@a.unnest).should == "unnest(a)"
83
+ end
84
+
85
+ it "#pg_array should return self" do
86
+ @a.pg_array.should equal(@a)
87
+ end
88
+
89
+ it "should be able to turn expressions into array ops using pg_array" do
90
+ @db.literal(:a.qualify(:b).pg_array.push(3)).should == "(b.a || 3)"
91
+ @db.literal(:a.sql_function(:b).pg_array.push(3)).should == "(a(b) || 3)"
92
+ end
93
+
94
+ it "should be able to turn literal strings into array ops using pg_array" do
95
+ @db.literal('a'.lit.pg_array.unnest).should == "unnest(a)"
96
+ end
97
+
98
+ it "should be able to turn symbols into array ops using pg_array" do
99
+ @db.literal(:a.pg_array.unnest).should == "unnest(a)"
100
+ end
101
+
102
+ it "should allow transforming PGArray instances into ArrayOp instances" do
103
+ @db.literal([1,2].pg_array.op.push(3)).should == "(ARRAY[1,2] || 3)"
104
+ end if pg_array_loaded
105
+ end
@@ -0,0 +1,196 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ begin
4
+ Sequel.extension :pg_array
5
+ rescue LoadError => e
6
+ skip_warn "can't load pg_array extension (#{e.class}: #{e})"
7
+ else
8
+ describe "pg_array extension" do
9
+ before do
10
+ @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
11
+ @db.extend(Module.new{def bound_variable_arg(arg, conn) arg end})
12
+ @m = Sequel::Postgres
13
+ end
14
+
15
+ it "should parse single dimensional text arrays" do
16
+ @m::PGStringArray.parse("{a}").to_a.first.should be_a_kind_of(String)
17
+ @m::PGStringArray.parse("{}").to_a.should == []
18
+ @m::PGStringArray.parse("{a}").to_a.should == ['a']
19
+ @m::PGStringArray.parse('{"a b"}').to_a.should == ['a b']
20
+ @m::PGStringArray.parse('{a,b}').to_a.should == ['a', 'b']
21
+ end
22
+
23
+ it "should parse multi-dimensional text arrays" do
24
+ @m::PGStringArray.parse("{{}}").to_a.should == [[]]
25
+ @m::PGStringArray.parse("{{a},{b}}").to_a.should == [['a'], ['b']]
26
+ @m::PGStringArray.parse('{{"a b"},{c}}').to_a.should == [['a b'], ['c']]
27
+ @m::PGStringArray.parse('{{{a},{b}},{{c},{d}}}').to_a.should == [[['a'], ['b']], [['c'], ['d']]]
28
+ @m::PGStringArray.parse('{{{a,e},{b,f}},{{c,g},{d,h}}}').to_a.should == [[['a', 'e'], ['b', 'f']], [['c', 'g'], ['d', 'h']]]
29
+ end
30
+
31
+ it "should parse text arrays with embedded deliminaters" do
32
+ @m::PGStringArray.parse('{{"{},","\\",\\,\\\\\\"\\""}}').to_a.should == [['{},', '",,\\""']]
33
+ end
34
+
35
+ it "should parse single dimensional integer arrays" do
36
+ @m::PGIntegerArray.parse("{1}").to_a.first.should be_a_kind_of(Integer)
37
+ @m::PGIntegerArray.parse("{}").to_a.should == []
38
+ @m::PGIntegerArray.parse("{1}").to_a.should == [1]
39
+ @m::PGIntegerArray.parse('{2,3}').to_a.should == [2, 3]
40
+ @m::PGIntegerArray.parse('{3,4,5}').to_a.should == [3, 4, 5]
41
+ end
42
+
43
+ it "should parse multiple dimensional integer arrays" do
44
+ @m::PGIntegerArray.parse("{{}}").to_a.should == [[]]
45
+ @m::PGIntegerArray.parse("{{1}}").to_a.should == [[1]]
46
+ @m::PGIntegerArray.parse('{{2},{3}}').to_a.should == [[2], [3]]
47
+ @m::PGIntegerArray.parse('{{{1,2},{3,4}},{{5,6},{7,8}}}').to_a.should == [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
48
+ end
49
+
50
+ it "should parse single dimensional float arrays" do
51
+ @m::PGFloatArray.parse("{}").to_a.should == []
52
+ @m::PGFloatArray.parse("{1.5}").to_a.should == [1.5]
53
+ @m::PGFloatArray.parse('{2.5,3.5}').to_a.should == [2.5, 3.5]
54
+ @m::PGFloatArray.parse('{3.5,4.5,5.5}').to_a.should == [3.5, 4.5, 5.5]
55
+ end
56
+
57
+ it "should parse multiple dimensional float arrays" do
58
+ @m::PGFloatArray.parse("{{}}").to_a.should == [[]]
59
+ @m::PGFloatArray.parse("{{1.5}}").to_a.should == [[1.5]]
60
+ @m::PGFloatArray.parse('{{2.5},{3.5}}').to_a.should == [[2.5], [3.5]]
61
+ @m::PGFloatArray.parse('{{{1.5,2.5},{3.5,4.5}},{{5.5,6.5},{7.5,8.5}}}').to_a.should == [[[1.5, 2.5], [3.5, 4.5]], [[5.5, 6.5], [7.5, 8.5]]]
62
+ end
63
+
64
+ it "should parse integers in float arrays as floats" do
65
+ @m::PGFloatArray.parse("{1}").to_a.first.should be_a_kind_of(Float)
66
+ @m::PGFloatArray.parse("{1}").to_a.should == [1.0]
67
+ @m::PGFloatArray.parse('{{{1,2},{3,4}},{{5,6},{7,8}}}').to_a.should == [[[1.0, 2.0], [3.0, 4.0]], [[5.0, 6.0], [7.0, 8.0]]]
68
+ end
69
+
70
+ it "should parse single dimensional decimal arrays" do
71
+ @m::PGDecimalArray.parse("{}").to_a.should == []
72
+ @m::PGDecimalArray.parse("{1.5}").to_a.should == [BigDecimal.new('1.5')]
73
+ @m::PGDecimalArray.parse('{2.5,3.5}').to_a.should == [BigDecimal.new('2.5'), BigDecimal.new('3.5')]
74
+ @m::PGDecimalArray.parse('{3.5,4.5,5.5}').to_a.should == [BigDecimal.new('3.5'), BigDecimal.new('4.5'), BigDecimal.new('5.5')]
75
+ end
76
+
77
+ it "should parse multiple dimensional decimal arrays" do
78
+ @m::PGDecimalArray.parse("{{}}").to_a.should == [[]]
79
+ @m::PGDecimalArray.parse("{{1.5}}").to_a.should == [[BigDecimal.new('1.5')]]
80
+ @m::PGDecimalArray.parse('{{2.5},{3.5}}').to_a.should == [[BigDecimal.new('2.5')], [BigDecimal.new('3.5')]]
81
+ @m::PGDecimalArray.parse('{{{1.5,2.5},{3.5,4.5}},{{5.5,6.5},{7.5,8.5}}}').to_a.should == [[[BigDecimal.new('1.5'), BigDecimal.new('2.5')], [BigDecimal.new('3.5'), BigDecimal.new('4.5')]], [[BigDecimal.new('5.5'), BigDecimal.new('6.5')], [BigDecimal.new('7.5'), BigDecimal.new('8.5')]]]
82
+ end
83
+
84
+ it "should parse decimal values with arbitrary precision" do
85
+ @m::PGDecimalArray.parse("{1.000000000000000000005}").to_a.should == [BigDecimal.new('1.000000000000000000005')]
86
+ @m::PGDecimalArray.parse("{{1.000000000000000000005,2.000000000000000000005},{3.000000000000000000005,4.000000000000000000005}}").to_a.should == [[BigDecimal.new('1.000000000000000000005'), BigDecimal.new('2.000000000000000000005')], [BigDecimal.new('3.000000000000000000005'), BigDecimal.new('4.000000000000000000005')]]
87
+ end
88
+
89
+ it "should parse integers in decimal arrays as BigDecimals" do
90
+ @m::PGDecimalArray.parse("{1}").to_a.first.should be_a_kind_of(BigDecimal)
91
+ @m::PGDecimalArray.parse("{1}").to_a.should == [BigDecimal.new('1')]
92
+ @m::PGDecimalArray.parse('{{{1,2},{3,4}},{{5,6},{7,8}}}').to_a.should == [[[BigDecimal.new('1'), BigDecimal.new('2')], [BigDecimal.new('3'), BigDecimal.new('4')]], [[BigDecimal.new('5'), BigDecimal.new('6')], [BigDecimal.new('7'), BigDecimal.new('8')]]]
93
+ end
94
+
95
+ it "should parse arrays with NULL values" do
96
+ [@m::PGStringArray, @m::PGIntegerArray, @m::PGFloatArray, @m::PGDecimalArray].each do |c|
97
+ c.parse("{NULL}").should == [nil]
98
+ c.parse("{NULL,NULL}").should == [nil,nil]
99
+ c.parse("{{NULL,NULL},{NULL,NULL}}").should == [[nil,nil],[nil,nil]]
100
+ end
101
+ end
102
+
103
+ it 'should parse arrays with "NULL" values' do
104
+ @m::PGStringArray.parse('{NULL,"NULL",NULL}').to_a.should == [nil, "NULL", nil]
105
+ @m::PGStringArray.parse('{NULLA,"NULL",NULL}').to_a.should == ["NULLA", "NULL", nil]
106
+ end
107
+
108
+ it "should literalize arrays without types correctly" do
109
+ @db.literal(@m::PGArray.new([])).should == 'ARRAY[]'
110
+ @db.literal(@m::PGArray.new([1])).should == 'ARRAY[1]'
111
+ @db.literal(@m::PGArray.new([nil])).should == 'ARRAY[NULL]'
112
+ @db.literal(@m::PGArray.new([nil, 1])).should == 'ARRAY[NULL,1]'
113
+ @db.literal(@m::PGArray.new([1.0, 2.5])).should == 'ARRAY[1.0,2.5]'
114
+ @db.literal(@m::PGArray.new([BigDecimal.new('1'), BigDecimal.new('2.000000000000000000005')])).should == 'ARRAY[1.0,2.000000000000000000005]'
115
+ @db.literal(@m::PGArray.new([nil, "NULL"])).should == "ARRAY[NULL,'NULL']"
116
+ @db.literal(@m::PGArray.new([nil, "{},[]'\""])).should == "ARRAY[NULL,'{},[]''\"']"
117
+ end
118
+
119
+ it "should literalize multidimensional arrays correctly" do
120
+ @db.literal(@m::PGArray.new([[]])).should == 'ARRAY[[]]'
121
+ @db.literal(@m::PGArray.new([[1, 2]])).should == 'ARRAY[[1,2]]'
122
+ @db.literal(@m::PGArray.new([[3], [5]])).should == 'ARRAY[[3],[5]]'
123
+ @db.literal(@m::PGArray.new([[[1.0]], [[2.5]]])).should == 'ARRAY[[[1.0]],[[2.5]]]'
124
+ @db.literal(@m::PGArray.new([[[["NULL"]]]])).should == "ARRAY[[[['NULL']]]]"
125
+ @db.literal(@m::PGArray.new([["a", "b"], ["{},[]'\"", nil]])).should == "ARRAY[['a','b'],['{},[]''\"',NULL]]"
126
+ end
127
+
128
+ it "should literalize with types correctly" do
129
+ @db.literal(@m::PGArray.new([1], :int4)).should == 'ARRAY[1]::int4[]'
130
+ @db.literal(@m::PGArray.new([nil], :text)).should == 'ARRAY[NULL]::text[]'
131
+ @db.literal(@m::PGArray.new([nil, 1], :int8)).should == 'ARRAY[NULL,1]::int8[]'
132
+ @db.literal(@m::PGArray.new([1.0, 2.5], :real)).should == 'ARRAY[1.0,2.5]::real[]'
133
+ @db.literal(@m::PGArray.new([BigDecimal.new('1'), BigDecimal.new('2.000000000000000000005')], :decimal)).should == 'ARRAY[1.0,2.000000000000000000005]::decimal[]'
134
+ @db.literal(@m::PGArray.new([nil, "NULL"], :varchar)).should == "ARRAY[NULL,'NULL']::varchar[]"
135
+ @db.literal(@m::PGArray.new([nil, "{},[]'\""], :"varchar(255)")).should == "ARRAY[NULL,'{},[]''\"']::varchar(255)[]"
136
+ end
137
+
138
+ it "should have reasonable default types" do
139
+ @db.literal(@m::PGArray.new([])).should == 'ARRAY[]'
140
+ @db.literal(@m::PGIntegerArray.new([])).should == 'ARRAY[]::int4[]'
141
+ @db.literal(@m::PGFloatArray.new([])).should == 'ARRAY[]::double precision[]'
142
+ @db.literal(@m::PGStringArray.new([])).should == 'ARRAY[]::text[]'
143
+ @db.literal(@m::PGDecimalArray.new([])).should == 'ARRAY[]::decimal[]'
144
+ end
145
+
146
+ it "should use varchar type for char arrays without length" do
147
+ @db.literal(@m::PGStringArray.new([], :char)).should == 'ARRAY[]::varchar[]'
148
+ @db.literal(@m::PGStringArray.new([], 'char')).should == 'ARRAY[]::varchar[]'
149
+ end
150
+
151
+ it "should use given type for char arrays with length" do
152
+ @db.literal(@m::PGStringArray.new([], :'char(2)')).should == 'ARRAY[]::char(2)[]'
153
+ @db.literal(@m::PGStringArray.new([], 'char(1)')).should == 'ARRAY[]::char(1)[]'
154
+ end
155
+
156
+ it "should have Array#pg_array method for easy PGArray creation" do
157
+ @db.literal([1].pg_array).should == 'ARRAY[1]'
158
+ @db.literal([1, 2].pg_array(:int4)).should == 'ARRAY[1,2]::int4[]'
159
+ @db.literal([[[1], [2]], [[3], [4]]].pg_array(:real)).should == 'ARRAY[[[1],[2]],[[3],[4]]]::real[]'
160
+ end
161
+
162
+ it "should support using arrays as bound variables" do
163
+ @db.extend Sequel::Postgres::PGArray::DatabaseMethods
164
+ @db.bound_variable_arg(1, nil).should == 1
165
+ @db.bound_variable_arg([1,2].pg_array, nil).should == '{1,2}'
166
+ @db.bound_variable_arg([1,2], nil).should == '{1,2}'
167
+ @db.bound_variable_arg([[1,2]], nil).should == '{{1,2}}'
168
+ @db.bound_variable_arg([1.0,2.0], nil).should == '{1.0,2.0}'
169
+ @db.bound_variable_arg(["\\ \"", 'NULL', nil], nil).should == '{"\\\\ \\"","NULL",NULL}'
170
+ end
171
+
172
+ it "should parse array types from the schema correctly" do
173
+ @db.extend Sequel::Postgres::PGArray::DatabaseMethods
174
+ @db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'integer[]'}, {:name=>'f', :db_type=>'real[]'}, {:name=>'d', :db_type=>'numeric[]'}, {:name=>'t', :db_type=>'text[]'}]
175
+ @db.schema(:items).map{|e| e[1][:type]}.should == [:integer, :integer_array, :float_array, :decimal_array, :string_array]
176
+ end
177
+
178
+ it "should support typecasting of the various array types" do
179
+ @db.extend Sequel::Postgres::PGArray::DatabaseMethods
180
+ a = [1, 2]
181
+ o = a.pg_array
182
+ %w[integer float decimal string].each do |x|
183
+ @db.typecast_value(:"#{x}_array", o).should equal(o)
184
+ @db.typecast_value(:"#{x}_array", a).should == a
185
+ @db.typecast_value(:"#{x}_array", a).should be_a_kind_of(eval("Sequel::Postgres::PG#{x.capitalize}Array"))
186
+ @db.typecast_value(:"#{x}_array", '{}').should == []
187
+ @db.typecast_value(:"#{x}_array", '{}').should be_a_kind_of(eval("Sequel::Postgres::PG#{x.capitalize}Array"))
188
+ end
189
+ @db.typecast_value(:integer_array, '{1}').should == [1]
190
+ @db.typecast_value(:float_array, '{1}').should == [1.0]
191
+ @db.typecast_value(:decimal_array, '{1}').should == [BigDecimal.new('1')]
192
+ @db.typecast_value(:string_array, '{1}').should == ['1']
193
+ proc{@db.typecast_value(:integer_array, {})}.should raise_error(Sequel::InvalidValue)
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,65 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "pg_auto_parameterize extension" do
4
+ before do
5
+ @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
6
+ @db.synchronize{|c| def c.escape_bytea(v) v*2 end}
7
+ @db.extend_datasets{def use_cursor(*) clone end}
8
+ @db.extend Sequel::Postgres::AutoParameterize::DatabaseMethods
9
+ end
10
+
11
+ it "should automatically parameterize queries strings, blobs, numerics, dates, and times" do
12
+ pr = proc do |ds, sql, *args|
13
+ arg = args[0]
14
+ parg = args[1] || arg
15
+ s = ds.filter(:a=>arg).sql
16
+ s.should == sql
17
+ s.args.should == (parg == :nil ? nil : [parg])
18
+ end
19
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::int4)', 1)
20
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::int8)', 18446744073709551616)
21
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::double precision)', 1.1)
22
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::numeric)', BigDecimal.new('1.01'))
23
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::text)', "a")
24
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::bytea)', "a\0b".to_sequel_blob)
25
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = 1)', '1'.lit, :nil)
26
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::time)', Sequel::SQLTime.create(1, 2, 3, 500000))
27
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::date)', Date.today)
28
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::timestamp)', DateTime.new(2012, 1, 2, 3, 4, 5))
29
+ pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::timestamp)', Time.utc(2012, 1, 2, 3, 4, 5))
30
+ end
31
+
32
+ it "should extract parameters from query string when executing" do
33
+ @db.fetch = {:a=>1}
34
+ @db.numrows = 1
35
+ @db.autoid = 1
36
+
37
+ @db[:table].filter(:a=>1).all.should == [{:a=>1}]
38
+ @db.sqls.should == ['SELECT * FROM table WHERE (a = $1::int4) -- args: [1]']
39
+
40
+ @db[:table].filter(:a=>1).update(:b=>'a').should == 1
41
+ @db.sqls.should == ['UPDATE table SET b = $1::text WHERE (a = $2::int4) -- args: ["a", 1]']
42
+
43
+ @db[:table].filter(:a=>1).delete.should == 1
44
+ @db.sqls.should == ['DELETE FROM table WHERE (a = $1::int4) -- args: [1]']
45
+
46
+ @db[:table].insert(:a=>1).should == 1
47
+ @db.sqls.should == ['INSERT INTO table (a) VALUES ($1::int4) RETURNING id -- args: [1]']
48
+ end
49
+
50
+ it "should not automatically paramiterize if no_auto_parameterize is used" do
51
+ @db[:table].no_auto_parameterize.filter(:a=>1).sql.should == 'SELECT * FROM table WHERE (a = 1)'
52
+ end
53
+
54
+ it "should not automatically parameterize prepared statements" do
55
+ @db[:table].filter(:a=>1, :b=>:$b).prepare(:select).sql.should =~ /SELECT \* FROM table WHERE \(\((a = 1|b = \$b)\) AND \((a = 1|b = \$b)\)\)/
56
+ end
57
+
58
+ it "should show args with string when inspecting SQL " do
59
+ @db[:table].filter(:a=>1).sql.inspect.should == '"SELECT * FROM table WHERE (a = $1::int4); [1]"'
60
+ end
61
+
62
+ it "should not auto parameterize when using cursors" do
63
+ @db[:table].filter(:a=>1).use_cursor.opts[:no_auto_parameterize].should be_true
64
+ end
65
+ end
@@ -0,0 +1,136 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel::Postgres::HStoreOp" do
4
+ before do
5
+ @ds = Sequel.connect('mock://postgres', :quote_identifiers=>false).dataset
6
+ @h = :h.hstore
7
+ end
8
+
9
+ it "#- should use the - operator" do
10
+ @ds.literal(@h - 'a').should == "(h - 'a')"
11
+ end
12
+
13
+ it "#- should return an HStoreOp" do
14
+ @ds.literal((@h - 'a')['a']).should == "((h - 'a') -> 'a')"
15
+ end
16
+
17
+ it "#[] should use the -> operator" do
18
+ @ds.literal(@h['a']).should == "(h -> 'a')"
19
+ end
20
+
21
+ it "#[] should return a string expression" do
22
+ @ds.literal(@h['a'] + 'b').should == "((h -> 'a') || 'b')"
23
+ end
24
+
25
+ it "#concat and #merge should use the || operator" do
26
+ @ds.literal(@h.concat(:h1)).should == "(h || h1)"
27
+ @ds.literal(@h.merge(:h1)).should == "(h || h1)"
28
+ end
29
+
30
+ it "#concat should return an HStoreOp" do
31
+ @ds.literal(@h.concat(:h1)['a']).should == "((h || h1) -> 'a')"
32
+ end
33
+
34
+ it "#contain_all should use the ?& operator" do
35
+ @ds.literal(@h.contain_all(:h1)).should == "(h ?& h1)"
36
+ end
37
+
38
+ it "#contain_any should use the ?| operator" do
39
+ @ds.literal(@h.contain_any(:h1)).should == "(h ?| h1)"
40
+ end
41
+
42
+ it "#contains should use the @> operator" do
43
+ @ds.literal(@h.contains(:h1)).should == "(h @> h1)"
44
+ end
45
+
46
+ it "#contained_by should use the <@ operator" do
47
+ @ds.literal(@h.contained_by(:h1)).should == "(h <@ h1)"
48
+ end
49
+
50
+ it "#defined should use the defined function" do
51
+ @ds.literal(@h.defined('a')).should == "defined(h, 'a')"
52
+ end
53
+
54
+ it "#delete should use the delete function" do
55
+ @ds.literal(@h.delete('a')).should == "delete(h, 'a')"
56
+ end
57
+
58
+ it "#delete should return an HStoreOp" do
59
+ @ds.literal(@h.delete('a')['a']).should == "(delete(h, 'a') -> 'a')"
60
+ end
61
+
62
+ it "#each should use the each function" do
63
+ @ds.literal(@h.each).should == "each(h)"
64
+ end
65
+
66
+ it "#has_key? and aliases should use the ? operator" do
67
+ @ds.literal(@h.has_key?('a')).should == "(h ? 'a')"
68
+ @ds.literal(@h.key?('a')).should == "(h ? 'a')"
69
+ @ds.literal(@h.member?('a')).should == "(h ? 'a')"
70
+ @ds.literal(@h.include?('a')).should == "(h ? 'a')"
71
+ @ds.literal(@h.exist?('a')).should == "(h ? 'a')"
72
+ end
73
+
74
+ it "#hstore should return the receiver" do
75
+ @h.hstore.should equal(@h)
76
+ end
77
+
78
+ it "#keys and #akeys should use the akeys function" do
79
+ @ds.literal(@h.keys).should == "akeys(h)"
80
+ @ds.literal(@h.akeys).should == "akeys(h)"
81
+ end
82
+
83
+ it "#populate should use the populate_record function" do
84
+ @ds.literal(@h.populate(:a)).should == "populate_record(a, h)"
85
+ end
86
+
87
+ it "#record_set should use the #= operator" do
88
+ @ds.literal(@h.record_set(:a)).should == "(a #= h)"
89
+ end
90
+
91
+ it "#skeys should use the skeys function" do
92
+ @ds.literal(@h.skeys).should == "skeys(h)"
93
+ end
94
+
95
+ it "#slice should should use the slice function" do
96
+ @ds.literal(@h.slice(:a)).should == "slice(h, a)"
97
+ end
98
+
99
+ it "#slice should return an HStoreOp" do
100
+ @ds.literal(@h.slice(:a)['a']).should == "(slice(h, a) -> 'a')"
101
+ end
102
+
103
+ it "#svals should use the svals function" do
104
+ @ds.literal(@h.svals).should == "svals(h)"
105
+ end
106
+
107
+ it "#to_array should use the hstore_to_array function" do
108
+ @ds.literal(@h.to_array).should == "hstore_to_array(h)"
109
+ end
110
+
111
+ it "#to_matrix should use the hstore_to_matrix function" do
112
+ @ds.literal(@h.to_matrix).should == "hstore_to_matrix(h)"
113
+ end
114
+
115
+ it "#values and #avals should use the avals function" do
116
+ @ds.literal(@h.values).should == "avals(h)"
117
+ @ds.literal(@h.avals).should == "avals(h)"
118
+ end
119
+
120
+ it "should be able to turn expressions into hstore ops using hstore" do
121
+ @ds.literal(:a.qualify(:b).hstore['a']).should == "(b.a -> 'a')"
122
+ @ds.literal(:a.sql_function(:b).hstore['a']).should == "(a(b) -> 'a')"
123
+ end
124
+
125
+ it "should be able to turn literal strings into hstore ops using hstore" do
126
+ @ds.literal('a'.lit.hstore['a']).should == "(a -> 'a')"
127
+ end
128
+
129
+ it "should be able to turn symbols into hstore ops using hstore" do
130
+ @ds.literal(:a.hstore['a']).should == "(a -> 'a')"
131
+ end
132
+
133
+ it "should allow transforming HStore instances into HStoreOp instances" do
134
+ @ds.literal({'a'=>'b'}.hstore.op['a']).should == "('\"a\"=>\"b\"'::hstore -> 'a')"
135
+ end
136
+ end