epugh-sequel 0.0.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 (134) hide show
  1. data/README.rdoc +652 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/sequel +104 -0
  4. data/lib/sequel.rb +1 -0
  5. data/lib/sequel/adapters/ado.rb +85 -0
  6. data/lib/sequel/adapters/db2.rb +132 -0
  7. data/lib/sequel/adapters/dbi.rb +101 -0
  8. data/lib/sequel/adapters/do.rb +197 -0
  9. data/lib/sequel/adapters/do/mysql.rb +38 -0
  10. data/lib/sequel/adapters/do/postgres.rb +92 -0
  11. data/lib/sequel/adapters/do/sqlite.rb +31 -0
  12. data/lib/sequel/adapters/firebird.rb +307 -0
  13. data/lib/sequel/adapters/informix.rb +75 -0
  14. data/lib/sequel/adapters/jdbc.rb +485 -0
  15. data/lib/sequel/adapters/jdbc/h2.rb +62 -0
  16. data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
  17. data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
  18. data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
  19. data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
  20. data/lib/sequel/adapters/mysql.rb +370 -0
  21. data/lib/sequel/adapters/odbc.rb +184 -0
  22. data/lib/sequel/adapters/openbase.rb +57 -0
  23. data/lib/sequel/adapters/oracle.rb +140 -0
  24. data/lib/sequel/adapters/postgres.rb +453 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +93 -0
  26. data/lib/sequel/adapters/shared/mysql.rb +341 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +62 -0
  28. data/lib/sequel/adapters/shared/postgres.rb +743 -0
  29. data/lib/sequel/adapters/shared/progress.rb +34 -0
  30. data/lib/sequel/adapters/shared/sqlite.rb +263 -0
  31. data/lib/sequel/adapters/sqlite.rb +243 -0
  32. data/lib/sequel/adapters/utils/date_format.rb +21 -0
  33. data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
  34. data/lib/sequel/adapters/utils/unsupported.rb +62 -0
  35. data/lib/sequel/connection_pool.rb +258 -0
  36. data/lib/sequel/core.rb +204 -0
  37. data/lib/sequel/core_sql.rb +185 -0
  38. data/lib/sequel/database.rb +687 -0
  39. data/lib/sequel/database/schema_generator.rb +324 -0
  40. data/lib/sequel/database/schema_methods.rb +164 -0
  41. data/lib/sequel/database/schema_sql.rb +324 -0
  42. data/lib/sequel/dataset.rb +422 -0
  43. data/lib/sequel/dataset/convenience.rb +237 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +220 -0
  45. data/lib/sequel/dataset/sql.rb +1105 -0
  46. data/lib/sequel/deprecated.rb +529 -0
  47. data/lib/sequel/exceptions.rb +44 -0
  48. data/lib/sequel/extensions/blank.rb +42 -0
  49. data/lib/sequel/extensions/inflector.rb +288 -0
  50. data/lib/sequel/extensions/pagination.rb +96 -0
  51. data/lib/sequel/extensions/pretty_table.rb +78 -0
  52. data/lib/sequel/extensions/query.rb +48 -0
  53. data/lib/sequel/extensions/string_date_time.rb +47 -0
  54. data/lib/sequel/metaprogramming.rb +44 -0
  55. data/lib/sequel/migration.rb +212 -0
  56. data/lib/sequel/model.rb +142 -0
  57. data/lib/sequel/model/association_reflection.rb +263 -0
  58. data/lib/sequel/model/associations.rb +1024 -0
  59. data/lib/sequel/model/base.rb +911 -0
  60. data/lib/sequel/model/deprecated.rb +188 -0
  61. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  62. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  63. data/lib/sequel/model/deprecated_validations.rb +384 -0
  64. data/lib/sequel/model/errors.rb +37 -0
  65. data/lib/sequel/model/exceptions.rb +7 -0
  66. data/lib/sequel/model/inflections.rb +230 -0
  67. data/lib/sequel/model/plugins.rb +74 -0
  68. data/lib/sequel/object_graph.rb +230 -0
  69. data/lib/sequel/plugins/caching.rb +122 -0
  70. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  71. data/lib/sequel/plugins/schema.rb +53 -0
  72. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  73. data/lib/sequel/plugins/validation_class_methods.rb +373 -0
  74. data/lib/sequel/sql.rb +854 -0
  75. data/lib/sequel/version.rb +11 -0
  76. data/lib/sequel_core.rb +1 -0
  77. data/lib/sequel_model.rb +1 -0
  78. data/spec/adapters/ado_spec.rb +46 -0
  79. data/spec/adapters/firebird_spec.rb +376 -0
  80. data/spec/adapters/informix_spec.rb +96 -0
  81. data/spec/adapters/mysql_spec.rb +875 -0
  82. data/spec/adapters/oracle_spec.rb +272 -0
  83. data/spec/adapters/postgres_spec.rb +692 -0
  84. data/spec/adapters/spec_helper.rb +10 -0
  85. data/spec/adapters/sqlite_spec.rb +550 -0
  86. data/spec/core/connection_pool_spec.rb +526 -0
  87. data/spec/core/core_ext_spec.rb +156 -0
  88. data/spec/core/core_sql_spec.rb +528 -0
  89. data/spec/core/database_spec.rb +1214 -0
  90. data/spec/core/dataset_spec.rb +3513 -0
  91. data/spec/core/expression_filters_spec.rb +363 -0
  92. data/spec/core/migration_spec.rb +261 -0
  93. data/spec/core/object_graph_spec.rb +280 -0
  94. data/spec/core/pretty_table_spec.rb +58 -0
  95. data/spec/core/schema_generator_spec.rb +167 -0
  96. data/spec/core/schema_spec.rb +778 -0
  97. data/spec/core/spec_helper.rb +82 -0
  98. data/spec/core/version_spec.rb +7 -0
  99. data/spec/extensions/blank_spec.rb +67 -0
  100. data/spec/extensions/caching_spec.rb +201 -0
  101. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  102. data/spec/extensions/inflector_spec.rb +122 -0
  103. data/spec/extensions/pagination_spec.rb +99 -0
  104. data/spec/extensions/pretty_table_spec.rb +91 -0
  105. data/spec/extensions/query_spec.rb +85 -0
  106. data/spec/extensions/schema_spec.rb +111 -0
  107. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  108. data/spec/extensions/spec_helper.rb +90 -0
  109. data/spec/extensions/string_date_time_spec.rb +93 -0
  110. data/spec/extensions/validation_class_methods_spec.rb +1054 -0
  111. data/spec/integration/dataset_test.rb +160 -0
  112. data/spec/integration/eager_loader_test.rb +683 -0
  113. data/spec/integration/prepared_statement_test.rb +130 -0
  114. data/spec/integration/schema_test.rb +183 -0
  115. data/spec/integration/spec_helper.rb +75 -0
  116. data/spec/integration/type_test.rb +96 -0
  117. data/spec/model/association_reflection_spec.rb +93 -0
  118. data/spec/model/associations_spec.rb +1780 -0
  119. data/spec/model/base_spec.rb +494 -0
  120. data/spec/model/caching_spec.rb +217 -0
  121. data/spec/model/dataset_methods_spec.rb +78 -0
  122. data/spec/model/eager_loading_spec.rb +1165 -0
  123. data/spec/model/hooks_spec.rb +472 -0
  124. data/spec/model/inflector_spec.rb +126 -0
  125. data/spec/model/model_spec.rb +588 -0
  126. data/spec/model/plugins_spec.rb +142 -0
  127. data/spec/model/record_spec.rb +1243 -0
  128. data/spec/model/schema_spec.rb +92 -0
  129. data/spec/model/spec_helper.rb +124 -0
  130. data/spec/model/validations_spec.rb +1080 -0
  131. data/spec/rcov.opts +6 -0
  132. data/spec/spec.opts +0 -0
  133. data/spec/spec_config.rb.example +10 -0
  134. metadata +202 -0
