sequel 3.21.0 → 3.39.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 (352) hide show
  1. data/CHANGELOG +1061 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +103 -63
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +67 -51
  7. data/doc/advanced_associations.rdoc +189 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/cheat_sheet.rdoc +21 -21
  10. data/doc/core_extensions.rdoc +374 -0
  11. data/doc/dataset_basics.rdoc +10 -10
  12. data/doc/dataset_filtering.rdoc +54 -42
  13. data/doc/mass_assignment.rdoc +56 -0
  14. data/doc/migration.rdoc +89 -557
  15. data/doc/model_hooks.rdoc +80 -29
  16. data/doc/object_model.rdoc +547 -0
  17. data/doc/opening_databases.rdoc +114 -53
  18. data/doc/prepared_statements.rdoc +41 -15
  19. data/doc/querying.rdoc +137 -56
  20. data/doc/reflection.rdoc +36 -10
  21. data/doc/release_notes/3.22.0.txt +39 -0
  22. data/doc/release_notes/3.23.0.txt +172 -0
  23. data/doc/release_notes/3.24.0.txt +420 -0
  24. data/doc/release_notes/3.25.0.txt +88 -0
  25. data/doc/release_notes/3.26.0.txt +88 -0
  26. data/doc/release_notes/3.27.0.txt +82 -0
  27. data/doc/release_notes/3.28.0.txt +304 -0
  28. data/doc/release_notes/3.29.0.txt +459 -0
  29. data/doc/release_notes/3.30.0.txt +135 -0
  30. data/doc/release_notes/3.31.0.txt +146 -0
  31. data/doc/release_notes/3.32.0.txt +202 -0
  32. data/doc/release_notes/3.33.0.txt +157 -0
  33. data/doc/release_notes/3.34.0.txt +671 -0
  34. data/doc/release_notes/3.35.0.txt +144 -0
  35. data/doc/release_notes/3.36.0.txt +245 -0
  36. data/doc/release_notes/3.37.0.txt +338 -0
  37. data/doc/release_notes/3.38.0.txt +234 -0
  38. data/doc/release_notes/3.39.0.txt +237 -0
  39. data/doc/schema_modification.rdoc +585 -0
  40. data/doc/sharding.rdoc +99 -8
  41. data/doc/sql.rdoc +154 -112
  42. data/doc/testing.rdoc +169 -0
  43. data/doc/thread_safety.rdoc +17 -0
  44. data/doc/transactions.rdoc +137 -0
  45. data/doc/validations.rdoc +1 -1
  46. data/doc/virtual_rows.rdoc +78 -43
  47. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  48. data/lib/sequel/adapters/ado.rb +40 -18
  49. data/lib/sequel/adapters/amalgalite.rb +17 -9
  50. data/lib/sequel/adapters/db2.rb +175 -86
  51. data/lib/sequel/adapters/dbi.rb +15 -15
  52. data/lib/sequel/adapters/do/mysql.rb +17 -11
  53. data/lib/sequel/adapters/do/postgres.rb +2 -61
  54. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  55. data/lib/sequel/adapters/do.rb +18 -36
  56. data/lib/sequel/adapters/firebird.rb +27 -208
  57. data/lib/sequel/adapters/ibmdb.rb +453 -0
  58. data/lib/sequel/adapters/informix.rb +6 -23
  59. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  60. data/lib/sequel/adapters/jdbc/db2.rb +56 -0
  61. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  62. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  63. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  64. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  65. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  66. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  67. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  68. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  69. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  70. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  71. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  73. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  74. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  75. data/lib/sequel/adapters/jdbc.rb +279 -97
  76. data/lib/sequel/adapters/mock.rb +372 -0
  77. data/lib/sequel/adapters/mysql.rb +125 -222
  78. data/lib/sequel/adapters/mysql2.rb +65 -56
  79. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  80. data/lib/sequel/adapters/odbc.rb +28 -9
  81. data/lib/sequel/adapters/openbase.rb +3 -5
  82. data/lib/sequel/adapters/oracle.rb +349 -53
  83. data/lib/sequel/adapters/postgres.rb +368 -138
  84. data/lib/sequel/adapters/shared/access.rb +32 -9
  85. data/lib/sequel/adapters/shared/db2.rb +343 -0
  86. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  87. data/lib/sequel/adapters/shared/informix.rb +53 -0
  88. data/lib/sequel/adapters/shared/mssql.rb +401 -116
  89. data/lib/sequel/adapters/shared/mysql.rb +424 -89
  90. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  91. data/lib/sequel/adapters/shared/oracle.rb +257 -45
  92. data/lib/sequel/adapters/shared/postgres.rb +675 -279
  93. data/lib/sequel/adapters/shared/progress.rb +5 -8
  94. data/lib/sequel/adapters/shared/sqlite.rb +285 -96
  95. data/lib/sequel/adapters/sqlite.rb +101 -39
  96. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  97. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  98. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  99. data/lib/sequel/adapters/swift.rb +28 -19
  100. data/lib/sequel/adapters/tinytds.rb +174 -22
  101. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  102. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  103. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  104. data/lib/sequel/ast_transformer.rb +194 -0
  105. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  106. data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
  107. data/lib/sequel/connection_pool/single.rb +5 -0
  108. data/lib/sequel/connection_pool/threaded.rb +43 -14
  109. data/lib/sequel/connection_pool.rb +10 -2
  110. data/lib/sequel/core.rb +143 -11
  111. data/lib/sequel/database/connecting.rb +38 -28
  112. data/lib/sequel/database/dataset.rb +4 -4
  113. data/lib/sequel/database/dataset_defaults.rb +63 -2
  114. data/lib/sequel/database/logging.rb +7 -2
  115. data/lib/sequel/database/misc.rb +190 -46
  116. data/lib/sequel/database/query.rb +272 -110
  117. data/lib/sequel/database/schema_generator.rb +103 -36
  118. data/lib/sequel/database/schema_methods.rb +300 -67
  119. data/lib/sequel/dataset/actions.rb +344 -90
  120. data/lib/sequel/dataset/features.rb +101 -8
  121. data/lib/sequel/dataset/graph.rb +42 -15
  122. data/lib/sequel/dataset/misc.rb +52 -25
  123. data/lib/sequel/dataset/mutation.rb +12 -7
  124. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  125. data/lib/sequel/dataset/query.rb +305 -54
  126. data/lib/sequel/dataset/sql.rb +720 -292
  127. data/lib/sequel/dataset.rb +8 -0
  128. data/lib/sequel/exceptions.rb +4 -0
  129. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  130. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  131. data/lib/sequel/extensions/blank.rb +4 -0
  132. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  133. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  134. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  135. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  136. data/lib/sequel/extensions/inflector.rb +4 -0
  137. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  138. data/lib/sequel/extensions/migration.rb +100 -11
  139. data/lib/sequel/extensions/named_timezones.rb +9 -0
  140. data/lib/sequel/extensions/null_dataset.rb +94 -0
  141. data/lib/sequel/extensions/pagination.rb +4 -0
  142. data/lib/sequel/extensions/pg_array.rb +537 -0
  143. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  144. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  145. data/lib/sequel/extensions/pg_hstore.rb +313 -0
  146. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  147. data/lib/sequel/extensions/pg_inet.rb +113 -0
  148. data/lib/sequel/extensions/pg_interval.rb +191 -0
  149. data/lib/sequel/extensions/pg_json.rb +208 -0
  150. data/lib/sequel/extensions/pg_range.rb +512 -0
  151. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  152. data/lib/sequel/extensions/pg_row.rb +572 -0
  153. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  154. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  155. data/lib/sequel/extensions/pretty_table.rb +17 -72
  156. data/lib/sequel/extensions/query.rb +8 -4
  157. data/lib/sequel/extensions/query_literals.rb +79 -0
  158. data/lib/sequel/extensions/schema_caching.rb +76 -0
  159. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  160. data/lib/sequel/extensions/select_remove.rb +39 -0
  161. data/lib/sequel/extensions/server_block.rb +140 -0
  162. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  163. data/lib/sequel/extensions/sql_expr.rb +8 -110
  164. data/lib/sequel/extensions/string_date_time.rb +4 -0
  165. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  166. data/lib/sequel/extensions/to_dot.rb +99 -83
  167. data/lib/sequel/model/associations.rb +1263 -409
  168. data/lib/sequel/model/base.rb +624 -171
  169. data/lib/sequel/model/errors.rb +1 -1
  170. data/lib/sequel/model/exceptions.rb +24 -2
  171. data/lib/sequel/model/inflections.rb +1 -1
  172. data/lib/sequel/model.rb +30 -11
  173. data/lib/sequel/no_core_ext.rb +2 -0
  174. data/lib/sequel/plugins/active_model.rb +13 -1
  175. data/lib/sequel/plugins/association_pks.rb +22 -4
  176. data/lib/sequel/plugins/caching.rb +25 -18
  177. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  178. data/lib/sequel/plugins/composition.rb +44 -12
  179. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  180. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  181. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  182. data/lib/sequel/plugins/dirty.rb +214 -0
  183. data/lib/sequel/plugins/eager_each.rb +59 -0
  184. data/lib/sequel/plugins/force_encoding.rb +6 -6
  185. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  186. data/lib/sequel/plugins/identity_map.rb +134 -15
  187. data/lib/sequel/plugins/instance_filters.rb +10 -0
  188. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  189. data/lib/sequel/plugins/json_serializer.rb +58 -6
  190. data/lib/sequel/plugins/list.rb +13 -2
  191. data/lib/sequel/plugins/many_through_many.rb +103 -51
  192. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  193. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  194. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  195. data/lib/sequel/plugins/pg_row.rb +121 -0
  196. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  197. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  198. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  199. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  200. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  201. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  202. data/lib/sequel/plugins/schema.rb +8 -3
  203. data/lib/sequel/plugins/serialization.rb +98 -49
  204. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  205. data/lib/sequel/plugins/sharding.rb +21 -54
  206. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  207. data/lib/sequel/plugins/static_cache.rb +99 -0
  208. data/lib/sequel/plugins/subclasses.rb +29 -3
  209. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  210. data/lib/sequel/plugins/timestamps.rb +1 -1
  211. data/lib/sequel/plugins/tree.rb +3 -3
  212. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  213. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  214. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  215. data/lib/sequel/plugins/validation_helpers.rb +55 -4
  216. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  217. data/lib/sequel/sql.rb +649 -122
  218. data/lib/sequel/timezones.rb +67 -40
  219. data/lib/sequel/version.rb +1 -1
  220. data/spec/adapters/db2_spec.rb +146 -0
  221. data/spec/adapters/firebird_spec.rb +1 -1
  222. data/spec/adapters/mssql_spec.rb +194 -66
  223. data/spec/adapters/mysql_spec.rb +475 -306
  224. data/spec/adapters/oracle_spec.rb +92 -117
  225. data/spec/adapters/postgres_spec.rb +1982 -325
  226. data/spec/adapters/spec_helper.rb +9 -6
  227. data/spec/adapters/sqlite_spec.rb +203 -75
  228. data/spec/core/connection_pool_spec.rb +218 -93
  229. data/spec/core/database_spec.rb +956 -522
  230. data/spec/core/dataset_spec.rb +1631 -1242
  231. data/spec/core/expression_filters_spec.rb +690 -334
  232. data/spec/core/mock_adapter_spec.rb +453 -0
  233. data/spec/core/object_graph_spec.rb +88 -129
  234. data/spec/core/schema_generator_spec.rb +4 -4
  235. data/spec/core/schema_spec.rb +556 -53
  236. data/spec/core/spec_helper.rb +7 -48
  237. data/spec/core_extensions_spec.rb +626 -0
  238. data/spec/extensions/active_model_spec.rb +13 -0
  239. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  240. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  241. data/spec/extensions/association_dependencies_spec.rb +15 -25
  242. data/spec/extensions/association_pks_spec.rb +66 -32
  243. data/spec/extensions/association_proxies_spec.rb +4 -4
  244. data/spec/extensions/boolean_readers_spec.rb +25 -25
  245. data/spec/extensions/caching_spec.rb +47 -51
  246. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  247. data/spec/extensions/columns_introspection_spec.rb +91 -0
  248. data/spec/extensions/composition_spec.rb +18 -13
  249. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  250. data/spec/extensions/constraint_validations_spec.rb +316 -0
  251. data/spec/extensions/dataset_associations_spec.rb +199 -0
  252. data/spec/extensions/defaults_setter_spec.rb +88 -0
  253. data/spec/extensions/dirty_spec.rb +155 -0
  254. data/spec/extensions/eager_each_spec.rb +34 -0
  255. data/spec/extensions/eval_inspect_spec.rb +67 -0
  256. data/spec/extensions/force_encoding_spec.rb +4 -2
  257. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  258. data/spec/extensions/identity_map_spec.rb +142 -24
  259. data/spec/extensions/inflector_spec.rb +0 -4
  260. data/spec/extensions/instance_filters_spec.rb +11 -21
  261. data/spec/extensions/instance_hooks_spec.rb +72 -0
  262. data/spec/extensions/json_serializer_spec.rb +49 -12
  263. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  264. data/spec/extensions/list_spec.rb +49 -40
  265. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  266. data/spec/extensions/many_through_many_spec.rb +368 -254
  267. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  268. data/spec/extensions/migration_spec.rb +140 -35
  269. data/spec/extensions/named_timezones_spec.rb +29 -11
  270. data/spec/extensions/nested_attributes_spec.rb +268 -89
  271. data/spec/extensions/null_dataset_spec.rb +85 -0
  272. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  273. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  274. data/spec/extensions/pg_array_spec.rb +320 -0
  275. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  276. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  277. data/spec/extensions/pg_hstore_spec.rb +194 -0
  278. data/spec/extensions/pg_inet_spec.rb +47 -0
  279. data/spec/extensions/pg_interval_spec.rb +72 -0
  280. data/spec/extensions/pg_json_spec.rb +99 -0
  281. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  282. data/spec/extensions/pg_range_spec.rb +395 -0
  283. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  284. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  285. data/spec/extensions/pg_row_spec.rb +323 -0
  286. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  287. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  288. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  289. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  290. data/spec/extensions/prepared_statements_spec.rb +87 -0
  291. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  292. data/spec/extensions/pretty_table_spec.rb +7 -6
  293. data/spec/extensions/query_literals_spec.rb +167 -0
  294. data/spec/extensions/query_spec.rb +9 -3
  295. data/spec/extensions/rcte_tree_spec.rb +50 -43
  296. data/spec/extensions/schema_caching_spec.rb +41 -0
  297. data/spec/extensions/schema_dumper_spec.rb +434 -49
  298. data/spec/extensions/schema_spec.rb +30 -49
  299. data/spec/extensions/select_remove_spec.rb +38 -0
  300. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  301. data/spec/extensions/serialization_spec.rb +86 -48
  302. data/spec/extensions/server_block_spec.rb +90 -0
  303. data/spec/extensions/sharding_spec.rb +69 -143
  304. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  305. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  306. data/spec/extensions/spec_helper.rb +34 -67
  307. data/spec/extensions/split_array_nil_spec.rb +24 -0
  308. data/spec/extensions/sql_expr_spec.rb +29 -60
  309. data/spec/extensions/static_cache_spec.rb +145 -0
  310. data/spec/extensions/subclasses_spec.rb +14 -0
  311. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  312. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  313. data/spec/extensions/timestamps_spec.rb +6 -6
  314. data/spec/extensions/to_dot_spec.rb +8 -11
  315. data/spec/extensions/touch_spec.rb +13 -14
  316. data/spec/extensions/tree_spec.rb +11 -26
  317. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  318. data/spec/extensions/update_primary_key_spec.rb +30 -24
  319. data/spec/extensions/validation_class_methods_spec.rb +58 -67
  320. data/spec/extensions/validation_helpers_spec.rb +31 -37
  321. data/spec/extensions/xml_serializer_spec.rb +29 -4
  322. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  323. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  324. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  325. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  326. data/spec/integration/associations_test.rb +659 -21
  327. data/spec/integration/database_test.rb +11 -5
  328. data/spec/integration/dataset_test.rb +717 -129
  329. data/spec/integration/eager_loader_test.rb +38 -54
  330. data/spec/integration/migrator_test.rb +2 -3
  331. data/spec/integration/model_test.rb +81 -2
  332. data/spec/integration/plugin_test.rb +604 -147
  333. data/spec/integration/prepared_statement_test.rb +272 -128
  334. data/spec/integration/schema_test.rb +367 -57
  335. data/spec/integration/spec_helper.rb +42 -32
  336. data/spec/integration/timezone_test.rb +38 -12
  337. data/spec/integration/transaction_test.rb +183 -8
  338. data/spec/integration/type_test.rb +31 -8
  339. data/spec/model/association_reflection_spec.rb +207 -8
  340. data/spec/model/associations_spec.rb +1206 -693
  341. data/spec/model/base_spec.rb +334 -100
  342. data/spec/model/dataset_methods_spec.rb +45 -27
  343. data/spec/model/eager_loading_spec.rb +828 -692
  344. data/spec/model/hooks_spec.rb +355 -67
  345. data/spec/model/model_spec.rb +251 -179
  346. data/spec/model/plugins_spec.rb +24 -13
  347. data/spec/model/record_spec.rb +506 -232
  348. data/spec/model/spec_helper.rb +16 -77
  349. data/spec/model/validations_spec.rb +38 -2
  350. data/spec/rcov.opts +2 -0
  351. metadata +209 -80
  352. data/spec/core/core_sql_spec.rb +0 -451
