epugh-sequel 0.0.0

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