@@ -0,0 +1,21 @@
1
+ # Module containing overrides for Sequel's standard date/time literalization
2
+ # to use the SQL standrd. The SQL standard is used by fewer databases than
3
+ # the defacto standard (which is just a normal string).
4
+ module Sequel::Dataset::SQLStandardDateFormat
5
+ private
6
+
7
+ # Use SQL standard syntax for Date
8
+ def literal_date(v)
9
+ v.strftime("DATE '%Y-%m-%d'")
10
+ end
11
+
12
+ # Use SQL standard syntax for DateTime
13
+ def literal_datetime(v)
14
+ v.strftime("TIMESTAMP '%Y-%m-%d %H:%M:%S'")
15
+ end
16
+
17
+ # Use SQL standard syntax for Time
18
+ def literal_time(v)
19
+ v.strftime("TIMESTAMP '%Y-%m-%d %H:%M:%S'")
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+ module Sequel
2
+ class Dataset
3
+ module StoredProcedureMethods
4
+ SQL_QUERY_TYPE = Hash.new{|h,k| h[k] = k}
5
+ SQL_QUERY_TYPE[:first] = SQL_QUERY_TYPE[:all] = :select
6
+
7
+ # The name of the stored procedure to call
8
+ attr_accessor :sproc_name
9
+
10
+ # Call the prepared statement
11
+ def call(*args, &block)
12
+ @sproc_args = args
13
+ case @sproc_type
14
+ when :select, :all
15
+ all(&block)
16
+ when :first
17
+ first
18
+ when :insert
19
+ insert
20
+ when :update
21
+ update
22
+ when :delete
23
+ delete
24
+ end
25
+ end
26
+
27
+ # Programmer friendly string showing this is a stored procedure,
28
+ # showing the name of the procedure.
29
+ def inspect
30
+ "<#{self.class.name}/StoredProcedure name=#{@sproc_name}>"
31
+ end
32
+
33
+ # Set the type of the sproc and override the corresponding _sql
34
+ # method to return the empty string (since the result will be
35
+ # ignored anyway).
36
+ def sproc_type=(type)
37
+ @sproc_type = type
38
+ meta_def("#{sql_query_type}_sql"){|*a| ''}
39
+ end
40
+
41
+ private
42
+
43
+ # The type of query (:select, :insert, :delete, :update).
44
+ def sql_query_type
45
+ SQL_QUERY_TYPE[@sproc_type]
46
+ end
47
+ end
48
+
49
+ module StoredProcedures
50
+ # For the given type (:select, :first, :insert, :update, or :delete),
51
+ # run the database stored procedure with the given name with the given
52
+ # arguments.
53
+ def call_sproc(type, name, *args)
54
+ prepare_sproc(type, name).call(*args)
55
+ end
56
+
57
+ # Transform this dataset into a stored procedure that you can call
58
+ # multiple times with new arguments.
59
+ def prepare_sproc(type, name)
60
+ sp = clone
61
+ prepare_extend_sproc(sp)
62
+ sp.sproc_type = type
63
+ sp.sproc_name = name
64
+ sp
65
+ end
66
+
67
+ private
68
+
69
+ # Extend the dataset with the stored procedure methods.
70
+ def prepare_extend_sproc(ds)
71
+ ds.extend(StoredProcedureMethods)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,62 @@
1
+ class Sequel::Dataset
2
+ # This module should be included in the dataset class for all databases that
3
+ # don't support INTERSECT or EXCEPT.
4
+ module UnsupportedIntersectExcept
5
+ # Raise an Error if EXCEPT is used
6
+ def except(ds, all=false)
7
+ raise(Sequel::Error, "EXCEPT not supported")
8
+ end
9
+
10
+ # Raise an Error if INTERSECT is used
11
+ def intersect(ds, all=false)
12
+ raise(Sequel::Error, "INTERSECT not supported")
13
+ end
14
+
15
+ private
16
+
17
+ # Since EXCEPT and INTERSECT are not supported, and order shouldn't matter
18
+ # when UNION is used, don't worry about parantheses. This may potentially
19
+ # give incorrect results if UNION ALL is used.
20
+ def select_compounds_sql(sql, opts)
21
+ return unless opts[:compounds]
22
+ opts[:compounds].each do |type, dataset, all|
23
+ sql << " #{type.to_s.upcase}#{' ALL' if all} #{subselect_sql(dataset)}"
24
+ end
25
+ end
26
+ end
27
+
28
+ # This module should be included in the dataset class for all databases that
29
+ # don't support INTERSECT ALL or EXCEPT ALL.
30
+ module UnsupportedIntersectExceptAll
31
+ # Raise an Error if EXCEPT is used
32
+ def except(ds, all=false)
33
+ raise(Sequel::Error, "EXCEPT ALL not supported") if all
34
+ super(ds)
35
+ end
36
+
37
+ # Raise an Error if INTERSECT is used
38
+ def intersect(ds, all=false)
39
+ raise(Sequel::Error, "INTERSECT ALL not supported") if all
40
+ super(ds)
41
+ end
42
+ end
43
+
44
+ # This module should be included in the dataset class for all databases that
45
+ # don't support IS [NOT] (TRUE|FALSE)
46
+ module UnsupportedIsTrue
47
+ # Use an = construct instead of IS and an != OR IS NULL construct instead of IS NOT.
48
+ def complex_expression_sql(op, args)
49
+ case op
50
+ when :IS, :'IS NOT'
51
+ isnot = op != :IS
52
+ return super if (v1 = args.at(1)).nil?
53
+ v0 = literal(args.at(0))
54
+ s = "(#{v0} #{'!' if isnot}= #{literal(v1)})"
55
+ s = "(#{s} OR (#{v0} IS NULL))" if isnot
56
+ s
57
+ else
58
+ super(op, args)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,258 @@
1
+ # A ConnectionPool manages access to database connections by keeping
2
+ # multiple connections and giving threads exclusive access to each
3
+ # connection.
4
+ class Sequel::ConnectionPool
5
+ # The proc used to create a new database connection.
6
+ attr_accessor :connection_proc
7
+
8
+ # The proc used to disconnect a database connection.
9
+ attr_accessor :disconnection_proc
10
+
11
+ # The maximum number of connections.
12
+ attr_reader :max_size
13
+
14
+ # The mutex that protects access to the other internal vairables. You must use
15
+ # this if you want to manipulate the variables safely.
16
+ attr_reader :mutex
17
+
18
+ # Constructs a new pool with a maximum size. If a block is supplied, it
19
+ # is used to create new connections as they are needed.
20
+ #
21
+ # pool = ConnectionPool.new(:max_connections=>10) {MyConnection.new(opts)}
22
+ #
23
+ # The connection creation proc can be changed at any time by assigning a
24
+ # Proc to pool#connection_proc.
25
+ #
26
+ # pool = ConnectionPool.new(:max_connections=>10)
27
+ # pool.connection_proc = proc {MyConnection.new(opts)}
28
+ #
29
+ # The connection pool takes the following options:
30
+ #
31
+ # * :max_connections - The maximum number of connections the connection pool
32
+ # will open (default 4)
33
+ # * :pool_convert_exceptions - Whether to convert non-StandardError based exceptions
34
+ # to RuntimeError exceptions (default true)
35
+ # * :pool_sleep_time - The amount of time to sleep before attempting to acquire
36
+ # a connection again (default 0.001)
37
+ # * :pool_timeout - The amount of seconds to wait to acquire a connection
38
+ # before raising a PoolTimeoutError (default 5)
39
+ # * :servers - A hash of servers to use. Keys should be symbols. If not
40
+ # present, will use a single :default server. The server name symbol will
41
+ # be passed to the connection_proc.
42
+ def initialize(opts = {}, &block)
43
+ @max_size = opts[:max_connections] || 4
44
+ @mutex = Mutex.new
45
+ @connection_proc = block
46
+ @disconnection_proc = opts[:disconnection_proc]
47
+ @servers = [:default]
48
+ @servers += opts[:servers].keys - @servers if opts[:servers]
49
+ @available_connections = Hash.new{|h,k| h[:default]}
50
+ @allocated = Hash.new{|h,k| h[:default]}
51
+ @created_count = Hash.new{|h,k| h[:default]}
52
+ @servers.each do |s|
53
+ @available_connections[s] = []
54
+ @allocated[s] = {}
55
+ @created_count[s] = 0
56
+ end
57
+ @timeout = opts[:pool_timeout] || 5
58
+ @sleep_time = opts[:pool_sleep_time] || 0.001
59
+ @convert_exceptions = opts.include?(:pool_convert_exceptions) ? opts[:pool_convert_exceptions] : true
60
+ end
61
+
62
+ # A hash of connections currently being used for the given server, key is the
63
+ # Thread, value is the connection.
64
+ def allocated(server=:default)
65
+ @allocated[server]
66
+ end
67
+
68
+ # An array of connections opened but not currently used, for the given
69
+ # server.
70
+ def available_connections(server=:default)
71
+ @available_connections[server]
72
+ end
73
+
74
+ # The total number of connections opened for the given server, should
75
+ # be equal to available_connections.length + allocated.length
76
+ def created_count(server=:default)
77
+ @created_count[server]
78
+ end
79
+ alias size created_count
80
+
81
+ # Chooses the first available connection to the given server, or if none are
82
+ # available, creates a new connection. Passes the connection to the supplied
83
+ # block:
84
+ #
85
+ # pool.hold {|conn| conn.execute('DROP TABLE posts')}
86
+ #
87
+ # Pool#hold is re-entrant, meaning it can be called recursively in
88
+ # the same thread without blocking.
89
+ #
90
+ # If no connection is immediately available and the pool is already using the maximum
91
+ # number of connections, Pool#hold will block until a connection
92
+ # is available or the timeout expires. If the timeout expires before a
93
+ # connection can be acquired, a Sequel::Error::PoolTimeoutError is
94
+ # raised.
95
+ def hold(server=:default)
96
+ begin
97
+ t = Thread.current
98
+ time = Time.new
99
+ timeout = time + @timeout
100
+ sleep_time = @sleep_time
101
+ if conn = owned_connection(t, server)
102
+ return yield(conn)
103
+ end
104
+ until conn = acquire(t, server)
105
+ raise(::Sequel::Error::PoolTimeoutError) if Time.new > timeout
106
+ sleep sleep_time
107
+ end
108
+ begin
109
+ yield conn
110
+ rescue Sequel::DatabaseDisconnectError => dde
111
+ remove(t, conn, server)
112
+ raise
113
+ ensure
114
+ release(t, conn, server) unless dde
115
+ end
116
+ rescue Exception => e
117
+ raise(@convert_exceptions && !e.is_a?(StandardError) ? RuntimeError.new(e.message) : e)
118
+ end
119
+ end
120
+
121
+ # Removes all connection currently available on all servers, optionally
122
+ # yielding each connection to the given block. This method has the effect of
123
+ # disconnecting from the database, assuming that no connections are currently
124
+ # being used. Once a connection is requested using #hold, the connection pool
125
+ # creates new connections to the database.
126
+ def disconnect(&block)
127
+ block ||= @disconnection_proc
128
+ @mutex.synchronize do
129
+ @available_connections.each do |server, conns|
130
+ conns.each{|c| block.call(c)} if block
131
+ conns.clear
132
+ set_created_count(server, allocated(server).length)
133
+ end
134
+ end
135
+ end
136
+
137
+ private
138
+
139
+ # Assigns a connection to the supplied thread for the given server, if one
140
+ # is available.
141
+ def acquire(thread, server)
142
+ @mutex.synchronize do
143
+ if conn = available(server)
144
+ allocated(server)[thread] = conn
145
+ end
146
+ end
147
+ end
148
+
149
+ # Returns an available connection to the given server. If no connection is
150
+ # available, tries to create a new connection.
151
+ def available(server)
152
+ available_connections(server).pop || make_new(server)
153
+ end
154
+
155
+ # Creates a new connection to the given server if the size of the pool for
156
+ # the server is less than the maximum size of the pool.
157
+ def make_new(server)
158
+ if @created_count[server] < @max_size
159
+ raise(Sequel::Error, "No connection proc specified") unless @connection_proc
160
+ begin
161
+ conn = @connection_proc.call(server)
162
+ rescue Exception=>exception
163
+ e = Sequel::DatabaseConnectionError.new("#{exception.class} #{exception.message}")
164
+ e.set_backtrace(exception.backtrace)
165
+ raise e
166
+ end
167
+ raise(Sequel::DatabaseConnectionError, "Connection parameters not valid") unless conn
168
+ set_created_count(server, @created_count[server] + 1)
169
+ conn
170
+ end
171
+ end
172
+
173
+ # Returns the connection owned by the supplied thread for the given server,
174
+ # if any.
175
+ def owned_connection(thread, server)
176
+ @mutex.synchronize{@allocated[server][thread]}
177
+ end
178
+
179
+ # Releases the connection assigned to the supplied thread and server.
180
+ def release(thread, conn, server)
181
+ @mutex.synchronize do
182
+ allocated(server).delete(thread)
183
+ available_connections(server) << conn
184
+ end
185
+ end
186
+
187
+ # Removes the currently allocated connection from the connection pool.
188
+ def remove(thread, conn, server)
189
+ @mutex.synchronize do
190
+ allocated(server).delete(thread)
191
+ set_created_count(server, @created_count[server] - 1)
192
+ @disconnection_proc.call(conn) if @disconnection_proc
193
+ end
194
+ end
195
+
196
+ # Set the created count for the given server type
197
+ def set_created_count(server, value)
198
+ server = :default unless @created_count.include?(server)
199
+ @created_count[server] = value
200
+ end
201
+ end
202
+
203
+ # A SingleThreadedPool acts as a replacement for a ConnectionPool for use
204
+ # in single-threaded applications. ConnectionPool imposes a substantial
205
+ # performance penalty, so SingleThreadedPool is used to gain some speed.
206
+ #
207
+ # Note that using a single threaded pool with some adapters can cause
208
+ # errors in certain cases, see Sequel.single_threaded=.
209
+ class Sequel::SingleThreadedPool
210
+ # The proc used to create a new database connection
211
+ attr_writer :connection_proc
212
+
213
+ # The proc used to disconnect a database connection.
214
+ attr_accessor :disconnection_proc
215
+
216
+ # Initializes the instance with the supplied block as the connection_proc.
217
+ #
218
+ # The single threaded pool takes the following options:
219
+ #
220
+ # * :pool_convert_exceptions - Whether to convert non-StandardError based exceptions
221
+ # to RuntimeError exceptions (default true)
222
+ def initialize(opts={}, &block)
223
+ @connection_proc = block
224
+ @disconnection_proc = opts[:disconnection_proc]
225
+ @conns = {}
226
+ @convert_exceptions = opts.include?(:pool_convert_exceptions) ? opts[:pool_convert_exceptions] : true
227
+ end
228
+
229
+ # The connection for the given server.
230
+ def conn(server=:default)
231
+ @conns[server]
232
+ end
233
+
234
+ # Yields the connection to the supplied block for the given server.
235
+ # This method simulates the ConnectionPool#hold API.
236
+ def hold(server=:default)
237
+ begin
238
+ begin
239
+ yield(c = (@conns[server] ||= @connection_proc.call(server)))
240
+ rescue Sequel::DatabaseDisconnectError => dde
241
+ @conns.delete(server)
242
+ @disconnection_proc.call(c) if @disconnection_proc
243
+ raise
244
+ end
245
+ rescue Exception => e
246
+ # if the error is not a StandardError it is converted into RuntimeError.
247
+ raise(@convert_exceptions && !e.is_a?(StandardError) ? RuntimeError.new(e.message) : e)
248
+ end
249
+ end
250
+
251
+ # Disconnects from the database. Once a connection is requested using
252
+ # #hold, the connection is reestablished.
253
+ def disconnect(&block)
254
+ block ||= @disconnection_proc
255
+ @conns.values.each{|conn| block.call(conn) if block}
256
+ @conns = {}
257
+ end
258
+ end
@@ -0,0 +1,204 @@
1
+ %w'bigdecimal bigdecimal/util date enumerator thread time uri yaml'.each do |f|
2
+ require f
3
+ end
4
+
5
+ # Top level module for Sequel
6
+ #
7
+ # There are some class methods that are added via metaprogramming, one for
8
+ # each supported adapter. For example:
9
+ #
10
+ # DB = Sequel.sqlite # Memory database
11
+ # DB = Sequel.sqlite('blog.db')
12
+ # DB = Sequel.postgres('database_name', :user=>'user',
13
+ # :password=>'password', :host=>'host', :port=>5432,
14
+ # :max_connections=>10)
15
+ #
16
+ # If a block is given to these methods, it is passed the opened Database
17
+ # object, which is closed (disconnected) when the block exits. For example:
18
+ #
19
+ # Sequel.sqlite('blog.db'){|db| puts db.users.count}
20
+ #
21
+ # Sequel converts the column type tinyint to a boolean by default,
22
+ # you can override the conversion to use tinyint as an integer:
23
+ #
24
+ # Sequel.convert_tinyint_to_bool = false
25
+ #
26
+ # Sequel converts two digit years in Dates and DateTimes by default,
27
+ # so 01/02/03 is interpreted at January 2nd, 2003, and 12/13/99 is interpreted
28
+ # as December 13, 1999.. You can override this # to treat those dates as
29
+ # January 2nd, 0003 and December 13, 0099, respectively, by setting:
30
+ #
31
+ # Sequel.convert_two_digit_years = false
32
+ #
33
+ # Sequel can use either Time or DateTime for times returned from the
34
+ # database. It defaults to Time. To change it to DateTime, use:
35
+ #
36
+ # Sequel.datetime_class = DateTime
37
+ #
38
+ # Sequel currently does not use instance_eval for virtual row blocks by default
39
+ # (e.g. the block passed to Dataset#filter, #select, #order and other similar
40
+ # methods). If you want to use instance_eval for these blocks, don't have any
41
+ # block arguments, and set:
42
+ #
43
+ # Sequel.virtual_row_instance_eval = true
44
+ #
45
+ # When this is set, you can do:
46
+ #
47
+ # dataset.filter{|o| o.column > 0} # no instance_eval
48
+ # dataset.filter{column > 0} # instance eval
49
+ #
50
+ # When the virtual_row_instance_eval is false, using a virtual row block without a block
51
+ # argument will generate a deprecation message.
52
+ #
53
+ # The option to not use instance_eval for a block with no arguments will be removed in a future version.
54
+ # If you have any virtual row blocks that you don't want to use instance_eval for,
55
+ # make sure the blocks have block arguments.
56
+ module Sequel
57
+ @convert_tinyint_to_bool = true
58
+ @convert_two_digit_years = true
59
+ @datetime_class = Time
60
+ @virtual_row_instance_eval = false
61
+
62
+ class << self
63
+ attr_accessor :convert_tinyint_to_bool, :convert_two_digit_years, :datetime_class, :virtual_row_instance_eval
64
+ end
65
+
66
+ # Creates a new database object based on the supplied connection string
67
+ # and optional arguments. The specified scheme determines the database
68
+ # class used, and the rest of the string specifies the connection options.
69
+ # For example:
70
+ #
71
+ # DB = Sequel.connect('sqlite:/') # Memory database
72
+ # DB = Sequel.connect('sqlite://blog.db') # ./blog.db
73
+ # DB = Sequel.connect('sqlite:///blog.db') # /blog.db
74
+ # DB = Sequel.connect('postgres://user:password@host:port/database_name')
75
+ # DB = Sequel.connect('sqlite:///blog.db', :max_connections=>10)
76
+ #
77
+ # If a block is given, it is passed the opened Database object, which is
78
+ # closed when the block exits. For example:
79
+ #
80
+ # Sequel.connect('sqlite://blog.db'){|db| puts db[:users].count}
81
+ def self.connect(*args, &block)
82
+ Database.connect(*args, &block)
83
+ end
84
+
85
+ # Set the method to call on identifiers going into the database. This affects
86
+ # the literalization of identifiers by calling this method on them before they are input.
87
+ # Sequel upcases identifiers in all SQL strings for most databases, so to turn that off:
88
+ #
89
+ # Sequel.identifier_input_method = nil
90
+ #
91
+ # to downcase instead:
92
+ #
93
+ # Sequel.identifier_input_method = :downcase
94
+ #
95
+ # Other string methods work as well.
96
+ def self.identifier_input_method=(value)
97
+ Database.identifier_input_method = value
98
+ end
99
+
100
+ # Set the method to call on identifiers coming out of the database. This affects
101
+ # the literalization of identifiers by calling this method on them when they are
102
+ # retrieved from the database. Sequel downcases identifiers retrieved for most
103
+ # databases, so to turn that off:
104
+ #
105
+ # Sequel.identifier_output_method = nil
106
+ #
107
+ # to upcase instead:
108
+ #
109
+ # Sequel.identifier_output_method = :upcase
110
+ #
111
+ # Other string methods work as well.
112
+ def self.identifier_output_method=(value)
113
+ Database.identifier_output_method = value
114
+ end
115
+
116
+ # Set whether to quote identifiers for all databases by default. By default,
117
+ # Sequel quotes identifiers in all SQL strings, so to turn that off:
118
+ #
119
+ # Sequel.quote_identifiers = false
120
+ def self.quote_identifiers=(value)
121
+ Database.quote_identifiers = value
122
+ end
123
+
124
+ # Require all given files which should be in the same or a subdirectory of
125
+ # this file
126
+ def self.require(files, subdir=nil)
127
+ Array(files).each{|f| super("#{File.dirname(__FILE__)}/#{"#{subdir}/" if subdir}#{f}")}
128
+ end
129
+
130
+ # Set whether to set the single threaded mode for all databases by default. By default,
131
+ # Sequel uses a threadsafe connection pool, which isn't as fast as the
132
+ # single threaded connection pool. If your program will only have one thread,
133
+ # and speed is a priority, you may want to set this to true:
134
+ #
135
+ # Sequel.single_threaded = true
136
+ def self.single_threaded=(value)
137
+ Database.single_threaded = value
138
+ end
139
+
140
+ # Converts a string into a Date object.
141
+ def self.string_to_date(s)
142
+ begin
143
+ Date.parse(s, Sequel.convert_two_digit_years)
144
+ rescue => e
145
+ raise Error::InvalidValue, "Invalid Date value '#{self}' (#{e.message})"
146
+ end
147
+ end
148
+
149
+ # Converts a string into a Time or DateTime object, depending on the
150
+ # value of Sequel.datetime_class.
151
+ def self.string_to_datetime(s)
152
+ begin
153
+ if datetime_class == DateTime
154
+ DateTime.parse(s, convert_two_digit_years)
155
+ else
156
+ datetime_class.parse(s)
157
+ end
158
+ rescue => e
159
+ raise Error::InvalidValue, "Invalid #{datetime_class} value '#{self}' (#{e.message})"
160
+ end
161
+ end
162
+
163
+ # Converts a string into a Time object.
164
+ def self.string_to_time(s)
165
+ begin
166
+ Time.parse(s)
167
+ rescue => e
168
+ raise Error::InvalidValue, "Invalid Time value '#{self}' (#{e.message})"
169
+ end
170
+ end
171
+
172
+ ### Private Class Methods ###
173
+
174
+ # Helper method that the database adapter class methods that are added to Sequel via
175
+ # metaprogramming use to parse arguments.
176
+ def self.adapter_method(adapter, *args, &block) # :nodoc:
177
+ raise(::Sequel::Error, "Wrong number of arguments, 0-2 arguments valid") if args.length > 2
178
+ opts = {:adapter=>adapter.to_sym}
179
+ opts[:database] = args.shift if args.length >= 1 && !(args[0].is_a?(Hash))
180
+ if Hash === (arg = args[0])
181
+ opts.merge!(arg)
182
+ elsif !arg.nil?
183
+ raise ::Sequel::Error, "Wrong format of arguments, either use (), (String), (Hash), or (String, Hash)"
184
+ end
185
+ connect(opts, &block)
186
+ end
187
+
188
+ # Method that adds a database adapter class method to Sequel that calls
189
+ # Sequel.adapter_method.
190
+ def self.def_adapter_method(*adapters) # :nodoc:
191
+ adapters.each do |adapter|
192
+ instance_eval("def #{adapter}(*args, &block); adapter_method('#{adapter}', *args, &block) end")
193
+ end
194
+ end
195
+
196
+ private_class_method :adapter_method, :def_adapter_method
197
+
198
+ require(%w"metaprogramming sql core_sql connection_pool exceptions dataset migration database object_graph version deprecated")
199
+ require(%w"schema_generator schema_methods schema_sql", 'database')
200
+ require(%w"convenience prepared_statements sql", 'dataset')
201
+
202
+ # Add the database adapter class methods to Sequel via metaprogramming
203
+ def_adapter_method(*Database::ADAPTERS)
204
+ end