@@ -2,271 +2,197 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "sharding plugin" do
4
4
  before do
5
- @db = Sequel::Model.db.clone
5
+ @db = Sequel.mock(:numrows=>1, :autoid=>proc{1}, :servers=>{:s1=>{}, :s2=>{}, :s3=>{}, :s4=>{}})
6
6
  @Artist = Class.new(Sequel::Model(@db[:artists]))
7
7
  @Artist.class_eval do
8
+ instance_dataset._fetch = dataset._fetch = {:id=>2, :name=>'YJM'}
8
9
  columns :id, :name
9
-
10
- def self.y
11
- {:id=>2, :name=>'YJM'}
12
- end
10
+ plugin :sharding
13
11
  end
14
12
  @Album = Class.new(Sequel::Model(@db[:albums]))
15
13
  @Album.class_eval do
14
+ instance_dataset._fetch = dataset._fetch = {:id=>1, :name=>'RF', :artist_id=>2}
16
15
  columns :id, :artist_id, :name
17
-
18
- def self.ds_ext(m=nil)
19
- @ds_ext = m if m
20
- @ds_ext
21
- end
22
-
23
- def self.y
24
- {:id=>1, :name=>'RF', :artist_id=>2}
25
- end
26
-
27
- private
28
-
29
- def _join_table_dataset(opts)
30
- ds = super
31
- m = model
32
- ds.meta_def(:model){m}
33
- ds.extend model.ds_ext
34
- ds
35
- end
16
+ plugin :sharding
36
17
  end
