viking-sequel 3.10.0

Sign up to get free protection for your applications and to get access to all the features.
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