viking-sequel 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. data/CHANGELOG +3134 -0
  2. data/COPYING +19 -0
  3. data/README.rdoc +723 -0
  4. data/Rakefile +193 -0
  5. data/bin/sequel +196 -0
  6. data/doc/advanced_associations.rdoc +644 -0
  7. data/doc/cheat_sheet.rdoc +218 -0
  8. data/doc/dataset_basics.rdoc +106 -0
  9. data/doc/dataset_filtering.rdoc +158 -0
  10. data/doc/opening_databases.rdoc +296 -0
  11. data/doc/prepared_statements.rdoc +104 -0
  12. data/doc/reflection.rdoc +84 -0
  13. data/doc/release_notes/1.0.txt +38 -0
  14. data/doc/release_notes/1.1.txt +143 -0
  15. data/doc/release_notes/1.3.txt +101 -0
  16. data/doc/release_notes/1.4.0.txt +53 -0
  17. data/doc/release_notes/1.5.0.txt +155 -0
  18. data/doc/release_notes/2.0.0.txt +298 -0
  19. data/doc/release_notes/2.1.0.txt +271 -0
  20. data/doc/release_notes/2.10.0.txt +328 -0
  21. data/doc/release_notes/2.11.0.txt +215 -0
  22. data/doc/release_notes/2.12.0.txt +534 -0
  23. data/doc/release_notes/2.2.0.txt +253 -0
  24. data/doc/release_notes/2.3.0.txt +88 -0
  25. data/doc/release_notes/2.4.0.txt +106 -0
  26. data/doc/release_notes/2.5.0.txt +137 -0
  27. data/doc/release_notes/2.6.0.txt +157 -0
  28. data/doc/release_notes/2.7.0.txt +166 -0
  29. data/doc/release_notes/2.8.0.txt +171 -0
  30. data/doc/release_notes/2.9.0.txt +97 -0
  31. data/doc/release_notes/3.0.0.txt +221 -0
  32. data/doc/release_notes/3.1.0.txt +406 -0
  33. data/doc/release_notes/3.10.0.txt +286 -0
  34. data/doc/release_notes/3.2.0.txt +268 -0
  35. data/doc/release_notes/3.3.0.txt +192 -0
  36. data/doc/release_notes/3.4.0.txt +325 -0
  37. data/doc/release_notes/3.5.0.txt +510 -0
  38. data/doc/release_notes/3.6.0.txt +366 -0
  39. data/doc/release_notes/3.7.0.txt +179 -0
  40. data/doc/release_notes/3.8.0.txt +151 -0
  41. data/doc/release_notes/3.9.0.txt +233 -0
  42. data/doc/schema.rdoc +36 -0
  43. data/doc/sharding.rdoc +113 -0
  44. data/doc/virtual_rows.rdoc +205 -0
  45. data/lib/sequel.rb +1 -0
  46. data/lib/sequel/adapters/ado.rb +90 -0
  47. data/lib/sequel/adapters/ado/mssql.rb +30 -0
  48. data/lib/sequel/adapters/amalgalite.rb +176 -0
  49. data/lib/sequel/adapters/db2.rb +139 -0
  50. data/lib/sequel/adapters/dbi.rb +113 -0
  51. data/lib/sequel/adapters/do.rb +188 -0
  52. data/lib/sequel/adapters/do/mysql.rb +49 -0
  53. data/lib/sequel/adapters/do/postgres.rb +91 -0
  54. data/lib/sequel/adapters/do/sqlite.rb +40 -0
  55. data/lib/sequel/adapters/firebird.rb +283 -0
  56. data/lib/sequel/adapters/informix.rb +77 -0
  57. data/lib/sequel/adapters/jdbc.rb +587 -0
  58. data/lib/sequel/adapters/jdbc/as400.rb +58 -0
  59. data/lib/sequel/adapters/jdbc/h2.rb +133 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
  61. data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
  62. data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
  64. data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
  65. data/lib/sequel/adapters/mysql.rb +421 -0
  66. data/lib/sequel/adapters/odbc.rb +143 -0
  67. data/lib/sequel/adapters/odbc/mssql.rb +42 -0
  68. data/lib/sequel/adapters/openbase.rb +64 -0
  69. data/lib/sequel/adapters/oracle.rb +131 -0
  70. data/lib/sequel/adapters/postgres.rb +504 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +490 -0
  72. data/lib/sequel/adapters/shared/mysql.rb +498 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +195 -0
  74. data/lib/sequel/adapters/shared/postgres.rb +830 -0
  75. data/lib/sequel/adapters/shared/progress.rb +44 -0
  76. data/lib/sequel/adapters/shared/sqlite.rb +389 -0
  77. data/lib/sequel/adapters/sqlite.rb +224 -0
  78. data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
  79. data/lib/sequel/connection_pool.rb +99 -0
  80. data/lib/sequel/connection_pool/sharded_single.rb +84 -0
  81. data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
  82. data/lib/sequel/connection_pool/single.rb +29 -0
  83. data/lib/sequel/connection_pool/threaded.rb +150 -0
  84. data/lib/sequel/core.rb +293 -0
  85. data/lib/sequel/core_sql.rb +241 -0
  86. data/lib/sequel/database.rb +1079 -0
  87. data/lib/sequel/database/schema_generator.rb +327 -0
  88. data/lib/sequel/database/schema_methods.rb +203 -0
  89. data/lib/sequel/database/schema_sql.rb +320 -0
  90. data/lib/sequel/dataset.rb +32 -0
  91. data/lib/sequel/dataset/actions.rb +441 -0
  92. data/lib/sequel/dataset/features.rb +86 -0
  93. data/lib/sequel/dataset/graph.rb +254 -0
  94. data/lib/sequel/dataset/misc.rb +119 -0
  95. data/lib/sequel/dataset/mutation.rb +64 -0
  96. data/lib/sequel/dataset/prepared_statements.rb +227 -0
  97. data/lib/sequel/dataset/query.rb +709 -0
  98. data/lib/sequel/dataset/sql.rb +996 -0
  99. data/lib/sequel/exceptions.rb +51 -0
  100. data/lib/sequel/extensions/blank.rb +43 -0
  101. data/lib/sequel/extensions/inflector.rb +242 -0
  102. data/lib/sequel/extensions/looser_typecasting.rb +21 -0
  103. data/lib/sequel/extensions/migration.rb +239 -0
  104. data/lib/sequel/extensions/named_timezones.rb +61 -0
  105. data/lib/sequel/extensions/pagination.rb +100 -0
  106. data/lib/sequel/extensions/pretty_table.rb +82 -0
  107. data/lib/sequel/extensions/query.rb +52 -0
  108. data/lib/sequel/extensions/schema_dumper.rb +271 -0
  109. data/lib/sequel/extensions/sql_expr.rb +122 -0
  110. data/lib/sequel/extensions/string_date_time.rb +46 -0
  111. data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
  112. data/lib/sequel/metaprogramming.rb +9 -0
  113. data/lib/sequel/model.rb +120 -0
  114. data/lib/sequel/model/associations.rb +1514 -0
  115. data/lib/sequel/model/base.rb +1069 -0
  116. data/lib/sequel/model/default_inflections.rb +45 -0
  117. data/lib/sequel/model/errors.rb +39 -0
  118. data/lib/sequel/model/exceptions.rb +21 -0
  119. data/lib/sequel/model/inflections.rb +162 -0
  120. data/lib/sequel/model/plugins.rb +70 -0
  121. data/lib/sequel/plugins/active_model.rb +59 -0
  122. data/lib/sequel/plugins/association_dependencies.rb +103 -0
  123. data/lib/sequel/plugins/association_proxies.rb +41 -0
  124. data/lib/sequel/plugins/boolean_readers.rb +53 -0
  125. data/lib/sequel/plugins/caching.rb +141 -0
  126. data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
  127. data/lib/sequel/plugins/composition.rb +138 -0
  128. data/lib/sequel/plugins/force_encoding.rb +72 -0
  129. data/lib/sequel/plugins/hook_class_methods.rb +126 -0
  130. data/lib/sequel/plugins/identity_map.rb +116 -0
  131. data/lib/sequel/plugins/instance_filters.rb +98 -0
  132. data/lib/sequel/plugins/instance_hooks.rb +57 -0
  133. data/lib/sequel/plugins/lazy_attributes.rb +77 -0
  134. data/lib/sequel/plugins/many_through_many.rb +208 -0
  135. data/lib/sequel/plugins/nested_attributes.rb +206 -0
  136. data/lib/sequel/plugins/optimistic_locking.rb +81 -0
  137. data/lib/sequel/plugins/rcte_tree.rb +281 -0
  138. data/lib/sequel/plugins/schema.rb +66 -0
  139. data/lib/sequel/plugins/serialization.rb +166 -0
  140. data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
  141. data/lib/sequel/plugins/subclasses.rb +45 -0
  142. data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
  143. data/lib/sequel/plugins/timestamps.rb +87 -0
  144. data/lib/sequel/plugins/touch.rb +118 -0
  145. data/lib/sequel/plugins/typecast_on_load.rb +72 -0
  146. data/lib/sequel/plugins/validation_class_methods.rb +405 -0
  147. data/lib/sequel/plugins/validation_helpers.rb +223 -0
  148. data/lib/sequel/sql.rb +1020 -0
  149. data/lib/sequel/timezones.rb +161 -0
  150. data/lib/sequel/version.rb +12 -0
  151. data/lib/sequel_core.rb +1 -0
  152. data/lib/sequel_model.rb +1 -0
  153. data/spec/adapters/firebird_spec.rb +407 -0
  154. data/spec/adapters/informix_spec.rb +97 -0
  155. data/spec/adapters/mssql_spec.rb +403 -0
  156. data/spec/adapters/mysql_spec.rb +1019 -0
  157. data/spec/adapters/oracle_spec.rb +286 -0
  158. data/spec/adapters/postgres_spec.rb +969 -0
  159. data/spec/adapters/spec_helper.rb +51 -0
  160. data/spec/adapters/sqlite_spec.rb +432 -0
  161. data/spec/core/connection_pool_spec.rb +808 -0
  162. data/spec/core/core_sql_spec.rb +417 -0
  163. data/spec/core/database_spec.rb +1662 -0
  164. data/spec/core/dataset_spec.rb +3827 -0
  165. data/spec/core/expression_filters_spec.rb +595 -0
  166. data/spec/core/object_graph_spec.rb +296 -0
  167. data/spec/core/schema_generator_spec.rb +159 -0
  168. data/spec/core/schema_spec.rb +830 -0
  169. data/spec/core/spec_helper.rb +56 -0
  170. data/spec/core/version_spec.rb +7 -0
  171. data/spec/extensions/active_model_spec.rb +76 -0
  172. data/spec/extensions/association_dependencies_spec.rb +127 -0
  173. data/spec/extensions/association_proxies_spec.rb +50 -0
  174. data/spec/extensions/blank_spec.rb +67 -0
  175. data/spec/extensions/boolean_readers_spec.rb +92 -0
  176. data/spec/extensions/caching_spec.rb +250 -0
  177. data/spec/extensions/class_table_inheritance_spec.rb +252 -0
  178. data/spec/extensions/composition_spec.rb +194 -0
  179. data/spec/extensions/force_encoding_spec.rb +117 -0
  180. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  181. data/spec/extensions/identity_map_spec.rb +202 -0
  182. data/spec/extensions/inflector_spec.rb +181 -0
  183. data/spec/extensions/instance_filters_spec.rb +55 -0
  184. data/spec/extensions/instance_hooks_spec.rb +133 -0
  185. data/spec/extensions/lazy_attributes_spec.rb +153 -0
  186. data/spec/extensions/looser_typecasting_spec.rb +39 -0
  187. data/spec/extensions/many_through_many_spec.rb +884 -0
  188. data/spec/extensions/migration_spec.rb +332 -0
  189. data/spec/extensions/named_timezones_spec.rb +72 -0
  190. data/spec/extensions/nested_attributes_spec.rb +396 -0
  191. data/spec/extensions/optimistic_locking_spec.rb +100 -0
  192. data/spec/extensions/pagination_spec.rb +99 -0
  193. data/spec/extensions/pretty_table_spec.rb +91 -0
  194. data/spec/extensions/query_spec.rb +85 -0
  195. data/spec/extensions/rcte_tree_spec.rb +205 -0
  196. data/spec/extensions/schema_dumper_spec.rb +357 -0
  197. data/spec/extensions/schema_spec.rb +127 -0
  198. data/spec/extensions/serialization_spec.rb +209 -0
  199. data/spec/extensions/single_table_inheritance_spec.rb +96 -0
  200. data/spec/extensions/spec_helper.rb +91 -0
  201. data/spec/extensions/sql_expr_spec.rb +89 -0
  202. data/spec/extensions/string_date_time_spec.rb +93 -0
  203. data/spec/extensions/subclasses_spec.rb +52 -0
  204. data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
  205. data/spec/extensions/thread_local_timezones_spec.rb +45 -0
  206. data/spec/extensions/timestamps_spec.rb +150 -0
  207. data/spec/extensions/touch_spec.rb +155 -0
  208. data/spec/extensions/typecast_on_load_spec.rb +69 -0
  209. data/spec/extensions/validation_class_methods_spec.rb +984 -0
  210. data/spec/extensions/validation_helpers_spec.rb +438 -0
  211. data/spec/integration/associations_test.rb +281 -0
  212. data/spec/integration/database_test.rb +26 -0
  213. data/spec/integration/dataset_test.rb +963 -0
  214. data/spec/integration/eager_loader_test.rb +734 -0
  215. data/spec/integration/model_test.rb +130 -0
  216. data/spec/integration/plugin_test.rb +814 -0
  217. data/spec/integration/prepared_statement_test.rb +213 -0
  218. data/spec/integration/schema_test.rb +361 -0
  219. data/spec/integration/spec_helper.rb +73 -0
  220. data/spec/integration/timezone_test.rb +55 -0
  221. data/spec/integration/transaction_test.rb +122 -0
  222. data/spec/integration/type_test.rb +96 -0
  223. data/spec/model/association_reflection_spec.rb +175 -0
  224. data/spec/model/associations_spec.rb +2633 -0
  225. data/spec/model/base_spec.rb +418 -0
  226. data/spec/model/dataset_methods_spec.rb +78 -0
  227. data/spec/model/eager_loading_spec.rb +1391 -0
  228. data/spec/model/hooks_spec.rb +240 -0
  229. data/spec/model/inflector_spec.rb +26 -0
  230. data/spec/model/model_spec.rb +593 -0
  231. data/spec/model/plugins_spec.rb +236 -0
  232. data/spec/model/record_spec.rb +1500 -0
  233. data/spec/model/spec_helper.rb +97 -0
  234. data/spec/model/validations_spec.rb +153 -0
  235. data/spec/rcov.opts +6 -0
  236. data/spec/spec_config.rb.example +10 -0
  237. metadata +346 -0