37
18
  @Tag = Class.new(Sequel::Model(@db[:tags]))
38
19
  @Tag.class_eval do
20
+ instance_dataset._fetch = dataset._fetch = {:id=>3, :name=>'M'}
39
21
  columns :id, :name
40
-
41
- def self.y
42
- {:id=>3, :name=>'M'}
43
- end
22
+ plugin :sharding
44
23
  end
45
- models = [@Artist, @Album, @Tag]
46
24
  @Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id
47
25
  @Album.many_to_one :artist, :class=>@Artist
48
26
  @Album.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:albums_tags
49
- m = Module.new do
50
- def actions
51
- @actions ||= []
52
- end
53
- end
54
- models.each do |model|
55
- model.extend m
56
- model.plugin :sharding
57
- model.dataset.extend(ds_ext = Module.new do
58
- def insert(h={})
59
- model.actions << [:insert, h.dup, opts[:server]]
60
- 1
61
- end
62
- def delete
63
- model.actions << [:delete,(literal(opts[:where]) if opts[:where]), opts[:server]]
64
- 1
65
- end
66
- def update(h={})
67
- model.actions << [:update, h.dup, (literal(opts[:where]) if opts[:where]), opts[:server]]
68
- 1
69
- end
70
- def fetch_rows(sql)
71
- model.actions << [:fetch, (literal(opts[:where] || opts[:join]) if opts[:where] || opts[:join]), opts[:server]]
72
- yield(model.y)
73
- end
74
- end)
75
- @Album.ds_ext(ds_ext)
76
- end
77
- def @db.actions; @actions ||= []; end
78
- def @db.transaction(opts)
79
- actions << [:transaction, opts[:server]]
80
- super
81
- end
27
+ @db.sqls
82
28
  end
