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,205 @@
1
+ = Virtual Row Blocks
2
+
3
+ Dataset methods filter, order, and select all take blocks that are referred to as
4
+ virtual row blocks. Many other dataset methods pass the blocks
5
+ they are given into one of those three methods, so there are actually
6
+ many Sequel::Dataset methods that take virtual row blocks.
7
+
8
+ == Regular Proc vs InstanceEvaled Procs
9
+
10
+ Virtual row blocks behave differently depending on whether the block accepts
11
+ an argument. If the block accepts an argument, it is called with an instance
12
+ of Sequel::SQL::VirtualRow. If it does not accept an argument, it is
13
+ evaluated in the context of an instance of Sequel::SQL::VirtualRow.
14
+
15
+ ds = DB[:items]
16
+ # Regular proc
17
+ ds.filter{|o| o.column > 1}
18
+ # WHERE column > 1
19
+
20
+ # Instance-evaled proc
21
+ ds.filter{column > 1}
22
+ # WHERE column > 1
23
+
24
+ If you aren't familiar with the difference between regular blocks and instance
25
+ evaled blocks, you should probably consult a general ruby reference, but briefly,
26
+ with regular procs, methods called without an explicit receiver inside the
27
+ proc call the method on the receiver in the surrounding scope, while instance
28
+ evaled procs call the method on the receiver of the instance_eval call. However,
29
+ in both cases, local variables available in the surrounding scope will be available
30
+ inside the proc. If that doesn't make sense, maybe this example will help:
31
+
32
+ def self.a
33
+ 42
34
+ end
35
+ b = 32
36
+
37
+ # Regular proc
38
+ ds.filter{|o| o.c > a - b}
39
+ # WHERE c > 10
40
+
41
+ # Instance-evaled proc
42
+ ds.filter{c > a - b}
43
+ # WHERE c > (a - 32)
44
+
45
+ There are two related differences here. First is the usage of "o.c" vs "c",
46
+ and second is the difference between the the use of "a". In the regular proc,
47
+ you couldn't call c without an explicit receiver in the proc, unless the self of the
48
+ surrounding scope responded to it. For a, note how ruby calls the method on
49
+ the receiver of the surrounding scope in the regular proc, which returns an integer,
50
+ and does the substraction before Sequel gets access to it. In the instance evaled
51
+ proc, calling a without a receiver calls the a method on the VirtualRow instance.
52
+ For b, note that it operates the same in both cases, as it is a local variable.
53
+
54
+ Basically, the choice for whether to use a regular proc or an instance evaled proc is
55
+ completely up to you. The same things can be accomplished with both.
56
+ Instance evaled procs tend to produce shorter code, but by modifying the scope
57
+ can be more difficult for a new user to understand. That being said, I usually
58
+ use instance evaled procs unless I need to call methods on the receiver of the
59
+ surrounding scope inside the proc.
60
+
61
+ == Local Variables vs Method Calls
62
+
63
+ If you have a method that accepts 0 arguments and has the same name as a local
64
+ variable, you can call it with () to differentiate the method call from the
65
+ local variable access. This is mostly useful in instance_evaled procs:
66
+
67
+ b = 32
68
+ ds.filter{b() > b}
69
+ # WHERE b > 32
70
+
71
+ == VirtualRow Methods
72
+
73
+ VirtualRow is a class that returns SQL::Identifiers, SQL::QualifiedIdentifiers,
74
+ SQL::Functions, or SQL::WindowFunctions depending on how it is called.
75
+
76
+ == SQL::Identifiers - Regular columns
77
+
78
+ SQL::Identifiers can be thought of as regular column references in SQL,
79
+ not qualified by any table. You get an SQL::Identifier if the method is called
80
+ without a block or arguments, and doesn't have a double underscore in the method
81
+ name:
82
+
83
+ ds.filter{|o| o.column > 1}
84
+ ds.filter{column > 1}
85
+ # WHERE column > 1
86
+
87
+ == SQL::QualifiedIdentifiers - Qualified columns
88
+
89
+ SQL::QualifiedIdentifiers can be thought of as column references in SQL that
90
+ are qualified to a specific table. You get an SQL::QualifiedIdentifier if
91
+ the method is called without a block or arguments, and has a double underscore
92
+ in the method name:
93
+
94
+ ds.filter{|o| o.table__column > 1}
95
+ ds.filter{table__column > 1}
96
+ # WHERE table.column > 1
97
+
98
+ Using the double underscore for SQL::QualifiedIdentifiers was done to make
99
+ usage very similar to using symbols, which also translate the double underscore
100
+ into a qualified column.
101
+
102
+ == SQL::Functions - SQL function calls
103
+
104
+ SQL::Functions can be thought of as function calls in SQL. You get a simple
105
+ function call if you call a method with arguments and without a block:
106
+
107
+ ds.filter{|o| o.function(1) > 1}
108
+ ds.filter{function(1) > 1}
109
+ # WHERE function(1) > 1
110
+
111
+ To call a SQL function with multiple arguments, just use those arguments in
112
+ your function call:
113
+
114
+ ds.filter{|o| o.function(1, o.a) > 1}
115
+ ds.filter{function(1, a) > 1}
116
+ # WHERE function(1, a) > 1
117
+
118
+ If the SQL function does not accept any arguments, you need to provide an empty
119
+ block to the method to distinguish it from a call that will produce an
120
+ SQL::Identifier:
121
+
122
+ ds.select{|o| o.version{}}
123
+ ds.select{version{}}
124
+ # SELECT version()
125
+
126
+ To use the SQL wildcard (*) as the sole argument in a function call (most often
127
+ used with the count function), you should provide :* as the sole argument to
128
+ the method, and provide an empty block to the method:
129
+
130
+ ds.select{|o| o.count(:*){}}
131
+ ds.select{count(:*){}}
132
+ # SELECT count(*)
133
+
134
+ To append the DISTINCT keyword before the method arguments, you need to make
135
+ :distinct the first argument of the method call, and provide an empty block to
136
+ the method:
137
+
138
+ ds.select{|o| o.count(:distinct, o.col1){}}
139
+ ds.select{count(:distinct, col1){}}
140
+ # SELECT count(DISTINCT col1)
141
+
142
+ To use multiple columns with the DISTINCT keyword, use multiple arguments in
143
+ the method call:
144
+
145
+ ds.select{|o| o.count(:distinct, o.col1, o.col2){}}
146
+ ds.select{count(:distinct, col1, col2){}}
147
+ # SELECT count(DISTINCT col1, col2)
148
+
149
+ == SQL::WindowFunctions - SQL window function calls
150
+
151
+ SQL::WindowFunctions can be thought of as calls to SQL window functions. Not
152
+ all databases support them, but they are very helpful for certain types of
153
+ queries. To use them, you need to make :over the first argument of the method
154
+ call, with an optional hash as the second argument: Here are some examples of use:
155
+
156
+ ds.select{|o| o.rank(:over){}}
157
+ ds.select{rank(:over){}}
158
+ # SELECT rank() OVER ()
159
+
160
+ ds.select{|o| o.count(:over, :*=>true){}}
161
+ ds.select{count(:over, :*=>true){}}
162
+ # SELECT count(*) OVER ()
163
+
164
+ ds.select{|o| o.sum(:over, :args=>o.col1, :partition=>o.col2, :order=>o.col3){}}
165
+ ds.select{sum(:over, :args=>col1, :partition=>col2, :order=>col3){}}
166
+ # SELECT sum(col1) OVER (PARTITION BY col2 ORDER BY col3)
167
+
168
+ == Returning multiple values
169
+
170
+ It's common when using select and order virtual row blocks to want to
171
+ return multiple values. If you want to do that, you just need to return a single
172
+ array:
173
+
174
+ ds.select{|o| [o.column1, o.sum(o.column2).as(o.sum)]}
175
+ ds.select{[column1, sum(column2).as(sum)]}
176
+ # SELECT column1, sum(column2) AS sum
177
+
178
+ Note that if you forget the array brackets, you'll end up with a syntax error:
179
+
180
+ # Invalid ruby syntax
181
+ ds.select{|o| o.column1, o.sum(o.column2).as(o.sum)}
182
+ ds.select{column1, sum(column2).as(sum)}
183
+
184
+ == Alternative Description of the VirtualRow method call rules
185
+
186
+ * If a block is given:
187
+ * The block is currently not called. This may change in a future version.
188
+ * If there are no arguments, an SQL::Function with the name of
189
+ method used, and no arguments.
190
+ * If the first argument is :*, an SQL::Function is created with a single
191
+ wildcard argument (*).
192
+ * If the first argument is :distinct, an SQL::Function is created with
193
+ the keyword DISTINCT prefacing all remaining arguments.
194
+ * If the first argument is :over, the second argument if provided should
195
+ be a hash of options to pass to SQL::Window. The options hash can also
196
+ contain :*=>true to use a wildcard argument as the function argument, or
197
+ :args=>... to specify an array of arguments to use as the function arguments.
198
+ * If a block is not given:
199
+ * If there are arguments, an SQL::Function is returned with the
200
+ name of the method used and the arguments given.
201
+ * If there are no arguments and the method contains a double
202
+ underscore, split on the double underscore and return an
203
+ SQL::QualifiedIdentifier with the table and column.
204
+ * Otherwise, create an SQL::Identifier with the name of the
205
+ method.
@@ -0,0 +1 @@
1
+ require 'sequel/model'
@@ -0,0 +1,90 @@
1
+ require 'win32ole'
2
+
3
+ module Sequel
4
+ # The ADO adapter provides connectivity to ADO databases in Windows.
5
+ module ADO
6
+ class Database < Sequel::Database
7
+ set_adapter_scheme :ado
8
+
9
+ def initialize(opts)
10
+ super
11
+ @opts[:driver] ||= 'SQL Server'
12
+ case @opts[:driver]
13
+ when 'SQL Server'
14
+ Sequel.ts_require 'adapters/ado/mssql'
15
+ extend Sequel::ADO::MSSQL::DatabaseMethods
16
+ end
17
+ end
18
+
19
+ # Connect to the database. In addition to the usual database options,
20
+ # the following options have an effect:
21
+ #
22
+ # * :command_timeout - Sets the time in seconds to wait while attempting
23
+ # to execute a command before cancelling the attempt and generating
24
+ # an error. Specifically, it sets the ADO CommandTimeout property.
25
+ # If this property is not set, the default of 30 seconds is used.
26
+ # * :conn_string - The full ADO connection string. If this is provided,
27
+ # the usual options are ignored.
28
+ # * :provider - Sets the Provider of this ADO connection (for example, "SQLOLEDB")
29
+ def connect(server)
30
+ opts = server_opts(server)
31
+ s = opts[:conn_string] || "driver=#{opts[:driver]};server=#{opts[:host]};database=#{opts[:database]}#{";uid=#{opts[:user]};pwd=#{opts[:password]}" if opts[:user]}"
32
+ handle = WIN32OLE.new('ADODB.Connection')
33
+ handle.CommandTimeout = opts[:command_timeout] if opts[:command_timeout]
34
+ handle.Provider = opts[:provider] if opts[:provider]
35
+ handle.Open(s)
36
+ handle
37
+ end
38
+
39
+ def dataset(opts = nil)
40
+ ADO::Dataset.new(self, opts)
41
+ end
42
+
43
+ def execute(sql, opts={})
44
+ synchronize(opts[:server]) do |conn|
45
+ begin
46
+ r = log_yield(sql){conn.Execute(sql)}
47
+ yield(r) if block_given?
48
+ rescue ::WIN32OLERuntimeError => e
49
+ raise_error(e)
50
+ end
51
+ end
52
+ nil
53
+ end
54
+ alias do execute
55
+
56
+ private
57
+
58
+ # The ADO adapter doesn't support transactions, since it appears not to
59
+ # use a single native connection for each connection in the pool
60
+ def _transaction(conn)
61
+ th = Thread.current
62
+ begin
63
+ @transactions << th
64
+ yield conn
65
+ rescue Sequel::Rollback
66
+ ensure
67
+ @transactions.delete(th)
68
+ end
69
+ end
70
+
71
+ def disconnect_connection(conn)
72
+ conn.Close
73
+ end
74
+ end
75
+
76
+ class Dataset < Sequel::Dataset
77
+ def fetch_rows(sql)
78
+ execute(sql) do |s|
79
+ @columns = cols = s.Fields.extend(Enumerable).map{|column| output_identifier(column.Name)}
80
+ s.getRows.transpose.each{|r| yield cols.inject({}){|m,c| m[c] = r.shift; m}} unless s.eof
81
+ end
82
+ end
83
+
84
+ # ADO returns nil for all for delete and update statements.
85
+ def provides_accurate_rows_matched?
86
+ false
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,30 @@
1
+ Sequel.require 'adapters/shared/mssql'
2
+
3
+ module Sequel
4
+ module ADO
5
+ # Database and Dataset instance methods for MSSQL specific
6
+ # support via ADO.
7
+ module MSSQL
8
+ module DatabaseMethods
9
+ include Sequel::MSSQL::DatabaseMethods
10
+
11
+ # Return instance of Sequel::ADO::MSSQL::Dataset with the given opts.
12
+ def dataset(opts=nil)
13
+ Sequel::ADO::MSSQL::Dataset.new(self, opts)
14
+ end
15
+ end
16
+
17
+ class Dataset < ADO::Dataset
18
+ include Sequel::MSSQL::DatasetMethods
19
+
20
+ # Use a nasty hack of multiple SQL statements in the same call and
21
+ # having the last one return the most recently inserted id. This
22
+ # is necessary as ADO doesn't provide a consistent native connection.
23
+ def insert(*values)
24
+ return super if @opts[:sql]
25
+ with_sql("SET NOCOUNT ON; #{insert_sql(*values)}; SELECT CAST(SCOPE_IDENTITY() AS INTEGER)").single_value
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,176 @@
1
+ require 'amalgalite'
2
+ Sequel.require 'adapters/shared/sqlite'
3
+
4
+ module Sequel
5
+ # Top level module for holding all Amalgalite-related modules and classes
6
+ # for Sequel.
7
+ module Amalgalite
8
+ # Type conversion map class for Sequel's use of Amalgamite
9
+ class SequelTypeMap < ::Amalgalite::TypeMaps::DefaultMap
10
+ methods_handling_sql_types.delete('string')
11
+ methods_handling_sql_types.merge!(
12
+ 'datetime' => %w'datetime timestamp',
13
+ 'time' => %w'time',
14
+ 'float' => ['float', 'double', 'real', 'double precision'],
15
+ 'decimal' => %w'numeric decimal money'
16
+ )
17
+
18
+ # Return blobs as instances of Sequel::SQL::Blob instead of
19
+ # Amalgamite::Blob
20
+ def blob(s)
21
+ SQL::Blob.new(s)
22
+ end
23
+
24
+ # Return numeric/decimal types as instances of BigDecimal
25
+ # instead of Float
26
+ def decimal(s)
27
+ BigDecimal.new(s)
28
+ end
29
+
30
+ # Return datetime types as instances of Sequel.datetime_class
31
+ def datetime(s)
32
+ Sequel.database_to_application_timestamp(s)
33
+ end
34
+
35
+ # Don't raise an error if the value is a string and the declared
36
+ # type doesn't match a known type, just return the value.
37
+ def result_value_of(declared_type, value)
38
+ if value.is_a?(::Amalgalite::Blob)
39
+ SQL::Blob.new(value.source)
40
+ elsif value.is_a?(String) && declared_type
41
+ (meth = self.class.sql_to_method(declared_type.downcase)) ? send(meth, value) : value
42
+ else
43
+ super
44
+ end
45
+ end
46
+ end
47
+
48
+ # Database class for SQLite databases used with Sequel and the
49
+ # amalgalite driver.
50
+ class Database < Sequel::Database
51
+ include ::Sequel::SQLite::DatabaseMethods
52
+
53
+ set_adapter_scheme :amalgalite
54
+
55
+ # Mimic the file:// uri, by having 2 preceding slashes specify a relative
56
+ # path, and 3 preceding slashes specify an absolute path.
57
+ def self.uri_to_options(uri) # :nodoc:
58
+ { :database => (uri.host.nil? && uri.path == '/') ? nil : "#{uri.host}#{uri.path}" }
59
+ end
60
+ private_class_method :uri_to_options
61
+
62
+ # Connect to the database. Since SQLite is a file based database,
63
+ # the only options available are :database (to specify the database
64
+ # name), and :timeout, to specify how long to wait for the database to
65
+ # be available if it is locked, given in milliseconds (default is 5000).
66
+ def connect(server)
67
+ opts = server_opts(server)
68
+ opts[:database] = ':memory:' if blank_object?(opts[:database])
69
+ db = ::Amalgalite::Database.new(opts[:database])
70
+ db.busy_handler(::Amalgalite::BusyTimeout.new(opts.fetch(:timeout, 5000)/50, 50))
71
+ db.type_map = SequelTypeMap.new
72
+ db
73
+ end
74
+
75
+ # Amalgalite is just the SQLite database without a separate SQLite installation.
76
+ def database_type
77
+ :sqlite
78
+ end
79
+
80
+ # Return instance of Sequel::Amalgalite::Dataset with the given options.
81
+ def dataset(opts = nil)
82
+ Amalgalite::Dataset.new(self, opts)
83
+ end
84
+
85
+ # Run the given SQL with the given arguments. Returns nil.
86
+ def execute_ddl(sql, opts={})
87
+ _execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}}
88
+ nil
89
+ end
90
+
91
+ # Run the given SQL with the given arguments and return the number of changed rows.
92
+ def execute_dui(sql, opts={})
93
+ _execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}; conn.row_changes}
94
+ end
95
+
96
+ # Run the given SQL with the given arguments and return the last inserted row id.
97
+ def execute_insert(sql, opts={})
98
+ _execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}; conn.last_insert_rowid}
99
+ end
100
+
101
+ # Run the given SQL with the given arguments and yield each row.
102
+ def execute(sql, opts={})
103
+ _execute(sql, opts) do |conn|
104
+ begin
105
+ yield(stmt = log_yield(sql){conn.prepare(sql)})
106
+ ensure
107
+ stmt.close if stmt
108
+ end
109
+ end
110
+ end
111
+
112
+ # Run the given SQL with the given arguments and return the first value of the first row.
113
+ def single_value(sql, opts={})
114
+ _execute(sql, opts){|conn| log_yield(sql){conn.first_value_from(sql)}}
115
+ end
116
+
117
+ private
118
+
119
+ # Yield an available connection. Rescue
120
+ # any Amalgalite::Errors and turn them into DatabaseErrors.
121
+ def _execute(sql, opts)
122
+ begin
123
+ synchronize(opts[:server]){|conn| yield conn}
124
+ rescue ::Amalgalite::Error, ::Amalgalite::SQLite3::Error => e
125
+ raise_error(e)
126
+ end
127
+ end
128
+
129
+ # The Amagalite adapter does not need the pool to convert exceptions.
130
+ # Also, force the max connections to 1 if a memory database is being
131
+ # used, as otherwise each connection gets a separate database.
132
+ def connection_pool_default_options
133
+ o = super.dup
134
+ # Default to only a single connection if a memory database is used,
135
+ # because otherwise each connection will get a separate database
136
+ o[:max_connections] = 1 if @opts[:database] == ':memory:' || blank_object?(@opts[:database])
137
+ o
138
+ end
139
+
140
+ # Both main error classes that Amalgalite raises
141
+ def database_error_classes
142
+ [::Amalgalite::Error, ::Amalgalite::SQLite3::Error]
143
+ end
144
+
145
+ # Disconnect given connections from the database.
146
+ def disconnect_connection(c)
147
+ c.close
148
+ end
149
+ end
150
+
151
+ # Dataset class for SQLite datasets that use the amalgalite driver.
152
+ class Dataset < Sequel::Dataset
153
+ include ::Sequel::SQLite::DatasetMethods
154
+
155
+ # Yield a hash for each row in the dataset.
156
+ def fetch_rows(sql)
157
+ execute(sql) do |stmt|
158
+ @columns = cols = stmt.result_fields.map{|c| output_identifier(c)}
159
+ col_count = cols.size
160
+ stmt.each do |result|
161
+ row = {}
162
+ col_count.times{|i| row[cols[i]] = result[i]}
163
+ yield row
164
+ end
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ # Quote the string using the adapter instance method.
171
+ def literal_string(v)
172
+ db.synchronize{|c| c.quote(v)}
173
+ end
174
+ end
175
+ end
176
+ end