@@ -0,0 +1,296 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Sequel::Dataset, " graphing" do
4
+ before do
5
+ dbc = Class.new
6
+ @db = dbc.new
7
+ @ds1 = Sequel::Dataset.new(@db).from(:points)
8
+ @ds2 = Sequel::Dataset.new(@db).from(:lines)
9
+ @ds3 = Sequel::Dataset.new(@db).from(:graphs)
10
+ dss = {:points=>@ds1, :lines=>@ds2, :graphs=>@ds3}
11
+ dbc.send(:define_method, :[]){|ds| dss[ds]}
12
+ def @ds1.columns; [:id, :x, :y] end
13
+ def @ds2.columns; [:id, :x, :y, :graph_id] end
14
+ def @ds3.columns; [:id, :name, :x, :y, :lines_x] end
15
+ end
16
+
17
+ it "#graph should not modify the current dataset's opts" do
18
+ o1 = @ds1.opts
19
+ o2 = o1.dup
20
+ ds1 = @ds1.graph(@ds2, :x=>:id)
21
+ @ds1.opts.should == o1
22
+ @ds1.opts.should == o2
23
+ ds1.opts.should_not == o1
24
+ end
25
+
26
+ it "#graph should accept a simple dataset and pass the table to join" do
27
+ ds = @ds1.graph(@ds2, :x=>:id)
28
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
29
+ end
30
+
31
+ it "#graph should accept a complex dataset and pass it directly to join" do
32
+ ds = @ds1.graph(@ds2.filter(:x=>1), {:x=>:id})
33
+ ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT * FROM lines WHERE (x = 1)) AS t1 ON (t1.x = points.id)'
34
+ end
35
+
36
+ it "#graph should work on from_self datasets" do
37
+ ds = @ds1.from_self.graph(@ds2, :x=>:id)
38
+ ds.sql.should == 'SELECT t1.id, t1.x, t1.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM (SELECT * FROM points) AS t1 LEFT OUTER JOIN lines ON (lines.x = t1.id)'
39
+ ds = @ds1.graph(@ds2.from_self, :x=>:id)
40
+ ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM lines) AS t1) AS t1 ON (t1.x = points.id)'
41
+ ds = @ds1.from_self.from_self.graph(@ds2.from_self.from_self, :x=>:id)
42
+ ds.sql.should == 'SELECT t1.id, t1.x, t1.y, t2.id AS t2_id, t2.x AS t2_x, t2.y AS t2_y, t2.graph_id FROM (SELECT * FROM (SELECT * FROM points) AS t1) AS t1 LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM (SELECT * FROM lines) AS t1) AS t1) AS t2 ON (t2.x = t1.id)'
43
+ ds = @ds1.from(@ds1, @ds3).graph(@ds2.from_self, :x=>:id)
44
+ ds.sql.should == 'SELECT t1.id, t1.x, t1.y, t3.id AS t3_id, t3.x AS t3_x, t3.y AS t3_y, t3.graph_id FROM (SELECT * FROM (SELECT * FROM points) AS t1, (SELECT * FROM graphs) AS t2) AS t1 LEFT OUTER JOIN (SELECT * FROM (SELECT * FROM lines) AS t1) AS t3 ON (t3.x = t1.id)'
45
+ end
46
+
47
+ it "#graph should accept a symbol table name as the dataset" do
48
+ ds = @ds1.graph(:lines, :x=>:id)
49
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
50
+ end
51
+
52
+ it "#graph should accept an object that responds to dataset as the dataset" do
53
+ oc = Class.new
54
+ o = oc.new
55
+ ds = @ds2
56
+ oc.send(:define_method, :dataset){ds}
57
+ ds = @ds1.graph(o, :x=>:id)
58
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
59
+ ds = :lines
60
+ oc.send(:define_method, :dataset){ds}
61
+ ds = @ds1.graph(o, :x=>:id)
62
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
63
+ end
64
+
65
+ it "#graph should raise an error if a symbol, dataset, or model is not used" do
66
+ proc{@ds1.graph(Object.new, :x=>:id)}.should raise_error(Sequel::Error)
67
+ end
68
+
69
+ it "#graph should accept a :table_alias option" do
70
+ ds = @ds1.graph(:lines, {:x=>:id}, :table_alias=>:planes)
71
+ ds.sql.should == 'SELECT points.id, points.x, points.y, planes.id AS planes_id, planes.x AS planes_x, planes.y AS planes_y, planes.graph_id FROM points LEFT OUTER JOIN lines AS planes ON (planes.x = points.id)'
72
+ end
73
+
74
+ it "#graph should accept a :implicit_qualifier option" do
75
+ ds = @ds1.graph(:lines, {:x=>:id}, :implicit_qualifier=>:planes)
76
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = planes.id)'
77
+ end
78
+
79
+ it "#graph should accept a :join_type option" do
80
+ ds = @ds1.graph(:lines, {:x=>:id}, :join_type=>:inner)
81
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points INNER JOIN lines ON (lines.x = points.id)'
82
+ end
83
+
84
+ it "#graph should not select any columns from the graphed table if :select option is false" do
85
+ ds = @ds1.graph(:lines, {:x=>:id}, :select=>false).graph(:graphs, :id=>:graph_id)
86
+ ds.sql.should == 'SELECT points.id, points.x, points.y, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
87
+ end
88
+
89
+ it "#graph should use the given columns if :select option is used" do
90
+ ds = @ds1.graph(:lines, {:x=>:id}, :select=>[:x, :graph_id]).graph(:graphs, :id=>:graph_id)
91
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.x AS lines_x, lines.graph_id, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x AS graphs_lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
92
+ end
93
+
94
+ it "#graph should pass all join_conditions to join_table" do
95
+ ds = @ds1.graph(@ds2, [[:x, :id], [:y, :id]])
96
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON ((lines.x = points.id) AND (lines.y = points.id))'
97
+ end
98
+
99
+ it "#graph should accept a block instead of conditions and pass it to join_table" do
100
+ ds = @ds1.graph(@ds2){|ja, lja, js| [[:x.qualify(ja), :id.qualify(lja)], [:y.qualify(ja), :id.qualify(lja)]]}
101
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON ((lines.x = points.id) AND (lines.y = points.id))'
102
+ end
103
+
104
+ it "#graph should not add columns if graph is called after set_graph_aliases" do
105
+ ds = @ds1.set_graph_aliases([[:x,[:points, :x]], [:y,[:lines, :y]]])
106
+ ds.sql.should == 'SELECT points.x, lines.y FROM points'
107
+ ds = ds.graph(:lines, :x=>:id)
108
+ ds.sql.should == 'SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
109
+ end
110
+
111
+ it "#graph should allow graphing of multiple datasets" do
112
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
113
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x AS graphs_lines_x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN graphs ON (graphs.id = lines.graph_id)'
114
+ end
115
+
116
+ it "#graph should allow graphing of the same dataset multiple times" do
117
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph)
118
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id, graph.id AS graph_id_0, graph.x AS graph_x, graph.y AS graph_y, graph.graph_id AS graph_graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id) LEFT OUTER JOIN lines AS graph ON (graph.y = points.id)'
119
+ end
120
+
121
+ it "#graph should raise an error if the table/table alias has already been used" do
122
+ proc{@ds1.graph(@ds1, :x=>:id)}.should raise_error(Sequel::Error)
123
+ proc{@ds1.graph(@ds2, :x=>:id)}.should_not raise_error
124
+ proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, :x=>:id)}.should raise_error(Sequel::Error)
125
+ proc{@ds1.graph(@ds2, :x=>:id).graph(@ds2, {:x=>:id}, :table_alias=>:blah)}.should_not raise_error
126
+ end
127
+
128
+ it "#set_graph_aliases and #add_graph_aliases should not modify the current dataset's opts" do
129
+ o1 = @ds1.opts
130
+ o2 = o1.dup
131
+ ds1 = @ds1.set_graph_aliases(:x=>[:graphs,:id])
132
+ @ds1.opts.should == o1
133
+ @ds1.opts.should == o2
134
+ ds1.opts.should_not == o1
135
+ o3 = ds1.opts
136
+ o4 = o3.dup
137
+ ds2 = ds1.add_graph_aliases(:y=>[:blah,:id])
138
+ ds1.opts.should == o3
139
+ ds1.opts.should == o3
140
+ ds2.opts.should_not == o2
141
+ end
142
+
143
+ it "#set_graph_aliases should specify the graph mapping" do
144
+ ds = @ds1.graph(:lines, :x=>:id)
145
+ ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
146
+ ds = ds.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
147
+ ['SELECT points.x, lines.y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
148
+ 'SELECT lines.y, points.x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
149
+ ].should(include(ds.sql))
150
+ end
151
+
152
+ it "#add_graph_aliases should add columns to the graph mapping" do
153
+ @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :q]).add_graph_aliases(:y=>[:lines, :r]).sql.should == 'SELECT points.q AS x, lines.r AS y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
154
+ end
155
+
156
+ it "#set_graph_aliases should allow a third entry to specify an expression to use other than the default" do
157
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x, 1], :y=>[:lines, :y, :random.sql_function])
158
+ ['SELECT 1 AS x, random() AS y FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)',
159
+ 'SELECT random() AS y, 1 AS x FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
160
+ ].should(include(ds.sql))
161
+ end
162
+
163
+ it "#set_graph_aliases should only alias columns if necessary" do
164
+ ds = @ds1.set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
165
+ ['SELECT points.x, lines.y FROM points',
166
+ 'SELECT lines.y, points.x FROM points'
167
+ ].should(include(ds.sql))
168
+
169
+ ds = @ds1.set_graph_aliases(:x1=>[:points, :x], :y=>[:lines, :y])
170
+ ['SELECT points.x AS x1, lines.y FROM points',
171
+ 'SELECT lines.y, points.x AS x1 FROM points'
172
+ ].should(include(ds.sql))
173
+ end
174
+
175
+ it "#graph_each should split the result set into component tables" do
176
+ ds = @ds1.graph(@ds2, :x=>:id)
177
+ def ds.fetch_rows(sql, &block)
178
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7})
179
+ end
180
+ results = ds.all
181
+ results.length.should == 1
182
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}}
183
+
184
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
185
+ def ds.fetch_rows(sql, &block)
186
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>8, :name=>9, :graphs_x=>10, :graphs_y=>11, :graphs_lines_x=>12})
187
+ end
188
+ results = ds.all
189
+ results.length.should == 1
190
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}
191
+
192
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph)
193
+ def ds.fetch_rows(sql, &block)
194
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graph_id_0=>8, :graph_x=>9, :graph_y=>10, :graph_graph_id=>11})
195
+ end
196
+ results = ds.all
197
+ results.length.should == 1
198
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graph=>{:id=>8, :x=>9, :y=>10, :graph_id=>11}}
199
+ end
200
+
201
+ it "#ungraphed should remove the splitting of result sets into component tables" do
202
+ ds = @ds1.graph(@ds2, :x=>:id).ungraphed
203
+ def ds.fetch_rows(sql, &block)
204
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7})
205
+ end
206
+ ds.all.should == [{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}]
207
+ end
208
+
209
+ it "#graph_each should give a nil value instead of a hash when all values for a table are nil" do
210
+ ds = @ds1.graph(@ds2, :x=>:id)
211
+ def ds.fetch_rows(sql, &block)
212
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>nil,:lines_x=>nil,:lines_y=>nil,:graph_id=>nil})
213
+ end
214
+ results = ds.all
215
+ results.length.should == 1
216
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>nil}
217
+
218
+ ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
219
+ def ds.fetch_rows(sql, &block)
220
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>nil, :name=>nil, :graphs_x=>nil, :graphs_y=>nil, :graphs_lines_x=>nil})
221
+ yield({:id=>2,:x=>4,:y=>5,:lines_id=>nil,:lines_x=>nil,:lines_y=>nil,:graph_id=>nil, :graphs_id=>nil, :name=>nil, :graphs_x=>nil, :graphs_y=>nil, :graphs_lines_x=>nil})
222
+ yield({:id=>3,:x=>5,:y=>6,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>7, :name=>8, :graphs_x=>9, :graphs_y=>10, :graphs_lines_x=>11})
223
+ yield({:id=>3,:x=>5,:y=>6,:lines_id=>7,:lines_x=>5,:lines_y=>8,:graph_id=>9, :graphs_id=>9, :name=>10, :graphs_x=>10, :graphs_y=>11, :graphs_lines_x=>12})
224
+ end
225
+ results = ds.all
226
+ results.length.should == 4
227
+ results[0].should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>nil}
228
+ results[1].should == {:points=>{:id=>2, :x=>4, :y=>5}, :lines=>nil, :graphs=>nil}
229
+ results[2].should == {:points=>{:id=>3, :x=>5, :y=>6}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>7, :name=>8, :x=>9, :y=>10, :lines_x=>11}}
230
+ results[3].should == {:points=>{:id=>3, :x=>5, :y=>6}, :lines=>{:id=>7, :x=>5, :y=>8, :graph_id=>9}, :graphs=>{:id=>9, :name=>10, :x=>10, :y=>11, :lines_x=>12}}
231
+ end
232
+
233
+ it "#graph_each should not give a nil value instead of a hash when any value for a table is false" do
234
+ ds = @ds1.graph(@ds2, :x=>:id)
235
+ def ds.fetch_rows(sql, &block)
236
+ block.call(:id=>1,:x=>2,:y=>3,:lines_id=>nil,:lines_x=>false,:lines_y=>nil,:graph_id=>nil)
237
+ end
238
+ ds.all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>nil, :x=>false, :y=>nil, :graph_id=>nil}}]
239
+ end
240
+
241
+ it "#graph_each should not included tables graphed with the :select => false option in the result set" do
242
+ ds = @ds1.graph(:lines, {:x=>:id}, :select=>false).graph(:graphs, :id=>:graph_id)
243
+ def ds.fetch_rows(sql, &block)
244
+ yield({:id=>1,:x=>2,:y=>3,:graphs_id=>8, :name=>9, :graphs_x=>10, :graphs_y=>11, :lines_x=>12})
245
+ end
246
+ results = ds.all
247
+ results.length.should == 1
248
+ results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}
249
+ end
250
+
251
+ it "#graph_each should only include the columns selected with #set_graph_aliases and #add_graph_aliases, if called" do
252
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
253
+ def ds.fetch_rows(sql, &block)
254
+ yield({:x=>2,:y=>3})
255
+ end
256
+ results = ds.all
257
+ results.length.should == 1
258
+ results.first.should == {:points=>{:x=>2}, :lines=>{:y=>3}}
259
+
260
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x])
261
+ def ds.fetch_rows(sql, &block)
262
+ yield({:x=>2})
263
+ end
264
+ results = ds.all
265
+ results.length.should == 1
266
+ results.first.should == {:points=>{:x=>2}, :lines=>nil}
267
+
268
+ ds = ds.add_graph_aliases(:q=>[:points, :r, 18])
269
+ def ds.fetch_rows(sql, &block)
270
+ yield({:x=>2, :q=>18})
271
+ end
272
+ ds.all.should == [{:points=>{:x=>2, :r=>18}, :lines=>nil}]
273
+ end
274
+
275
+ it "#graph_each should correctly map values when #set_graph_aliases is used with a third argument for each entry" do
276
+ ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :z1, 2], :y=>[:lines, :z2, :random.sql_function])
277
+ def ds.fetch_rows(sql, &block)
278
+ yield({:x=>2,:y=>3})
279
+ end
280
+ results = ds.all
281
+ results.length.should == 1
282
+ results.first.should == {:points=>{:z1=>2}, :lines=>{:z2=>3}}
283
+ end
284
+
285
+ it "#graph_each should run the row_proc for graphed datasets" do
286
+ @ds1.row_proc = proc{|h| h.keys.each{|k| h[k] *= 2}; h}
287
+ @ds2.row_proc = proc{|h| h.keys.each{|k| h[k] *= 3}; h}
288
+ ds = @ds1.graph(@ds2, :x=>:id)
289
+ def ds.fetch_rows(sql, &block)
290
+ yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7})
291
+ end
292
+ results = ds.all
293
+ results.length.should == 1
294
+ results.first.should == {:points=>{:id=>2, :x=>4, :y=>6}, :lines=>{:id=>12, :x=>15, :y=>18, :graph_id=>21}}
295
+ end
296
+ end
@@ -0,0 +1,159 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Sequel::Schema::Generator do
4
+ before do
5
+ @generator = Sequel::Schema::Generator.new(SchemaDummyDatabase.new) do
6
+ string :title
7
+ column :body, :text
8
+ foreign_key :parent_id
9
+ primary_key :id
10
+ check 'price > 100'
11
+ constraint(:xxx) {:yyy == :zzz}
12
+ index :title
13
+ index [:title, :body], :unique => true
14
+ foreign_key :node_id, :nodes
15
+ primary_key [:title, :parent_id], :name => :cpk
16
+ foreign_key [:node_id, :prop_id], :nodes_props, :name => :cfk
17
+ end
18
+ @columns, @indexes, @constraints = @generator.columns, @generator.indexes, @generator.constraints
19
+ end
20
+
21
+ it "should primary key column first" do
22
+ @columns.first[:name].should == :id
23
+ @columns.first[:primary_key].should == true
24
+ @columns[3][:name].should == :parent_id
25
+ @columns[3][:primary_key].should == nil
26
+ end
27
+
28
+ it "counts definitions correctly" do
29
+ @columns.size.should == 5
30
+ @indexes.size.should == 2
31
+ @constraints.size.should == 4
32
+ end
33
+
34
+ it "retrieves primary key name" do
35
+ @generator.primary_key_name.should == :id
36
+ end
37
+
38
+ it "keeps columns in order" do
39
+ @columns[1][:name].should == :title
40
+ @columns[1][:type].should == :string
41
+ @columns[2][:name].should == :body
42
+ @columns[2][:type].should == :text
43
+ end
44
+
45
+ it "creates foreign key column" do
46
+ @columns[3][:name].should == :parent_id
47
+ @columns[3][:type].should == Integer
48
+ @columns[4][:name].should == :node_id
49
+ @columns[4][:type].should == Integer
50
+ end
51
+
52
+ it "uses table for foreign key columns, if specified" do
53
+ @columns[3][:table].should == nil
54
+ @columns[4][:table].should == :nodes
55
+ @constraints[3][:table].should == :nodes_props
56
+ end
57
+
58
+ it "finds columns" do
59
+ [:title, :body, :parent_id, :id].each do |col|
60
+ @generator.has_column?(col).should be_true
61
+ end
62
+ @generator.has_column?(:foo).should_not be_true
63
+ end
64
+
65
+ it "creates constraints" do
66
+ @constraints[0][:name].should == nil
67
+ @constraints[0][:type].should == :check
68
+ @constraints[0][:check].should == ['price > 100']
69
+
70
+ @constraints[1][:name].should == :xxx
71
+ @constraints[1][:type].should == :check
72
+ @constraints[1][:check].should be_a_kind_of(Proc)
73
+
74
+ @constraints[2][:name].should == :cpk
75
+ @constraints[2][:type].should == :primary_key
76
+ @constraints[2][:columns].should == [ :title, :parent_id ]
77
+
78
+ @constraints[3][:name].should == :cfk
79
+ @constraints[3][:type].should == :foreign_key
80
+ @constraints[3][:columns].should == [ :node_id, :prop_id ]
81
+ @constraints[3][:table].should == :nodes_props
82
+ end
83
+
84
+ it "creates indexes" do
85
+ @indexes[0][:columns].should include(:title)
86
+ @indexes[1][:columns].should include(:title)
87
+ @indexes[1][:columns].should include(:body)
88
+ end
89
+ end
90
+
91
+ describe Sequel::Schema::AlterTableGenerator do
92
+ before do
93
+ @generator = Sequel::Schema::AlterTableGenerator.new(SchemaDummyDatabase.new) do
94
+ add_column :aaa, :text
95
+ drop_column :bbb
96
+ rename_column :ccc, :ho
97
+ set_column_type :ddd, :float
98
+ set_column_default :eee, 1
99
+ add_index [:fff, :ggg]
100
+ drop_index :hhh
101
+ drop_index :hhh, :name=>:blah_blah
102
+ add_full_text_index :blah
103
+ add_spatial_index :geom
104
+ add_index :blah, :type => :hash
105
+ add_index :blah, :where => {:something => true}
106
+ add_constraint :con1, 'fred > 100'
107
+ drop_constraint :con2
108
+ add_unique_constraint [:aaa, :bbb, :ccc], :name => :con3
109
+ add_primary_key :id
110
+ add_foreign_key :node_id, :nodes
111
+ add_primary_key [:aaa, :bbb]
112
+ add_foreign_key [:node_id, :prop_id], :nodes_props
113
+ end
114
+ end
115
+
116
+ specify "should generate operation records" do
117
+ @generator.operations.should == [
118
+ {:op => :add_column, :name => :aaa, :type => :text},
119
+ {:op => :drop_column, :name => :bbb},
120
+ {:op => :rename_column, :name => :ccc, :new_name => :ho},
121
+ {:op => :set_column_type, :name => :ddd, :type => :float},
122
+ {:op => :set_column_default, :name => :eee, :default => 1},
123
+ {:op => :add_index, :columns => [:fff, :ggg]},
124
+ {:op => :drop_index, :columns => [:hhh]},
125
+ {:op => :drop_index, :columns => [:hhh], :name=>:blah_blah},
126
+ {:op => :add_index, :columns => [:blah], :type => :full_text},
127
+ {:op => :add_index, :columns => [:geom], :type => :spatial},
128
+ {:op => :add_index, :columns => [:blah], :type => :hash},
129
+ {:op => :add_index, :columns => [:blah], :where => {:something => true}},
130
+ {:op => :add_constraint, :type => :check, :name => :con1, :check => ['fred > 100']},
131
+ {:op => :drop_constraint, :name => :con2},
132
+ {:op => :add_constraint, :type => :unique, :name => :con3, :columns => [:aaa, :bbb, :ccc]},
133
+ {:op => :add_column, :name => :id, :type => Integer, :primary_key=>true, :auto_increment=>true},
134
+ {:op => :add_column, :name => :node_id, :type => Integer, :table=>:nodes},
135
+ {:op => :add_constraint, :type => :primary_key, :columns => [:aaa, :bbb]},
136
+ {:op => :add_constraint, :type => :foreign_key, :columns => [:node_id, :prop_id], :table => :nodes_props}
137
+ ]
138
+ end
139
+ end
140
+
141
+ describe "Sequel::Schema::Generator generic type methods" do
142
+ it "should store the type class in :type for each column" do
143
+ Sequel::Schema::Generator.new(SchemaDummyDatabase.new) do
144
+ String :a
145
+ Integer :b
146
+ Fixnum :c
147
+ Bignum :d
148
+ Float :e
149
+ BigDecimal :f
150
+ Date :g
151
+ DateTime :h
152
+ Time :i
153
+ Numeric :j
154
+ File :k
155
+ TrueClass :l
156
+ FalseClass :m
157
+ end.columns.map{|c| c[:type]}.should == [String, Integer, Fixnum, Bignum, Float, BigDecimal, Date, DateTime, Time, Numeric, File, TrueClass, FalseClass]
158
+ end
159
+ end