83
29
 
84
30
  specify "should allow you to instantiate a new object for a specified shard" do
85
31
  @Album.new_using_server(:s1, :name=>'RF').save
86
- @Album.actions.should == [[:insert, {:name=>"RF"}, :s1], [:fetch, "(id = 1)", :s1]]
32
+ @db.sqls.should == ["INSERT INTO albums (name) VALUES ('RF') -- s1", "SELECT * FROM albums WHERE (id = 1) LIMIT 1 -- s1"]
87
33
 
88
- @Album.actions.clear
89
34
  @Album.new_using_server(:s2){|o| o.name = 'MO'}.save
90
- @Album.actions.should == [[:insert, {:name=>"MO"}, :s2], [:fetch, "(id = 1)", :s2]]
35
+ @db.sqls.should == ["INSERT INTO albums (name) VALUES ('MO') -- s2", "SELECT * FROM albums WHERE (id = 1) LIMIT 1 -- s2"]
91
36
  end
92
37
 
93
38
  specify "should allow you to create and save a new object for a specified shard" do
94
39
  @Album.create_using_server(:s1, :name=>'RF')
95
- @Album.actions.should == [[:insert, {:name=>"RF"}, :s1], [:fetch, "(id = 1)", :s1]]
96
-
97
- @Album.actions.clear
40
+ @db.sqls.should == ["INSERT INTO albums (name) VALUES ('RF') -- s1", "SELECT * FROM albums WHERE (id = 1) LIMIT 1 -- s1"]
41
+
98
42
  @Album.create_using_server(:s2){|o| o.name = 'MO'}
99
- @Album.actions.should == [[:insert, {:name=>"MO"}, :s2], [:fetch, "(id = 1)", :s2]]
43
+ @db.sqls.should == ["INSERT INTO albums (name) VALUES ('MO') -- s2", "SELECT * FROM albums WHERE (id = 1) LIMIT 1 -- s2"]
100
44
  end
101
45
 
102
46
  specify "should have objects retrieved from a specific shard update that shard" do
103
47
  @Album.server(:s1).first.update(:name=>'MO')
104
- @Album.actions.should == [[:fetch, nil, :s1], [:update, {:name=>"MO"}, "(id = 1)", :s1]]
48
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "UPDATE albums SET name = 'MO' WHERE (id = 1) -- s1"]
105
49
  end
106
50
 
107
51
  specify "should have objects retrieved from a specific shard delete from that shard" do
108
52
  @Album.server(:s1).first.delete
109
- @Album.actions.should == [[:fetch, nil, :s1], [:delete, "(id = 1)", :s1]]
53
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "DELETE FROM albums WHERE (id = 1) -- s1"]
110
54
  end
111
55
 
112
56
  specify "should have objects retrieved from a specific shard reload from that shard" do
113
57
  @Album.server(:s1).first.reload
114
- @Album.actions.should == [[:fetch, nil, :s1], [:fetch, "(id = 1)", :s1]]
58
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "SELECT * FROM albums WHERE (id = 1) LIMIT 1 -- s1"]
115
59
  end
116
60
 
117
61
  specify "should use current dataset's shard when eager loading if eagerly loaded dataset doesn't have its own shard" do
118
62
  albums = @Album.server(:s1).eager(:artist).all
119
- @Album.actions.should == [[:fetch, nil, :s1]]
120
- @Artist.actions.should == [[:fetch, "(artists.id IN (2))", :s1]]
121
- @Artist.actions.clear
122
- albums.length == 1
63
+ @db.sqls.should == ["SELECT * FROM albums -- s1", "SELECT * FROM artists WHERE (artists.id IN (2)) -- s1"]
64
+ albums.length.should == 1
123
65
  albums.first.artist.save
124
- @Artist.actions.should == [[:update, {:name=>"YJM"}, "(id = 2)", :s1]]
66
+ @db.sqls.should == ["UPDATE artists SET name = 'YJM' WHERE (id = 2) -- s1"]
125
67
  end
126
68
 
127
69
  specify "should not use current dataset's shard when eager loading if eagerly loaded dataset has its own shard" do
128
- @Artist.dataset.opts[:server] = :s2
70
+ @Artist.instance_dataset.opts[:server] = @Artist.dataset.opts[:server] = :s2
129
71
  albums = @Album.server(:s1).eager(:artist).all
130
- @Album.actions.should == [[:fetch, nil, :s1]]
131
- @Artist.actions.should == [[:fetch, "(artists.id IN (2))", :s2]]
132
- @Artist.actions.clear
133
- albums.length == 1
72
+ @db.sqls.should == ["SELECT * FROM albums -- s1", "SELECT * FROM artists WHERE (artists.id IN (2)) -- s2"]
73
+ albums.length.should == 1
134
74
  albums.first.artist.save
135
- @Artist.actions.should == [[:update, {:name=>"YJM"}, "(id = 2)", :s2]]
75
+ @db.sqls.should == ["UPDATE artists SET name = 'YJM' WHERE (id = 2) -- s2"]
136
76
  end
137
77
 
138
78
  specify "should use current dataset's shard when eager graphing if eagerly graphed dataset doesn't have its own shard" do
