sequel 3.48.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (267) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +114 -0
  3. data/Rakefile +10 -7
  4. data/doc/association_basics.rdoc +25 -23
  5. data/doc/code_order.rdoc +7 -0
  6. data/doc/core_extensions.rdoc +0 -10
  7. data/doc/object_model.rdoc +4 -1
  8. data/doc/querying.rdoc +3 -3
  9. data/doc/release_notes/4.0.0.txt +262 -0
  10. data/doc/security.rdoc +0 -28
  11. data/doc/testing.rdoc +8 -14
  12. data/lib/sequel/adapters/ado.rb +7 -11
  13. data/lib/sequel/adapters/ado/access.rb +8 -8
  14. data/lib/sequel/adapters/ado/mssql.rb +4 -4
  15. data/lib/sequel/adapters/amalgalite.rb +6 -6
  16. data/lib/sequel/adapters/cubrid.rb +7 -7
  17. data/lib/sequel/adapters/db2.rb +5 -9
  18. data/lib/sequel/adapters/dbi.rb +2 -6
  19. data/lib/sequel/adapters/do.rb +4 -4
  20. data/lib/sequel/adapters/firebird.rb +4 -4
  21. data/lib/sequel/adapters/ibmdb.rb +8 -8
  22. data/lib/sequel/adapters/informix.rb +2 -10
  23. data/lib/sequel/adapters/jdbc.rb +17 -17
  24. data/lib/sequel/adapters/jdbc/as400.rb +2 -2
  25. data/lib/sequel/adapters/jdbc/cubrid.rb +1 -1
  26. data/lib/sequel/adapters/jdbc/db2.rb +1 -1
  27. data/lib/sequel/adapters/jdbc/derby.rb +1 -1
  28. data/lib/sequel/adapters/jdbc/h2.rb +2 -2
  29. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
  30. data/lib/sequel/adapters/jdbc/informix.rb +1 -1
  31. data/lib/sequel/adapters/jdbc/mssql.rb +2 -2
  32. data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
  33. data/lib/sequel/adapters/jdbc/oracle.rb +5 -1
  34. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -3
  35. data/lib/sequel/adapters/jdbc/sqlite.rb +3 -3
  36. data/lib/sequel/adapters/jdbc/transactions.rb +3 -3
  37. data/lib/sequel/adapters/mock.rb +7 -7
  38. data/lib/sequel/adapters/mysql.rb +3 -3
  39. data/lib/sequel/adapters/mysql2.rb +4 -4
  40. data/lib/sequel/adapters/odbc.rb +2 -6
  41. data/lib/sequel/adapters/odbc/mssql.rb +1 -1
  42. data/lib/sequel/adapters/openbase.rb +1 -5
  43. data/lib/sequel/adapters/oracle.rb +13 -17
  44. data/lib/sequel/adapters/postgres.rb +20 -25
  45. data/lib/sequel/adapters/shared/cubrid.rb +3 -3
  46. data/lib/sequel/adapters/shared/db2.rb +2 -2
  47. data/lib/sequel/adapters/shared/firebird.rb +7 -7
  48. data/lib/sequel/adapters/shared/mssql.rb +9 -9
  49. data/lib/sequel/adapters/shared/mysql.rb +29 -13
  50. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +7 -7
  51. data/lib/sequel/adapters/shared/oracle.rb +22 -13
  52. data/lib/sequel/adapters/shared/postgres.rb +61 -46
  53. data/lib/sequel/adapters/shared/sqlite.rb +9 -9
  54. data/lib/sequel/adapters/sqlite.rb +17 -11
  55. data/lib/sequel/adapters/swift.rb +3 -3
  56. data/lib/sequel/adapters/swift/mysql.rb +1 -1
  57. data/lib/sequel/adapters/swift/sqlite.rb +1 -1
  58. data/lib/sequel/adapters/tinytds.rb +8 -8
  59. data/lib/sequel/ast_transformer.rb +3 -1
  60. data/lib/sequel/connection_pool.rb +4 -2
  61. data/lib/sequel/connection_pool/sharded_single.rb +2 -2
  62. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -5
  63. data/lib/sequel/connection_pool/threaded.rb +7 -7
  64. data/lib/sequel/core.rb +4 -67
  65. data/lib/sequel/database.rb +1 -0
  66. data/lib/sequel/database/connecting.rb +2 -8
  67. data/lib/sequel/database/dataset.rb +2 -7
  68. data/lib/sequel/database/dataset_defaults.rb +0 -18
  69. data/lib/sequel/database/features.rb +4 -4
  70. data/lib/sequel/database/misc.rb +6 -8
  71. data/lib/sequel/database/query.rb +5 -61
  72. data/lib/sequel/database/schema_generator.rb +22 -20
  73. data/lib/sequel/database/schema_methods.rb +48 -20
  74. data/lib/sequel/database/transactions.rb +7 -17
  75. data/lib/sequel/dataset.rb +2 -0
  76. data/lib/sequel/dataset/actions.rb +23 -91
  77. data/lib/sequel/dataset/features.rb +1 -4
  78. data/lib/sequel/dataset/graph.rb +3 -47
  79. data/lib/sequel/dataset/misc.rb +4 -33
  80. data/lib/sequel/dataset/prepared_statements.rb +3 -1
  81. data/lib/sequel/dataset/query.rb +116 -240
  82. data/lib/sequel/dataset/sql.rb +19 -97
  83. data/lib/sequel/deprecated.rb +0 -16
  84. data/lib/sequel/exceptions.rb +0 -3
  85. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  86. data/lib/sequel/extensions/columns_introspection.rb +1 -12
  87. data/lib/sequel/extensions/constraint_validations.rb +3 -3
  88. data/lib/sequel/extensions/core_extensions.rb +0 -9
  89. data/lib/sequel/extensions/date_arithmetic.rb +1 -2
  90. data/lib/sequel/extensions/graph_each.rb +11 -0
  91. data/lib/sequel/extensions/migration.rb +5 -5
  92. data/lib/sequel/extensions/null_dataset.rb +11 -13
  93. data/lib/sequel/extensions/pagination.rb +3 -6
  94. data/lib/sequel/extensions/pg_array.rb +6 -4
  95. data/lib/sequel/extensions/pg_array_ops.rb +35 -1
  96. data/lib/sequel/extensions/pg_json.rb +12 -2
  97. data/lib/sequel/extensions/pg_json_ops.rb +266 -0
  98. data/lib/sequel/extensions/pg_range.rb +2 -2
  99. data/lib/sequel/extensions/pg_range_ops.rb +0 -8
  100. data/lib/sequel/extensions/pg_row.rb +2 -2
  101. data/lib/sequel/extensions/pretty_table.rb +0 -4
  102. data/lib/sequel/extensions/query.rb +3 -8
  103. data/lib/sequel/extensions/schema_caching.rb +0 -7
  104. data/lib/sequel/extensions/schema_dumper.rb +10 -17
  105. data/lib/sequel/extensions/select_remove.rb +0 -4
  106. data/lib/sequel/extensions/set_overrides.rb +28 -0
  107. data/lib/sequel/extensions/to_dot.rb +6 -10
  108. data/lib/sequel/model.rb +6 -7
  109. data/lib/sequel/model/associations.rb +127 -182
  110. data/lib/sequel/model/base.rb +88 -211
  111. data/lib/sequel/model/errors.rb +0 -13
  112. data/lib/sequel/model/plugins.rb +2 -2
  113. data/lib/sequel/no_core_ext.rb +0 -1
  114. data/lib/sequel/plugins/after_initialize.rb +11 -17
  115. data/lib/sequel/plugins/association_autoreloading.rb +1 -47
  116. data/lib/sequel/plugins/association_dependencies.rb +2 -2
  117. data/lib/sequel/plugins/auto_validations.rb +2 -8
  118. data/lib/sequel/plugins/blacklist_security.rb +32 -2
  119. data/lib/sequel/plugins/caching.rb +1 -1
  120. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  121. data/lib/sequel/plugins/composition.rb +10 -8
  122. data/lib/sequel/plugins/constraint_validations.rb +2 -2
  123. data/lib/sequel/plugins/dataset_associations.rb +4 -0
  124. data/lib/sequel/plugins/defaults_setter.rb +8 -6
  125. data/lib/sequel/plugins/dirty.rb +6 -6
  126. data/lib/sequel/plugins/force_encoding.rb +13 -8
  127. data/lib/sequel/plugins/hook_class_methods.rb +1 -7
  128. data/lib/sequel/plugins/json_serializer.rb +13 -74
  129. data/lib/sequel/plugins/lazy_attributes.rb +2 -4
  130. data/lib/sequel/plugins/list.rb +1 -1
  131. data/lib/sequel/plugins/many_through_many.rb +4 -11
  132. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +1 -49
  133. data/lib/sequel/plugins/nested_attributes.rb +1 -1
  134. data/lib/sequel/plugins/optimistic_locking.rb +3 -5
  135. data/lib/sequel/plugins/pg_array_associations.rb +453 -0
  136. data/lib/sequel/plugins/pg_typecast_on_load.rb +23 -7
  137. data/lib/sequel/plugins/prepared_statements.rb +1 -1
  138. data/lib/sequel/plugins/prepared_statements_associations.rb +20 -14
  139. data/lib/sequel/plugins/prepared_statements_safe.rb +2 -2
  140. data/lib/sequel/plugins/rcte_tree.rb +1 -1
  141. data/lib/sequel/plugins/serialization.rb +5 -4
  142. data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
  143. data/lib/sequel/plugins/sharding.rb +7 -1
  144. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  145. data/lib/sequel/plugins/timestamps.rb +1 -1
  146. data/lib/sequel/plugins/touch.rb +2 -2
  147. data/lib/sequel/plugins/tree.rb +1 -1
  148. data/lib/sequel/plugins/typecast_on_load.rb +19 -4
  149. data/lib/sequel/plugins/validation_class_methods.rb +0 -30
  150. data/lib/sequel/plugins/validation_helpers.rb +13 -31
  151. data/lib/sequel/plugins/xml_serializer.rb +18 -57
  152. data/lib/sequel/sql.rb +20 -22
  153. data/lib/sequel/version.rb +2 -2
  154. data/spec/adapters/db2_spec.rb +14 -23
  155. data/spec/adapters/firebird_spec.rb +25 -29
  156. data/spec/adapters/informix_spec.rb +11 -14
  157. data/spec/adapters/mssql_spec.rb +71 -77
  158. data/spec/adapters/mysql_spec.rb +165 -172
  159. data/spec/adapters/oracle_spec.rb +36 -39
  160. data/spec/adapters/postgres_spec.rb +175 -100
  161. data/spec/adapters/spec_helper.rb +13 -11
  162. data/spec/adapters/sqlite_spec.rb +36 -44
  163. data/spec/core/connection_pool_spec.rb +2 -1
  164. data/spec/core/database_spec.rb +55 -55
  165. data/spec/core/dataset_spec.rb +45 -249
  166. data/spec/core/deprecated_spec.rb +0 -8
  167. data/spec/core/expression_filters_spec.rb +23 -5
  168. data/spec/core/object_graph_spec.rb +4 -66
  169. data/spec/core/schema_spec.rb +35 -12
  170. data/spec/core/spec_helper.rb +3 -2
  171. data/spec/core_extensions_spec.rb +17 -19
  172. data/spec/extensions/arbitrary_servers_spec.rb +2 -3
  173. data/spec/extensions/association_dependencies_spec.rb +14 -14
  174. data/spec/extensions/auto_validations_spec.rb +7 -0
  175. data/spec/extensions/blacklist_security_spec.rb +5 -5
  176. data/spec/extensions/blank_spec.rb +2 -0
  177. data/spec/extensions/class_table_inheritance_spec.rb +2 -2
  178. data/spec/extensions/columns_introspection_spec.rb +2 -29
  179. data/spec/extensions/composition_spec.rb +10 -17
  180. data/spec/extensions/core_refinements_spec.rb +5 -1
  181. data/spec/extensions/dataset_associations_spec.rb +18 -0
  182. data/spec/extensions/date_arithmetic_spec.rb +2 -2
  183. data/spec/extensions/defaults_setter_spec.rb +9 -9
  184. data/spec/extensions/dirty_spec.rb +0 -5
  185. data/spec/extensions/eval_inspect_spec.rb +2 -0
  186. data/spec/extensions/force_encoding_spec.rb +2 -18
  187. data/spec/extensions/hash_aliases_spec.rb +8 -0
  188. data/spec/extensions/hook_class_methods_spec.rb +39 -58
  189. data/spec/extensions/inflector_spec.rb +2 -0
  190. data/spec/extensions/instance_filters_spec.rb +8 -8
  191. data/spec/extensions/json_serializer_spec.rb +1 -41
  192. data/spec/extensions/list_spec.rb +1 -1
  193. data/spec/extensions/many_through_many_spec.rb +106 -109
  194. data/spec/extensions/migration_spec.rb +2 -0
  195. data/spec/extensions/named_timezones_spec.rb +1 -0
  196. data/spec/extensions/pg_array_associations_spec.rb +603 -0
  197. data/spec/extensions/pg_array_ops_spec.rb +25 -0
  198. data/spec/extensions/pg_array_spec.rb +9 -1
  199. data/spec/extensions/pg_hstore_ops_spec.rb +13 -0
  200. data/spec/extensions/pg_hstore_spec.rb +1 -0
  201. data/spec/extensions/pg_json_ops_spec.rb +131 -0
  202. data/spec/extensions/pg_json_spec.rb +10 -4
  203. data/spec/extensions/pg_range_ops_spec.rb +2 -5
  204. data/spec/extensions/pg_range_spec.rb +6 -2
  205. data/spec/extensions/pg_row_ops_spec.rb +2 -0
  206. data/spec/extensions/prepared_statements_associations_spec.rb +26 -5
  207. data/spec/extensions/rcte_tree_spec.rb +15 -15
  208. data/spec/extensions/schema_dumper_spec.rb +0 -1
  209. data/spec/extensions/schema_spec.rb +9 -9
  210. data/spec/extensions/serialization_modification_detection_spec.rb +1 -1
  211. data/spec/extensions/serialization_spec.rb +18 -29
  212. data/spec/extensions/set_overrides_spec.rb +4 -0
  213. data/spec/extensions/{many_to_one_pk_lookup_spec.rb → shared_caching_spec.rb} +1 -4
  214. data/spec/extensions/single_table_inheritance_spec.rb +4 -4
  215. data/spec/extensions/spec_helper.rb +8 -9
  216. data/spec/extensions/sql_expr_spec.rb +2 -0
  217. data/spec/extensions/string_date_time_spec.rb +2 -0
  218. data/spec/extensions/string_stripper_spec.rb +2 -0
  219. data/spec/extensions/tactical_eager_loading_spec.rb +12 -12
  220. data/spec/extensions/thread_local_timezones_spec.rb +2 -0
  221. data/spec/extensions/timestamps_spec.rb +1 -1
  222. data/spec/extensions/to_dot_spec.rb +1 -1
  223. data/spec/extensions/touch_spec.rb +24 -24
  224. data/spec/extensions/tree_spec.rb +7 -7
  225. data/spec/extensions/typecast_on_load_spec.rb +8 -1
  226. data/spec/extensions/update_primary_key_spec.rb +10 -10
  227. data/spec/extensions/validation_class_methods_spec.rb +10 -39
  228. data/spec/extensions/validation_helpers_spec.rb +29 -47
  229. data/spec/extensions/xml_serializer_spec.rb +1 -23
  230. data/spec/integration/associations_test.rb +231 -40
  231. data/spec/integration/database_test.rb +1 -1
  232. data/spec/integration/dataset_test.rb +64 -64
  233. data/spec/integration/eager_loader_test.rb +28 -28
  234. data/spec/integration/migrator_test.rb +1 -1
  235. data/spec/integration/model_test.rb +2 -2
  236. data/spec/integration/plugin_test.rb +21 -21
  237. data/spec/integration/prepared_statement_test.rb +7 -7
  238. data/spec/integration/schema_test.rb +115 -110
  239. data/spec/integration/spec_helper.rb +17 -27
  240. data/spec/integration/timezone_test.rb +1 -1
  241. data/spec/integration/transaction_test.rb +10 -10
  242. data/spec/integration/type_test.rb +2 -2
  243. data/spec/model/association_reflection_spec.rb +2 -28
  244. data/spec/model/associations_spec.rb +239 -188
  245. data/spec/model/base_spec.rb +27 -68
  246. data/spec/model/dataset_methods_spec.rb +4 -4
  247. data/spec/model/eager_loading_spec.rb +160 -172
  248. data/spec/model/hooks_spec.rb +62 -79
  249. data/spec/model/model_spec.rb +36 -51
  250. data/spec/model/plugins_spec.rb +5 -19
  251. data/spec/model/record_spec.rb +125 -151
  252. data/spec/model/spec_helper.rb +8 -6
  253. data/spec/model/validations_spec.rb +4 -17
  254. data/spec/spec_config.rb +2 -10
  255. metadata +50 -56
  256. data/lib/sequel/deprecated_core_extensions.rb +0 -135
  257. data/lib/sequel/extensions/pg_auto_parameterize.rb +0 -185
  258. data/lib/sequel/extensions/pg_statement_cache.rb +0 -318
  259. data/lib/sequel/plugins/identity_map.rb +0 -260
  260. data/lib/sequel_core.rb +0 -2
  261. data/lib/sequel_model.rb +0 -2
  262. data/spec/extensions/association_autoreloading_spec.rb +0 -102
  263. data/spec/extensions/identity_map_spec.rb +0 -337
  264. data/spec/extensions/pg_auto_parameterize_spec.rb +0 -70
  265. data/spec/extensions/pg_statement_cache_spec.rb +0 -208
  266. data/spec/rcov.opts +0 -8
  267. data/spec/spec_config.rb.example +0 -10