139
79
  ds = @Album.server(:s1).eager_graph(:artist)
140
- def ds.fetch_rows(sql)
141
- super(sql)
142
- yield({:id=>1, :artist_id=>2, :name=>'RF', :artist_id_0=>2, :artist_name=>'YJM'})
143
- end
80
+ ds._fetch = {:id=>1, :artist_id=>2, :name=>'RF', :artist_id_0=>2, :artist_name=>'YJM'}
144
81
  albums = ds.all
145
- @Album.actions.should == [[:fetch, "( LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id))", :s1]]
146
- albums.length == 1
82
+ @db.sqls.should == ["SELECT albums.id, albums.artist_id, albums.name, artist.id AS artist_id_0, artist.name AS artist_name FROM albums LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id) -- s1"]
83
+ albums.length.should == 1
147
84
  albums.first.artist.save
148
- @Artist.actions.should == [[:update, {:name=>"YJM"}, "(id = 2)", :s1]]
85
+ @db.sqls.should == ["UPDATE artists SET name = 'YJM' WHERE (id = 2) -- s1"]
149
86
  end
150
87
 
151
88
  specify "should not use current dataset's shard when eager graphing if eagerly graphed dataset has its own shard" do
152
- @Artist.dataset.opts[:server] = :s2
89
+ @Artist.instance_dataset.opts[:server] = @Artist.dataset.opts[:server] = :s2
153
90
  ds = @Album.server(:s1).eager_graph(:artist)
154
- def ds.fetch_rows(sql)
155
- super(sql)
156
- yield({:id=>1, :artist_id=>2, :name=>'RF', :artist_id_0=>2, :artist_name=>'YJM'})
157
- end
91
+ ds._fetch = {:id=>1, :artist_id=>2, :name=>'RF', :artist_id_0=>2, :artist_name=>'YJM'}
158
92
  albums = ds.all
159
- @Album.actions.should == [[:fetch, "( LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id))", :s1]]
160
- albums.length == 1
93
+ @db.sqls.should == ["SELECT albums.id, albums.artist_id, albums.name, artist.id AS artist_id_0, artist.name AS artist_name FROM albums LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id) -- s1"]
94
+ albums.length.should == 1
161
95
  albums.first.artist.save
162
- @Artist.actions.should == [[:update, {:name=>"YJM"}, "(id = 2)", :s2]]
96
+ @db.sqls.should == ["UPDATE artists SET name = 'YJM' WHERE (id = 2) -- s2"]
163
97
  end
164
98
 
165
99
  specify "should use eagerly graphed dataset shard for eagerly graphed objects even if current dataset does not have a shard" do
166
- @Artist.dataset.opts[:server] = :s2
100
+ @Artist.instance_dataset.opts[:server] = @Artist.dataset.opts[:server] = :s2
167
101
  ds = @Album.eager_graph(:artist)
168
- def ds.fetch_rows(sql)
169
- super(sql)
170
- yield({:id=>1, :artist_id=>2, :name=>'RF', :artist_id_0=>2, :artist_name=>'YJM'})
171
- end
102
+ ds._fetch = {:id=>1, :artist_id=>2, :name=>'RF', :artist_id_0=>2, :artist_name=>'YJM'}
172
103
  albums = ds.all
173
- @Album.actions.should == [[:fetch, "( LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id))", nil]]
174
- albums.length == 1
104
+ @db.sqls.should == ["SELECT albums.id, albums.artist_id, albums.name, artist.id AS artist_id_0, artist.name AS artist_name FROM albums LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id)"]
105
+ albums.length.should == 1
175
106
  albums.first.artist.save
176
- @Artist.actions.should == [[:update, {:name=>"YJM"}, "(id = 2)", :s2]]
107
+ @db.sqls.should == ["UPDATE artists SET name = 'YJM' WHERE (id = 2) -- s2"]
177
108
  end
178
109
 
179
110
  specify "should have objects retrieved from a specific shard use associated objects from that shard, with modifications to the associated objects using that shard" do
180
111
  album = @Album.server(:s1).first
181
- @Album.actions.should == [[:fetch, nil, :s1]]
112
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1"]
182
113
  album.artist.update(:name=>'AS')
183
- @Artist.actions.should == [[:fetch, "(artists.id = 2)", :s1], [:update, {:name=>"AS"}, "(id = 2)", :s1]]
114
+ @db.sqls.should == ["SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1 -- s1", "UPDATE artists SET name = 'AS' WHERE (id = 2) -- s1"]
184
115
  album.tags.map{|a| a.update(:name=>'SR')}
185
- @Tag.actions.should == [[:fetch, "( INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.album_id = 1)))", :s1], [:update, {:name=>"SR"}, "(id = 3)", :s1]]
186
-
187
- @Album.actions.clear
188
- @Artist.actions.clear
116
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.album_id = 1)) -- s1", "UPDATE tags SET name = 'SR' WHERE (id = 3) -- s1"]
189
117
  @Artist.server(:s2).first.albums.map{|a| a.update(:name=>'MO')}
190
- @Artist.actions.should == [[:fetch, nil, :s2]]
191
- @Album.actions.should == [[:fetch, "(albums.artist_id = 2)", :s2], [:update, {:name=>"MO"}, "(id = 1)", :s2]]
118
+ @db.sqls.should == ["SELECT * FROM artists LIMIT 1 -- s2", "SELECT * FROM albums WHERE (albums.artist_id = 2) -- s2", "UPDATE albums SET name = 'MO' WHERE (id = 1) -- s2"]
192
119
  end
193
120
 
194
121
  specify "should have objects retrieved from a specific shard add associated objects to that shard" do
195
122
  album = @Album.server(:s1).first
196
123
  artist = @Artist.server(:s2).first
197
- @Album.actions.clear
198
- @Artist.actions.clear
124
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "SELECT * FROM artists LIMIT 1 -- s2"]
199
125
 
200
126
  artist.add_album(:name=>'MO')
201
- @Album.actions.should == [[:insert, {:name=>"MO", :artist_id=>2}, :s2], [:fetch, "(id = 1)", :s2]]
202
- @Album.actions.clear
127
+ sqls = @db.sqls
128
+ ["INSERT INTO albums (artist_id, name) VALUES (2, 'MO') -- s2", "INSERT INTO albums (name, artist_id) VALUES ('MO', 2) -- s2"].should include(sqls.shift)
129
+ sqls.should == ["SELECT * FROM albums WHERE (id = 1) LIMIT 1 -- s2"]
203
130
 
204
131
  album.add_tag(:name=>'SR')