@@ -1,5 +1,7 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
+ Sequel.extension :migration
4
+
3
5
  describe "Migration.descendants" do
4
6
  before do
5
7
  Sequel::Migration.descendants.clear
@@ -5,6 +5,7 @@ begin
5
5
  rescue LoadError => e
6
6
  skip_warn "named_timezones_spec: can't load tzinfo (#{e.class}: #{e})"
7
7
  else
8
+ Sequel.extension :thread_local_timezones
8
9
  Sequel.extension :named_timezones
9
10
  Sequel.datetime_class = Time
10
11
 
@@ -0,0 +1,603 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe Sequel::Model, "pg_array_associations" do
4
+ before do
5
+ class ::Artist < Sequel::Model
6
+ attr_accessor :yyy
7
+ columns :id, :tag_ids
8
+ plugin :pg_array_associations
9
+ pg_array_to_many :tags
10
+ end
11
+ class ::Tag < Sequel::Model
12
+ columns :id
13
+ plugin :pg_array_associations
14
+ many_to_pg_array :artists
15
+ def id3
16
+ id*3
17
+ end
18
+ end
19
+ @c1 = Artist
20
+ @c2 = Tag
21
+ @c1.dataset._fetch = {:id=>1, :tag_ids=>Sequel.pg_array([1,2,3])}
22
+ @c2.dataset._fetch = {:id=>2}
23
+ @o1 = @c1.first
24
+ @o2 = @c2.first
25
+ @n1 = @c1.new
26
+ @n2 = @c2.new
27
+ DB.reset
28
+ end
29
+ after do
30
+ Object.send(:remove_const, :Artist)
31
+ Object.send(:remove_const, :Tag)
32
+ end
33
+
34
+ it "should populate :key_hash and :id_map option correctly for custom eager loaders" do
35
+ khs = []
36
+ pr = proc{|h| khs << [h[:key_hash], h[:id_map]]}
37
+ @c1.pg_array_to_many :tags, :clone=>:tags, :eager_loader=>pr
38
+ @c2.many_to_pg_array :artists, :clone=>:artists, :eager_loader=>pr
39
+ @c1.eager(:tags).all
40
+ @c2.eager(:artists).all
41
+ khs.should == [[{}, nil], [{:id=>{2=>[Tag.load(:id=>2)]}}, {2=>[Tag.load(:id=>2)]}]]
42
+ end
43
+
44
+ it "should not issue queries if the object cannot have associated objects" do
45
+ @n1.tags.should == []
46
+ @c1.load(:tag_ids=>[]).tags.should == []
47
+ @n2.artists.should == []
48
+ DB.sqls.should == []
49
+ end
50
+
51
+ it "should use correct SQL when loading associations lazily" do
52
+ @o1.tags.should == [@o2]
53
+ @o2.artists.should == [@o1]
54
+ DB.sqls.should == ["SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))", "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2])"]
55
+ end
56
+
57
+ it "should accept :primary_key option for primary keys to use in current and associated table" do
58
+ @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>Sequel./(:id, 3)
59
+ @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>:id3
60
+ @o1.tags_dataset.sql.should == "SELECT * FROM tags WHERE ((tags.id / 3) IN (1, 2, 3))"
61
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[6])"
62
+ end
63
+
64
+ it "should allowing filtering by associations" do
65
+ @c1.filter(:tags=>@o2).sql.should == "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2])"
66
+ @c2.filter(:artists=>@o1).sql.should == "SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))"
67
+ end
68
+
69
+ it "should allowing excluding by associations" do
70
+ @c1.exclude(:tags=>@o2).sql.should == "SELECT * FROM artists WHERE (NOT (artists.tag_ids @> ARRAY[2]) OR (artists.tag_ids IS NULL))"
71
+ @c2.exclude(:artists=>@o1).sql.should == "SELECT * FROM tags WHERE ((tags.id NOT IN (1, 2, 3)) OR (tags.id IS NULL))"
72
+ end
73
+
74
+ it "should allowing filtering by multiple associations" do
75
+ @c1.filter(:tags=>[@c2.load(:id=>1), @c2.load(:id=>2)]).sql.should == "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[1,2])"
76
+ @c2.filter(:artists=>[@c1.load(:tag_ids=>Sequel.pg_array([3, 4])), @c1.load(:tag_ids=>Sequel.pg_array([4, 5]))]).sql.should == "SELECT * FROM tags WHERE (tags.id IN (3, 4, 5))"
77
+ end
78
+
79
+ it "should allowing excluding by multiple associations" do
80
+ @c1.exclude(:tags=>[@c2.load(:id=>1), @c2.load(:id=>2)]).sql.should == "SELECT * FROM artists WHERE (NOT (artists.tag_ids && ARRAY[1,2]) OR (artists.tag_ids IS NULL))"
81
+ @c2.exclude(:artists=>[@c1.load(:tag_ids=>Sequel.pg_array([3, 4])), @c1.load(:tag_ids=>Sequel.pg_array([4, 5]))]).sql.should == "SELECT * FROM tags WHERE ((tags.id NOT IN (3, 4, 5)) OR (tags.id IS NULL))"
82
+ end
83
+
84
+ it "should allowing filtering/excluding associations with NULL or empty values" do
85
+ @c1.filter(:tags=>@c2.new).sql.should == 'SELECT * FROM artists WHERE \'f\''
86
+ @c1.exclude(:tags=>@c2.new).sql.should == 'SELECT * FROM artists WHERE \'t\''
87
+ @c2.filter(:artists=>@c1.new).sql.should == 'SELECT * FROM tags WHERE \'f\''
88
+ @c2.exclude(:artists=>@c1.new).sql.should == 'SELECT * FROM tags WHERE \'t\''
89
+
90
+ @c2.filter(:artists=>@c1.load(:tag_ids=>[])).sql.should == 'SELECT * FROM tags WHERE \'f\''
91
+ @c2.exclude(:artists=>@c1.load(:tag_ids=>[])).sql.should == 'SELECT * FROM tags WHERE \'t\''
92
+
93
+ @c1.filter(:tags=>[@c2.new, @c2.load(:id=>2)]).sql.should == "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2])"
94
+ @c2.filter(:artists=>[@c1.load(:tag_ids=>Sequel.pg_array([3, 4])), @c1.new]).sql.should == "SELECT * FROM tags WHERE (tags.id IN (3, 4))"
95
+ end
96
+
97
+ it "should allowing filtering by association datasets" do
98
+ @c1.filter(:tags=>@c2.where(:id=>1)).sql.should == "SELECT * FROM artists WHERE coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE (id = 1))), 'f')"
99
+ @c2.filter(:artists=>@c1.where(:id=>1)).sql.should == "SELECT * FROM tags WHERE (tags.id IN (SELECT unnest(artists.tag_ids) FROM artists WHERE (id = 1)))"
100
+ end
101
+
102
+ it "should allowing excluding by association datasets" do
103
+ @c1.exclude(:tags=>@c2.where(:id=>1)).sql.should == "SELECT * FROM artists WHERE (NOT coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE (id = 1))), 'f') OR (artists.tag_ids IS NULL))"
104
+ @c2.exclude(:artists=>@c1.where(:id=>1)).sql.should == "SELECT * FROM tags WHERE ((tags.id NOT IN (SELECT unnest(artists.tag_ids) FROM artists WHERE (id = 1))) OR (tags.id IS NULL))"
105
+ end
106
+
107
+ it "filter by associations should respect key options" do
108
+ @c1.class_eval{def tag3_ids; tag_ids.map{|x| x*3} end}
109
+ @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>Sequel.*(:id, 3), :primary_key_method=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
110
+ @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>Sequel.*(:id, 3), :primary_key_method=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
111
+
112
+ @c1.filter(:tags=>@o2).sql.should == "SELECT * FROM artists WHERE (artists.tag_ids[1:2] @> ARRAY[6])"
113
+ @c2.filter(:artists=>@o1).sql.should == "SELECT * FROM tags WHERE ((tags.id * 3) IN (3, 6, 9))"
114
+ @c1.filter(:tags=>@c2.where(:id=>1)).sql.should == "SELECT * FROM artists WHERE coalesce((artists.tag_ids[1:2] && (SELECT array_agg((tags.id * 3)) FROM tags WHERE (id = 1))), 'f')"
115
+ @c2.filter(:artists=>@c1.where(:id=>1)).sql.should == "SELECT * FROM tags WHERE ((tags.id * 3) IN (SELECT unnest(artists.tag_ids[1:2]) FROM artists WHERE (id = 1)))"
116
+ end
117
+
118
+ it "should support a :key option" do
119
+ @c1.pg_array_to_many :tags, :clone=>:tags, :key=>:tag2_ids
120
+ @c2.many_to_pg_array :artists, :clone=>:artists, :key=>:tag2_ids
121
+ @c1.class_eval{def tag2_ids; tag_ids.map{|x| x * 2} end}
122
+ @o1.tags_dataset.sql.should == "SELECT * FROM tags WHERE (tags.id IN (2, 4, 6))"
123
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE (artists.tag2_ids @> ARRAY[2])"
124
+ end
125
+
126
+ it "should support a :key_column option" do
127
+ @c2.many_to_pg_array :artists, :clone=>:artists, :key_column=>Sequel.pg_array(:tag_ids)[1..2], :key=>:tag2_ids
128
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE (artists.tag_ids[1:2] @> ARRAY[2])"
129
+ end
130
+
131
+ it "should support a :primary_key option" do
132
+ @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>:id2
133
+ @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>:id2
134
+ @o1.tags_dataset.sql.should == "SELECT * FROM tags WHERE (tags.id2 IN (1, 2, 3))"
135
+ @c2.class_eval{def id2; id*2 end}
136
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[4])"
137
+ end
138
+
139
+ it "should support a :conditions option" do
140
+ @c1.pg_array_to_many :tags, :clone=>:tags, :conditions=>{:a=>1}
141
+ @c2.many_to_pg_array :artists, :clone=>:artists, :conditions=>{:a=>1}
142
+ @o1.tags_dataset.sql.should == "SELECT * FROM tags WHERE ((a = 1) AND (tags.id IN (1, 2, 3)))"
143
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE ((a = 1) AND (artists.tag_ids @> ARRAY[2]))"
144
+ end
145
+
146
+ it "should support an :order option" do
147
+ @c1.pg_array_to_many :tags, :clone=>:tags, :order=>[:a, :b]
148
+ @c2.many_to_pg_array :artists, :clone=>:artists, :order=>[:a, :b]
149
+ @o1.tags_dataset.sql.should == "SELECT * FROM tags WHERE (tags.id IN (1, 2, 3)) ORDER BY a, b"
150
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2]) ORDER BY a, b"
151
+ end
152
+
153
+ it "should support a select option" do
154
+ @c1.pg_array_to_many :tags, :clone=>:tags, :select=>[:a, :b]
155
+ @c2.many_to_pg_array :artists, :clone=>:artists, :select=>[:a, :b]
156
+ @c1.load(:tag_ids=>Sequel.pg_array([1,2,3])).tags_dataset.sql.should == "SELECT a, b FROM tags WHERE (tags.id IN (1, 2, 3))"
157
+ @c2.load(:id=>1).artists_dataset.sql.should == "SELECT a, b FROM artists WHERE (artists.tag_ids @> ARRAY[1])"
158
+ end
159
+
160
+ it "should accept a block" do
161
+ @c1.pg_array_to_many :tags, :clone=>:tags do |ds| ds.filter(:yyy=>@yyy) end
162
+ @c2.many_to_pg_array :artists, :clone=>:artists do |ds| ds.filter(:a=>1) end
163
+ @c1.new(:yyy=>6, :tag_ids=>Sequel.pg_array([1,2,3])).tags_dataset.sql.should == "SELECT * FROM tags WHERE ((tags.id IN (1, 2, 3)) AND (yyy = 6))"
164
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE ((artists.tag_ids @> ARRAY[2]) AND (a = 1))"
165
+ end
166
+
167
+ it "should support a :dataset option that is used instead of the default" do
168
+ @c1.pg_array_to_many :tags, :clone=>:tags, :dataset=>proc{Tag.where(:id=>tag_ids.map{|x| x*2})}
169
+ @c2.many_to_pg_array :artists, :clone=>:artists, :dataset=>proc{Artist.where(Sequel.pg_array(Sequel.pg_array(:tag_ids)[1..2]).contains([id]))}
170
+ @o1.tags_dataset.sql.should == "SELECT * FROM tags WHERE (id IN (2, 4, 6))"
171
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE (tag_ids[1:2] @> ARRAY[2])"
172
+ end
173
+
174
+ it "should support a :limit option" do
175
+ @c1.pg_array_to_many :tags, :clone=>:tags, :limit=>[2, 3]
176
+ @c2.many_to_pg_array :artists, :clone=>:artists, :limit=>[3, 2]
177
+ @o1.tags_dataset.sql.should == "SELECT * FROM tags WHERE (tags.id IN (1, 2, 3)) LIMIT 2 OFFSET 3"
178
+ @o2.artists_dataset.sql.should == "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2]) LIMIT 3 OFFSET 2"
179
+ end
180
+
181
+ it "should support a :uniq option that removes duplicates from the association" do
182
+ @c1.pg_array_to_many :tags, :clone=>:tags, :uniq=>true
183
+ @c2.many_to_pg_array :artists, :clone=>:artists, :uniq=>true
184
+ @c1.dataset._fetch = [{:id=>20}, {:id=>30}, {:id=>20}, {:id=>30}]
185
+ @c2.dataset._fetch = [{:id=>20}, {:id=>30}, {:id=>20}, {:id=>30}]
186
+ @o1.tags.should == [@c2.load(:id=>20), @c2.load(:id=>30)]
187
+ @o2.artists.should == [@c1.load(:id=>20), @c1.load(:id=>30)]
188
+ end
189
+
190
+ it "reflection associated_object_keys should return correct values" do
191
+ @c1.association_reflection(:tags).associated_object_keys.should == [:id]
192
+ @c2.association_reflection(:artists).associated_object_keys.should == [:tag_ids]
193
+ end
194
+
195
+ it "reflection remove_before_destroy? should return correct values" do
196
+ @c1.association_reflection(:tags).remove_before_destroy?.should be_true
197
+ @c2.association_reflection(:artists).remove_before_destroy?.should be_false
198
+ end
199
+
200
+ it "reflection reciprocal should be correct" do
201
+ @c1.association_reflection(:tags).reciprocal.should == :artists
202
+ @c2.association_reflection(:artists).reciprocal.should == :tags
203
+ end
204
+
205
+ it "should eagerly load correctly" do
206
+ a = @c1.eager(:tags).all
207
+ a.should == [@o1]
208
+ sqls = DB.sqls
209
+ sqls.pop.should =~ /SELECT \* FROM tags WHERE \(tags\.id IN \([123], [123], [123]\)\)/
210
+ sqls.should == ["SELECT * FROM artists"]
211
+ a.first.tags.should == [@o2]
212
+ DB.sqls.should == []
213
+
214
+ a = @c2.eager(:artists).all
215
+ a.should == [@o2]
216
+ DB.sqls.should == ['SELECT * FROM tags', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2])"]
217
+ a.first.artists.should == [@o1]
218
+ DB.sqls.should == []
219
+ end
220
+
221
+ it "should support using custom key options when eager loading associations" do
222
+ @c1.class_eval{def tag3_ids; tag_ids.map{|x| x*3} end}
223
+ @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>Sequel.*(:id, 3), :primary_key_method=>:id3, :key=>:tag3_ids
224
+ @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
225
+
226
+ a = @c1.eager(:tags).all
227
+ a.should == [@o1]
228
+ sqls = DB.sqls
229
+ sqls.pop.should =~ /SELECT \* FROM tags WHERE \(\(tags\.id \* 3\) IN \([369], [369], [369]\)\)/
230
+ sqls.should == ["SELECT * FROM artists"]
231
+ a.first.tags.should == [@o2]
232
+ DB.sqls.should == []
233
+
234
+ a = @c2.eager(:artists).all
235
+ a.should == [@o2]
236
+ DB.sqls.should == ["SELECT * FROM tags", "SELECT * FROM artists WHERE (artists.tag_ids[1:2] && ARRAY[6])"]
237
+ a.first.artists.should == [@o1]
238
+ DB.sqls.should == []
239
+ end
240
+
241
+ it "should allow cascading of eager loading for associations of associated models" do
242
+ a = @c1.eager(:tags=>:artists).all
243
+ a.should == [@o1]
244
+ sqls = DB.sqls
245
+ sqls.slice!(1).should =~ /SELECT \* FROM tags WHERE \(tags\.id IN \([123], [123], [123]\)\)/
246
+ sqls.should == ['SELECT * FROM artists', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2])"]
247
+ a.first.tags.should == [@o2]
248
+ a.first.tags.first.artists.should == [@o1]
249
+ DB.sqls.should == []
250
+ end
251
+
252
+ it "should respect :eager when lazily loading an association" do
253
+ @c1.pg_array_to_many :tags2, :clone=>:tags, :eager=>:artists, :key=>:tag_ids
254
+ @c2.many_to_pg_array :artists2, :clone=>:artists, :eager=>:tags
255
+
256
+ @o1.tags2.should == [@o2]
257
+ DB.sqls.should == ["SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))", "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2])"]
258
+ @o1.tags2.first.artists.should == [@o1]
259
+ DB.sqls.should == []
260
+
261
+ @o2.artists2.should == [@o1]
262
+ sqls = DB.sqls
263
+ sqls.pop.should =~ /SELECT \* FROM tags WHERE \(tags\.id IN \([123], [123], [123]\)\)/
264
+ sqls.should == ["SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2])"]
265
+ @o2.artists2.first.tags.should == [@o2]
266
+ DB.sqls.should == []
267
+ end
268
+
269
+ it "should cascade eagerly loading when the :eager_graph association option is used" do
270
+ @c1.pg_array_to_many :tags2, :clone=>:tags, :eager_graph=>:artists, :key=>:tag_ids
271
+ @c2.many_to_pg_array :artists2, :clone=>:artists, :eager_graph=>:tags
272
+
273
+ @c2.dataset._fetch = {:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3])}
274
+ @c1.dataset._fetch = {:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3])}
275
+
276
+ @o1.tags2.should == [@o2]
277
+ DB.sqls.first.should =~ /SELECT tags\.id, artists\.id AS artists_id, artists\.tag_ids FROM tags LEFT OUTER JOIN artists ON \(artists.tag_ids @> ARRAY\[tags.id\]\) WHERE \(tags\.id IN \([123], [123], [123]\)\)/
278
+ @o1.tags2.first.artists.should == [@o1]
279
+ DB.sqls.should == []
280
+
281
+ @o2.artists2.should == [@o1]
282
+ DB.sqls.should == ["SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id]) WHERE (artists.tag_ids @> ARRAY[2])"]
283
+ @o2.artists2.first.tags.should == [@o2]
284
+ DB.sqls.should == []
285
+
286
+ @c2.dataset._fetch = {:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3])}
287
+ @c1.dataset._fetch = {:id=>1, :tag_ids=>Sequel.pg_array([1,2,3])}
288
+
289
+ a = @c1.eager(:tags2).all
290
+ sqls = DB.sqls
291
+ sqls.pop.should =~ /SELECT tags\.id, artists\.id AS artists_id, artists\.tag_ids FROM tags LEFT OUTER JOIN artists ON \(artists.tag_ids @> ARRAY\[tags.id\]\) WHERE \(tags\.id IN \([123], [123], [123]\)\)/
292
+ sqls.should == ["SELECT * FROM artists"]
293
+ a.should == [@o1]
294
+ a.first.tags2.should == [@o2]
295
+ a.first.tags2.first.artists.should == [@o1]
296
+ DB.sqls.should == []
297
+
298
+ @c2.dataset._fetch = {:id=>2}
299
+ @c1.dataset._fetch = {:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3])}
300
+
301
+ a = @c2.eager(:artists2).all
302
+ DB.sqls.should == ["SELECT * FROM tags", "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id]) WHERE (artists.tag_ids && ARRAY[2])"]
303
+ a.should == [@o2]
304
+ a.first.artists2.should == [@o1]
305
+ a.first.artists2.first.tags.should == [@o2]
306
+ DB.sqls.should == []
307
+ end
308
+
309
+ it "should respect the :limit option when eager loading" do
310
+ @c2.dataset._fetch = [{:id=>1},{:id=>2}, {:id=>3}]
311
+
312
+ @c1.pg_array_to_many :tags, :clone=>:tags, :limit=>2
313
+ a = @c1.eager(:tags).all
314
+ a.should == [@o1]
315
+ sqls = DB.sqls
316
+ sqls.pop.should =~ /SELECT \* FROM tags WHERE \(tags\.id IN \([123], [123], [123]\)\)/
317
+ sqls.should == ["SELECT * FROM artists"]
318
+ a.first.tags.should == [@c2.load(:id=>1), @c2.load(:id=>2)]
319
+ DB.sqls.should == []
320
+
321
+ @c1.pg_array_to_many :tags, :clone=>:tags, :limit=>[1, 1]
322
+ a = @c1.eager(:tags).all
323
+ a.should == [@o1]
324
+ sqls = DB.sqls
325
+ sqls.pop.should =~ /SELECT \* FROM tags WHERE \(tags\.id IN \([123], [123], [123]\)\)/
326
+ sqls.should == ["SELECT * FROM artists"]
327
+ a.first.tags.should == [@c2.load(:id=>2)]
328
+ DB.sqls.should == []
329
+
330
+ @c1.pg_array_to_many :tags, :clone=>:tags, :limit=>[nil, 1]
331
+ a = @c1.eager(:tags).all
332
+ a.should == [@o1]
333
+ sqls = DB.sqls
334
+ sqls.pop.should =~ /SELECT \* FROM tags WHERE \(tags\.id IN \([123], [123], [123]\)\)/
335
+ sqls.should == ["SELECT * FROM artists"]
336
+ a.first.tags.should == [@c2.load(:id=>2), @c2.load(:id=>3)]
337
+ DB.sqls.length.should == 0
338
+
339
+ @c2.dataset._fetch = [{:id=>2}]
340
+ @c1.dataset._fetch = [{:id=>5, :tag_ids=>Sequel.pg_array([1,2,3])},{:id=>6, :tag_ids=>Sequel.pg_array([2,3])}, {:id=>7, :tag_ids=>Sequel.pg_array([1,2])}]
341
+
342
+ @c2.many_to_pg_array :artists, :clone=>:artists, :limit=>2
343
+ a = @c2.eager(:artists).all
344
+ a.should == [@o2]
345
+ DB.sqls.should == ['SELECT * FROM tags', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2])"]
346
+ a.first.artists.should == [@c1.load(:id=>5, :tag_ids=>Sequel.pg_array([1,2,3])), @c1.load(:id=>6, :tag_ids=>Sequel.pg_array([2,3]))]
347
+ DB.sqls.should == []
348
+
349
+ @c2.many_to_pg_array :artists, :clone=>:artists, :limit=>[1, 1]
350
+ a = @c2.eager(:artists).all
351
+ a.should == [@o2]
352
+ DB.sqls.should == ['SELECT * FROM tags', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2])"]
353
+ a.first.artists.should == [@c1.load(:id=>6, :tag_ids=>Sequel.pg_array([2,3]))]
354
+ DB.sqls.should == []
355
+
356
+ @c2.many_to_pg_array :artists, :clone=>:artists, :limit=>[nil, 1]
357
+ a = @c2.eager(:artists).all
358
+ a.should == [@o2]
359
+ DB.sqls.should == ['SELECT * FROM tags', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2])"]
360
+ a.first.artists.should == [@c1.load(:id=>6, :tag_ids=>Sequel.pg_array([2,3])), @c1.load(:id=>7, :tag_ids=>Sequel.pg_array([1,2]))]
361
+ DB.sqls.should == []
362
+ end
363
+
364
+ it "should eagerly graph associations" do
365
+ @c2.dataset._fetch = {:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3])}
366
+ @c1.dataset._fetch = {:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3])}
367
+
368
+ a = @c1.eager_graph(:tags).all
369
+ DB.sqls.should == ["SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id])"]
370
+ a.should == [@o1]
371
+ a.first.tags.should == [@o2]
372
+ DB.sqls.should == []
373
+
374
+ a = @c2.eager_graph(:artists).all
375
+ DB.sqls.should == ["SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id])"]
376
+ a.should == [@o2]
377
+ a.first.artists.should == [@o1]
378
+ DB.sqls.should == []
379
+ end
380
+
381
+ it "should allow cascading of eager graphing for associations of associated models" do
382
+ @c2.dataset._fetch = {:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3]), :tags_0_id=>2}
383
+ @c1.dataset._fetch = {:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3]), :artists_0_id=>1, :artists_0_tag_ids=>Sequel.pg_array([1,2,3])}
384
+
385
+ a = @c1.eager_graph(:tags=>:artists).all
386
+ DB.sqls.should == ["SELECT artists.id, artists.tag_ids, tags.id AS tags_id, artists_0.id AS artists_0_id, artists_0.tag_ids AS artists_0_tag_ids FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id]) LEFT OUTER JOIN artists AS artists_0 ON (artists_0.tag_ids @> ARRAY[tags.id])"]
387
+ a.should == [@o1]
388
+ a.first.tags.should == [@o2]
389
+ a.first.tags.first.artists.should == [@o1]
390
+ DB.sqls.should == []
391
+
392
+ a = @c2.eager_graph(:artists=>:tags).all
393
+ DB.sqls.should == ["SELECT tags.id, artists.id AS artists_id, artists.tag_ids, tags_0.id AS tags_0_id FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id]) LEFT OUTER JOIN tags AS tags_0 ON (artists.tag_ids @> ARRAY[tags_0.id])"]
394
+ a.should == [@o2]
395
+ a.first.artists.should == [@o1]
396
+ a.first.artists.first.tags.should == [@o2]
397
+ DB.sqls.should == []
398
+ end
399
+
400
+ it "eager graphing should respect key options" do
401
+ @c1.class_eval{def tag3_ids; tag_ids.map{|x| x*3} end}
402
+ @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>Sequel.*(:id, 3), :primary_key_method=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
403
+ @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
404
+
405
+ @c2.dataset._fetch = {:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3]), :tags_0_id=>2}
406
+ @c1.dataset._fetch = {:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3]), :artists_0_id=>1, :artists_0_tag_ids=>Sequel.pg_array([1,2,3])}
407
+
408
+ a = @c1.eager_graph(:tags).all
409
+ a.should == [@o1]
410
+ DB.sqls.should == ["SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids[1:2] @> ARRAY[(tags.id * 3)])"]
411
+ a.first.tags.should == [@o2]
412
+ DB.sqls.should == []
413
+
414
+ a = @c2.eager_graph(:artists).all
415
+ a.should == [@o2]
416
+ DB.sqls.should == ["SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids[1:2] @> ARRAY[tags.id3])"]
417
+ a.first.artists.should == [@o1]
418
+ DB.sqls.should == []
419
+ end
420
+
421
+ it "should respect the association's :graph_select option" do
422
+ @c1.pg_array_to_many :tags, :clone=>:tags, :graph_select=>:id2
423
+ @c2.many_to_pg_array :artists, :clone=>:artists, :graph_select=>:id
424
+
425
+ @c2.dataset._fetch = {:id=>2, :artists_id=>1}
426
+ @c1.dataset._fetch = {:id=>1, :id2=>2, :tag_ids=>Sequel.pg_array([1,2,3])}
427
+
428
+ a = @c1.eager_graph(:tags).all
429
+ DB.sqls.should == ["SELECT artists.id, artists.tag_ids, tags.id2 FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id])"]
430
+ a.should == [@o1]
431
+ a.first.tags.should == [@c2.load(:id2=>2)]
432
+ DB.sqls.should == []
433
+
434
+ a = @c2.eager_graph(:artists).all
435
+ DB.sqls.should == ["SELECT tags.id, artists.id AS artists_id FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id])"]
436
+ a.should == [@o2]
437
+ a.first.artists.should == [@c1.load(:id=>1)]
438
+ DB.sqls.should == []
439
+ end
440
+
441
+ it "should respect the association's :graph_join_type option" do
442
+ @c1.pg_array_to_many :tags, :clone=>:tags, :graph_join_type=>:inner
443
+ @c2.many_to_pg_array :artists, :clone=>:artists, :graph_join_type=>:inner
444
+ @c1.eager_graph(:tags).sql.should == "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists INNER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id])"
445
+ @c2.eager_graph(:artists).sql.should == "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags INNER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id])"
446
+ end
447
+
448
+ it "should respect the association's :conditions option" do
449
+ @c1.pg_array_to_many :tags, :clone=>:tags, :conditions=>{:a=>1}
450
+ @c2.many_to_pg_array :artists, :clone=>:artists, :conditions=>{:a=>1}
451
+ @c1.eager_graph(:tags).sql.should == "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON ((tags.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
452
+ @c2.eager_graph(:artists).sql.should == "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON ((artists.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
453
+ end
454
+
455
+ it "should respect the association's :graph_conditions option" do
456
+ @c1.pg_array_to_many :tags, :clone=>:tags, :graph_conditions=>{:a=>1}
457
+ @c2.many_to_pg_array :artists, :clone=>:artists, :graph_conditions=>{:a=>1}
458
+ @c1.eager_graph(:tags).sql.should == "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON ((tags.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
459
+ @c2.eager_graph(:artists).sql.should == "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON ((artists.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
460
+ end
461
+
462
+ it "should respect the association's :graph_block option" do
463
+ @c1.pg_array_to_many :tags, :clone=>:tags, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :a)=>1}}
464
+ @c2.many_to_pg_array :artists, :clone=>:artists, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :a)=>1}}
465
+ @c1.eager_graph(:tags).sql.should == "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON ((tags.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
466
+ @c2.eager_graph(:artists).sql.should == "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON ((artists.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
467
+ end
468
+
469
+ it "should respect the association's :graph_only_conditions option" do
470
+ @c1.pg_array_to_many :tags, :clone=>:tags, :graph_only_conditions=>{:a=>1}
471
+ @c2.many_to_pg_array :artists, :clone=>:artists, :graph_only_conditions=>{:a=>1}
472
+ @c1.eager_graph(:tags).sql.should == "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (tags.a = 1)"
473
+ @c2.eager_graph(:artists).sql.should == "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON (artists.a = 1)"
474
+ end
475
+
476
+ it "should respect the association's :graph_only_conditions with :graph_block option" do
477
+ @c1.pg_array_to_many :tags, :clone=>:tags, :graph_only_conditions=>{:a=>1}, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(lja, :b)=>1}}
478
+ @c2.many_to_pg_array :artists, :clone=>:artists, :graph_only_conditions=>{:a=>1}, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(lja, :b)=>1}}
479
+ @c1.eager_graph(:tags).sql.should == "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON ((tags.a = 1) AND (artists.b = 1))"
480
+ @c2.eager_graph(:artists).sql.should == "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON ((artists.a = 1) AND (tags.b = 1))"
481
+ end
482
+
483
+ it "should define an add_ method for adding associated objects" do
484
+ @o1.add_tag(@c2.load(:id=>4))
485
+ @o1.tag_ids.should == [1,2,3,4]
486
+ DB.sqls.should == []
487
+ @o1.save_changes
488
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[1,2,3,4] WHERE (id = 1)"]
489
+
490
+ @o2.add_artist(@c1.load(:id=>1, :tag_ids=>Sequel.pg_array([4])))
491
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[4,2] WHERE (id = 1)"]
492
+ end
493
+
494
+ it "should define a remove_ method for removing associated objects" do
495
+ @o1.remove_tag(@o2)
496
+ @o1.tag_ids.should == [1,3]
497
+ DB.sqls.should == []
498
+ @o1.save_changes
499
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[1,3] WHERE (id = 1)"]
500
+
501
+ @o2.remove_artist(@c1.load(:id=>1, :tag_ids=>Sequel.pg_array([1,2,3,4])))
502
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[1,3,4] WHERE (id = 1)"]
503
+ end
504
+
505
+ it "should define a remove_all_ method for removing all associated objects" do
506
+ @o1.remove_all_tags
507
+ @o1.tag_ids.should == []
508
+ DB.sqls.should == []
509
+ @o1.save_changes
510
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[] WHERE (id = 1)"]
511
+
512
+ @o2.remove_all_artists
513
+ DB.sqls.should == ["UPDATE artists SET tag_ids = array_remove(tag_ids, 2) WHERE (tag_ids @> ARRAY[2])"]
514
+ end
515
+
516
+ it "should have pg_array_to_many association modification methods save if :save_after_modify option is used" do
517
+ @c1.pg_array_to_many :tags, :clone=>:tags, :save_after_modify=>true
518
+
519
+ @o1.add_tag(@c2.load(:id=>4))
520
+ @o1.tag_ids.should == [1,2,3,4]
521
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[1,2,3,4] WHERE (id = 1)"]
522
+
523
+ @o1.remove_tag(@o2)
524
+ @o1.tag_ids.should == [1,3,4]
525
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[1,3,4] WHERE (id = 1)"]
526
+
527
+ @o1.remove_all_tags
528
+ @o1.tag_ids.should == []
529
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[] WHERE (id = 1)"]
530
+ end
531
+
532
+ it "should have association modification methods deal with nil values" do
533
+ v = @c1.load(:id=>1)
534
+ v.add_tag(@c2.load(:id=>4))
535
+ v.tag_ids.should == [4]
536
+ DB.sqls.should == []
537
+ v.save_changes
538
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[4]::integer[] WHERE (id = 1)"]
539
+
540
+ @o2.add_artist(@c1.load(:id=>1))
541
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[2]::integer[] WHERE (id = 1)"]
542
+
543
+ v = @c1.load(:id=>1)
544
+ v.remove_tag(@c2.load(:id=>4))
545
+ v.tag_ids.should == nil
546
+ DB.sqls.should == []
547
+ v.save_changes
548
+ DB.sqls.should == []
549
+
550
+ @o2.remove_artist(@c1.load(:id=>1))
551
+ DB.sqls.should == []
552
+
553
+ v = @c1.load(:id=>1)
554
+ v.remove_all_tags
555
+ v.tag_ids.should == nil
556
+ DB.sqls.should == []
557
+ v.save_changes
558
+ DB.sqls.should == []
559
+ end
560
+
561
+ it "should have association modification methods deal with empty arrays values" do
562
+ v = @c1.load(:id=>1, :tag_ids=>Sequel.pg_array([]))
563
+ v.add_tag(@c2.load(:id=>4))
564
+ v.tag_ids.should == [4]
565
+ DB.sqls.should == []
566
+ v.save_changes
567
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[4] WHERE (id = 1)"]
568
+
569
+ @o2.add_artist(@c1.load(:id=>1, :tag_ids=>Sequel.pg_array([])))
570
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[2] WHERE (id = 1)"]
571
+
572
+ v = @c1.load(:id=>1, :tag_ids=>Sequel.pg_array([]))
573
+ v.remove_tag(@c2.load(:id=>4))
574
+ v.tag_ids.should == []
575
+ DB.sqls.should == []
576
+ v.save_changes
577
+ DB.sqls.should == []
578
+
579
+ @o2.remove_artist(@c1.load(:id=>1, :tag_ids=>Sequel.pg_array([])))
580
+ DB.sqls.should == []
581
+
582
+ v = @c1.load(:id=>1, :tag_ids=>Sequel.pg_array([]))
583
+ v.remove_all_tags
584
+ v.tag_ids.should == []
585
+ DB.sqls.should == []
586
+ v.save_changes
587
+ DB.sqls.should == []
588
+ end
589
+
590
+ it "should respect the :array_type option when manually creating arrays" do
591
+ @c1.pg_array_to_many :tags, :clone=>:tags, :array_type=>:int8
592
+ @c2.many_to_pg_array :artists, :clone=>:artists, :array_type=>:int8
593
+ v = @c1.load(:id=>1)
594
+ v.add_tag(@c2.load(:id=>4))
595
+ v.tag_ids.should == [4]
596
+ DB.sqls.should == []
597
+ v.save_changes
598
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[4]::int8[] WHERE (id = 1)"]
599
+
600
+ @o2.add_artist(@c1.load(:id=>1))
601
+ DB.sqls.should == ["UPDATE artists SET tag_ids = ARRAY[2]::int8[] WHERE (id = 1)"]
602
+ end
603
+ end