205
- @Tag.actions.should == [[:insert, {:name=>"SR"}, :s1], [:fetch, "(id = 1)", :s1]]
206
- @Album.actions.should == [[:insert, {:album_id=>1, :tag_id=>3}, :s1]]
132
+ sqls = @db.sqls
133
+ ["INSERT INTO albums_tags (album_id, tag_id) VALUES (1, 3) -- s1", "INSERT INTO albums_tags (tag_id, album_id) VALUES (3, 1) -- s1"].should include(sqls.pop)
134
+ sqls.should == ["INSERT INTO tags (name) VALUES ('SR') -- s1", "SELECT * FROM tags WHERE (id = 1) LIMIT 1 -- s1", ]
207
135
  end
208
136
 
209
137
  specify "should have objects retrieved from a specific shard remove associated objects from that shard" do
210
138
  album = @Album.server(:s1).first
211
139
  artist = @Artist.server(:s2).first
212
- @Album.actions.clear
213
- @Artist.actions.clear
140
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "SELECT * FROM artists LIMIT 1 -- s2"]
214
141
 
215
142
  artist.remove_album(1)
216
- @Album.actions.should == [[:fetch, "((albums.artist_id = 2) AND (albums.id = 1))", :s2], [:update, {:name=>"RF", :artist_id=>nil}, "(id = 1)", :s2]]
217
- @Album.actions.clear
143
+ sqls = @db.sqls
144
+ ["UPDATE albums SET artist_id = NULL, name = 'RF' WHERE (id = 1) -- s2", "UPDATE albums SET name = 'RF', artist_id = NULL WHERE (id = 1) -- s2"].should include(sqls.pop)
145
+ sqls.should == ["SELECT * FROM albums WHERE ((albums.artist_id = 2) AND (albums.id = 1)) LIMIT 1 -- s2"]
218
146
 
219
147
  album.remove_tag(3)
220
- @Tag.actions.should == [[:fetch, "(tags.id = 3)", :s1]]
221
- @Album.actions.should == [[:delete, "((album_id = 1) AND (tag_id = 3))", :s1]]
148
+ @db.sqls.should == ["SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id = tags.id) AND (albums_tags.album_id = 1)) WHERE (tags.id = 3) LIMIT 1 -- s1", "DELETE FROM albums_tags WHERE ((album_id = 1) AND (tag_id = 3)) -- s1"]
222
149
  end
223
150
 
224
151
  specify "should have objects retrieved from a specific shard remove all associated objects from that shard" do
225
152
  album = @Album.server(:s1).first
226
153
  artist = @Artist.server(:s2).first
227
- @Album.actions.clear
228
- @Artist.actions.clear
154
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "SELECT * FROM artists LIMIT 1 -- s2"]
229
155
 
230
156
  artist.remove_all_albums
231
- @Album.actions.should == [[:update, {:artist_id=>nil}, "(artist_id = 2)", :s2]]
232
- @Album.actions.clear
157
+ @db.sqls.should == ["UPDATE albums SET artist_id = NULL WHERE (artist_id = 2) -- s2"]
233
158
 
234
159
  album.remove_all_tags
235
- @Album.actions.should == [[:delete, "(album_id = 1)", :s1]]
160
+ @db.sqls.should == ["DELETE FROM albums_tags WHERE (album_id = 1) -- s1"]
236
161
  end
237
162
 
238
163
  specify "should not override a server already set on an associated object" do
239
164
  album = @Album.server(:s1).first
240
165
  artist = @Artist.server(:s2).first
241
- @Album.actions.clear
242
- @Artist.actions.clear
166
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "SELECT * FROM artists LIMIT 1 -- s2"]
243
167
 
244
168
  artist.add_album(@Album.load(:id=>4, :name=>'MO').set_server(:s3))
245
- @Album.actions.should == [[:update, {:name=>"MO", :artist_id=>2}, "(id = 4)", :s3]]
246
- @Album.actions.clear
169
+ ["UPDATE albums SET artist_id = 2, name = 'MO' WHERE (id = 4) -- s3", "UPDATE albums SET name = 'MO', artist_id = 2 WHERE (id = 4) -- s3"].should include(@db.sqls.pop)
247
170
 
248
171
  artist.remove_album(@Album.load(:id=>5, :name=>'T', :artist_id=>2).set_server(:s4))
249
172
  # Should select from current object's shard to check existing association, but update associated object's shard
250
- @Album.actions.should == [[:fetch, "((albums.artist_id = 2) AND (id = 5))", :s2], [:update, {:name=>"T", :artist_id=>nil}, "(id = 5)", :s4]]
251
- @Album.actions.clear
173
+ sqls = @db.sqls
174
+ ["UPDATE albums SET artist_id = NULL, name = 'T' WHERE (id = 5) -- s4", "UPDATE albums SET name = 'T', artist_id = NULL WHERE (id = 5) -- s4"].should include(sqls.pop)
175
+ sqls.should == ["SELECT 1 AS one FROM albums WHERE ((albums.artist_id = 2) AND (id = 5)) LIMIT 1 -- s2"]
252
176
  end
253
177
 
254
178
  specify "should be able to set a shard to use for any object using set_server" do
255
179
  @Album.server(:s1).first.set_server(:s2).reload
256
- @Album.actions.should == [[:fetch, nil, :s1], [:fetch, "(id = 1)", :s2]]
180
+ @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "SELECT * FROM albums WHERE (id = 1) LIMIT 1 -- s2"]
257
181
  end
258
182
 
259
183
  specify "should use transactions on the correct shard" do
260
184
  @Album.use_transactions = true
261
185
  @Album.server(:s2).first.save
262
- @Album.actions.should == [[:fetch, nil, :s2], [:update, {:name=>"RF", :artist_id=>2}, "(id = 1)", :s2]]
263
- @db.actions.should == [[:transaction, :s2]]
186
+ sqls = @db.sqls
187
+ ["UPDATE albums SET artist_id = 2, name = 'RF' WHERE (id = 1) -- s2", "UPDATE albums SET name = 'RF', artist_id = 2 WHERE (id = 1) -- s2"].should include(sqls.slice!(2))
188
+ sqls.should == ["SELECT * FROM albums LIMIT 1 -- s2", "BEGIN -- s2", "COMMIT -- s2"]
264
189
  end
265
190
 
266
- specify "should use not override shard given when saving" do
191
+ specify "should use override current shard when saving with given :server option" do
267
192
  @Album.use_transactions = true
268
193
  @Album.server(:s2).first.save(:server=>:s1)
269
- @Album.actions.should == [[:fetch, nil, :s2], [:update, {:name=>"RF", :artist_id=>2}, "(id = 1)", :s2]]
270
- @db.actions.should == [[:transaction, :s1]]
194
+ sqls = @db.sqls
195
+ ["UPDATE albums SET artist_id = 2, name = 'RF' WHERE (id = 1) -- s1", "UPDATE albums SET name = 'RF', artist_id = 2 WHERE (id = 1) -- s1"].should include(sqls.slice!(2))
196
+ sqls.should == ["SELECT * FROM albums LIMIT 1 -- s2", "BEGIN -- s1", "COMMIT -- s1"]
271
197
  end
272
198
  end
@@ -3,9 +3,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
3
3
  describe Sequel::Model, "#sti_key" do
4
4
  before do
5
5
  class ::StiTest < Sequel::Model
6
- def kind; self[:kind]; end
7
- def kind=(x); self[:kind] = x; end
8
- def _refresh(x); end
6
+ columns :id, :kind, :blah
9
7
  plugin :single_table_inheritance, :kind
10
8
  end
11
9
  class ::StiTestSub1 < StiTest
@@ -22,7 +20,7 @@ describe Sequel::Model, "#sti_key" do
22
20
  end
23
21
 
24
22
  specify "should have simple_table = nil" do
25
- StiTest.simple_table.should == nil
23
+ StiTest.simple_table.should == "sti_tests"
26
24
  StiTestSub1.simple_table.should == nil
27
25
  end
28
26
 
@@ -30,15 +28,9 @@ describe Sequel::Model, "#sti_key" do
30
28
  StiTest.plugin :single_table_inheritance, :blah
31
29
  Object.send(:remove_const, :StiTestSub1)
32
30
  Object.send(:remove_const, :StiTestSub2)
33
- class ::StiTestSub1 < StiTest
34
- end
35
- class ::StiTestSub2 < StiTest
36
- end
37
- def @ds.fetch_rows(sql)
38
- yield({:blah=>'StiTest'})
39
- yield({:blah=>'StiTestSub1'})
40
- yield({:blah=>'StiTestSub2'})
41
- end
31
+ class ::StiTestSub1 < StiTest; end
32
+ class ::StiTestSub2 < StiTest; end
33
+ @ds._fetch = [{:blah=>'StiTest'}, {:blah=>'StiTestSub1'}, {:blah=>'StiTestSub2'}]
42
34
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
43
35
  StiTest.dataset.sql.should == "SELECT * FROM sti_tests"
44
36
  StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.blah IN ('StiTestSub1'))"
@@ -46,18 +38,23 @@ describe Sequel::Model, "#sti_key" do
46
38
  end
47
39
 
48
40
  it "should return rows with the correct class based on the polymorphic_key value" do
49
- def @ds.fetch_rows(sql)
50
- yield({:kind=>'StiTest'})
51
- yield({:kind=>'StiTestSub1'})
52
- yield({:kind=>'StiTestSub2'})
53
- end
41
+ @ds._fetch = [{:kind=>'StiTest'}, {:kind=>'StiTestSub1'}, {:kind=>'StiTestSub2'}]
54
42
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
55
43
  end
56
44
 
45
+ it "should return rows with the correct class based on the polymorphic_key value when retreiving by primary key" do
46
+ @ds._fetch = [{:kind=>'StiTestSub1'}]
47
+ StiTest[1].class.should == StiTestSub1
48
+ end
49
+
50
+ it "should return rows with the correct class for subclasses based on the polymorphic_key value" do
51
+ class ::StiTestSub1Sub < StiTestSub1; end
52
+ StiTestSub1.dataset._fetch = [{:kind=>'StiTestSub1'}, {:kind=>'StiTestSub1Sub'}]
53
+ StiTestSub1.all.collect{|x| x.class}.should == [StiTestSub1, StiTestSub1Sub]
54
+ end
55
+
57
56
  it "should fallback to the main class if the given class does not exist" do
58
- def @ds.fetch_rows(sql)
59
- yield({:kind=>'StiTestSub3'})
60
- end
57
+ @ds._fetch = {:kind=>'StiTestSub3'}
61
58
  StiTest.all.collect{|x| x.class}.should == [StiTest]
62
59
  end
63
60
 
@@ -68,10 +65,7 @@ describe Sequel::Model, "#sti_key" do
68
65
  Object
69
66
  end
70
67
  StiTest.plugin :single_table_inheritance, :kind
71
- def @ds.fetch_rows(sql)
72
- yield({:kind=>''})
73
- yield({:kind=>nil})
74
- end
68
+ @ds._fetch = [{:kind=>''}, {:kind=>nil}]
75
69
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTest]
76
70
  called.should == false
77
71
  end
@@ -80,19 +74,19 @@ describe Sequel::Model, "#sti_key" do
80
74
  StiTest.new.save
81
75
  StiTestSub1.new.save
82
76
  StiTestSub2.new.save
83
- MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTest')", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub2')"]
77
+ MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTest')", "SELECT * FROM sti_tests WHERE (id = 10) LIMIT 1", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "SELECT * FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub1')) AND (id = 10)) LIMIT 1", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub2')", "SELECT * FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub2')) AND (id = 10)) LIMIT 1"]
84
78
  end
85
79
 
86
80
  it "should have the before_create hook not override an existing value" do
87
81
  StiTest.create(:kind=>'StiTestSub1')
88
- MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')"]
82
+ MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "SELECT * FROM sti_tests WHERE (id = 10) LIMIT 1"]
89
83
  end
90
84
 
91
85
  it "should have the before_create hook handle columns with the same name as existing method names" do
92
86
  StiTest.plugin :single_table_inheritance, :type
93
87
  StiTest.columns :id, :type
94
88
  StiTest.create
95
- MODEL_DB.sqls.should == ["INSERT INTO sti_tests (type) VALUES ('StiTest')"]
89
+ MODEL_DB.sqls.should == ["INSERT INTO sti_tests (type) VALUES ('StiTest')", "SELECT * FROM sti_tests WHERE (id = 10) LIMIT 1"]
96
90
  end
97
91
 
98
92
  it "should add a filter to model datasets inside subclasses hook to only retreive objects with the matching key" do
@@ -118,7 +112,7 @@ describe Sequel::Model, "#sti_key" do
118
112
  before do
119
113
  class ::StiTest2 < Sequel::Model
120
114
  columns :id, :kind
121
- def _refresh(x); end
115
+ def _save_refresh; end
122
116
  end
123
117
  end
124
118
  after do
@@ -5,7 +5,7 @@ describe "Sequel::Plugins::SkipCreateRefresh" do
5
5
  c = Class.new(Sequel::Model(:a))
6
6
  c.columns :id, :x
7
7
  c.db.reset
8
- c.dataset.meta_def(:insert){|*a| super(*a); 2}
8
+ c.instance_dataset.meta_def(:insert){|*a| super(*a); 2}
9
9
  c.create(:x=>1)
10
10
  c.db.sqls.should == ['INSERT INTO a (x) VALUES (1)', 'SELECT * FROM a WHERE (id = 2) LIMIT 1']
11
11
 
@@ -1,80 +1,45 @@
1
1
  require 'rubygems'
2
- unless Object.const_defined?('Sequel')
3
- $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
4
- require 'sequel/core'
5
- end
6
- unless Sequel.const_defined?('Model')
7
- $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
8
- require 'sequel/model'
9
- end
10
-
11
- Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot')
12
- {:hook_class_methods=>[], :schema=>[], :validation_class_methods=>[]}.each{|p, opts| Sequel::Model.plugin(p, *opts)}
13
-
14
- def skip_warn(s)
15
- warn "Skipping test of #{s}" if ENV["SKIPPED_TEST_WARN"]
16
- end
17
2
 
18
- class MockDataset < Sequel::Dataset
19
- def insert(*args)
20
- @db.execute insert_sql(*args)
21
- end
22
-
23
- def update(*args)
24
- @db.execute update_sql(*args)
25
- 1
26
- end
27
-
28
- def delete(*args)
29
- @db.execute delete_sql(*args)
30
- 1
31
- end
32
-
33
- def fetch_rows(sql)
34
- return if sql =~ /information_schema/
35
- @db.execute(sql)
36
- yield({:id => 1, :x => 1})
3
+ if defined?(RSpec)
4
+ begin
5
+ require 'rspec/expectations'
6
+ rescue LoadError
7
+ nil
37
8
  end
9
+ end
38
10
 
39
- def quoted_identifier(c)
40
- "\"#{c}\""
41
- end
11
+ unless Object.const_defined?('Sequel') && Sequel.const_defined?('Model')
12
+ $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
13
+ require 'sequel/no_core_ext'
42
14
  end
43
15
 
44
- class MockDatabase < Sequel::Database
45
- @@quote_identifiers = false
46
- self.identifier_input_method = nil
47
- self.identifier_output_method = nil
48
- attr_reader :sqls
49
-
50
- def execute(sql, opts={})
51
- @sqls ||= []
52
- @sqls << sql
53
- end
54
-
55
- def new_sqls
56
- s = sqls
57
- reset
58
- s
59
- end
16
+ begin
17
+ # Attempt to load ActiveSupport inflector first, so Sequel inflector
18
+ # can override it.
19
+ require 'active_support/inflector'
20
+ require 'active_support/core_ext/string/inflections'
21
+ rescue LoadError
22
+ nil
23
+ end
60
24
 
61
- def reset
62
- @sqls = []
63
- end
25
+ # Load most extensions by default, so that any conflicts are easily detectable.
26
+ Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot columns_introspection server_block arbitrary_servers pg_auto_parameterize pg_statement_cache pg_array pg_array_ops pg_hstore pg_hstore_ops pg_range pg_range_ops pg_json pg_inet pg_row pg_row_ops schema_caching null_dataset select_remove query_literals eval_inspect')
64
27
 
65
- def schema(table_name, opts)
66
- [[:id, {:primary_key=>true}]]
67
- end
28
+ Sequel::Dataset.introspect_all_columns if ENV['SEQUEL_COLUMNS_INTROSPECTION']
68
29
 
69
- def transaction(opts={}); yield; end
70
-
71
- def dataset(opts=nil); MockDataset.new(self, opts); end
30
+ def skip_warn(s)
31
+ warn "Skipping test of #{s}" if ENV["SKIPPED_TEST_WARN"]
72
32
  end
73
33
 
34
+ Sequel.quote_identifiers = false
35
+ Sequel.identifier_input_method = nil
36
+ Sequel.identifier_output_method = nil
37
+
74
38
  class << Sequel::Model
39
+ attr_writer :db_schema
75
40
  alias orig_columns columns
76
41
  def columns(*cols)
77
- return @columns if cols.empty?
42
+ return super if cols.empty?
78
43
  define_method(:columns){cols}
79
44
  @dataset.instance_variable_set(:@columns, cols) if @dataset
80
45
  def_column_accessor(*cols)
@@ -82,10 +47,12 @@ class << Sequel::Model
82
47
  @db_schema = {}
83
48
  cols.each{|c| @db_schema[c] = {}}
84
49
  end
85
- def simple_table
86
- nil
87
- end
88
50
  end
89
51
 
90
- Sequel::Model.db = MODEL_DB = MockDatabase.new
91
52
  Sequel::Model.use_transactions = false
53
+ Sequel::Model.cache_anonymous_models = false
54
+
55
+ db = Sequel.mock(:fetch=>{:id => 1, :x => 1}, :numrows=>1, :autoid=>proc{|sql| 10})
56
+ def db.schema(*) [[:id, {:primary_key=>true}]] end
57
+ def db.reset() sqls end
58
+ Sequel::Model.db = MODEL_DB = db
@@ -0,0 +1,24 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
+
3
+ describe "split_array_nil extension" do
4
+ before do
5
+ @ds = Sequel.mock[:table].extension(:split_array_nil)
6
+ end
7
+
8
+ specify "should split IN with nil in array into separate OR IS NULL clause" do
9
+ @ds.filter(:a=>[1, nil]).sql.should == "SELECT * FROM table WHERE ((a IN (1)) OR (a IS NULL))"
10
+ end
11
+
12
+ specify "should split NOT IN with nil in array into separate AND IS NOT NULL clause" do
13
+ @ds.exclude(:a=>[1, nil]).sql.should == "SELECT * FROM table WHERE ((a NOT IN (1)) AND (a IS NOT NULL))"
14
+ end
15
+
16
+ specify "should not affect other IN/NOT in clauses" do
17
+ @ds.filter(:a=>[1, 2]).sql.should == "SELECT * FROM table WHERE (a IN (1, 2))"
18
+ @ds.exclude(:a=>[1, 2]).sql.should == "SELECT * FROM table WHERE (a NOT IN (1, 2))"
19
+ end
20
+
21
+ specify "should not affect other types of filters clauses" do
22
+ @ds.filter(:a=>1).sql.should == "SELECT * FROM table WHERE (a = 1)"
23
+ end
24
+ end