sequel_core 2.2.0 → 3.8.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 (66) hide show
  1. metadata +30 -101
  2. data/CHANGELOG +0 -1519
  3. data/COPYING +0 -19
  4. data/README +0 -313
  5. data/Rakefile +0 -158
  6. data/bin/sequel +0 -117
  7. data/doc/cheat_sheet.rdoc +0 -225
  8. data/doc/dataset_filtering.rdoc +0 -182
  9. data/lib/sequel_core.rb +0 -136
  10. data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -68
  11. data/lib/sequel_core/adapters/ado.rb +0 -90
  12. data/lib/sequel_core/adapters/db2.rb +0 -160
  13. data/lib/sequel_core/adapters/dbi.rb +0 -127
  14. data/lib/sequel_core/adapters/informix.rb +0 -89
  15. data/lib/sequel_core/adapters/jdbc.rb +0 -110
  16. data/lib/sequel_core/adapters/mysql.rb +0 -486
  17. data/lib/sequel_core/adapters/odbc.rb +0 -167
  18. data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
  19. data/lib/sequel_core/adapters/openbase.rb +0 -76
  20. data/lib/sequel_core/adapters/oracle.rb +0 -182
  21. data/lib/sequel_core/adapters/postgres.rb +0 -560
  22. data/lib/sequel_core/adapters/sqlite.rb +0 -270
  23. data/lib/sequel_core/connection_pool.rb +0 -194
  24. data/lib/sequel_core/core_ext.rb +0 -197
  25. data/lib/sequel_core/core_sql.rb +0 -184
  26. data/lib/sequel_core/database.rb +0 -462
  27. data/lib/sequel_core/database/schema.rb +0 -156
  28. data/lib/sequel_core/dataset.rb +0 -457
  29. data/lib/sequel_core/dataset/callback.rb +0 -13
  30. data/lib/sequel_core/dataset/convenience.rb +0 -245
  31. data/lib/sequel_core/dataset/pagination.rb +0 -96
  32. data/lib/sequel_core/dataset/query.rb +0 -41
  33. data/lib/sequel_core/dataset/schema.rb +0 -15
  34. data/lib/sequel_core/dataset/sql.rb +0 -889
  35. data/lib/sequel_core/deprecated.rb +0 -26
  36. data/lib/sequel_core/exceptions.rb +0 -42
  37. data/lib/sequel_core/migration.rb +0 -187
  38. data/lib/sequel_core/object_graph.rb +0 -216
  39. data/lib/sequel_core/pretty_table.rb +0 -71
  40. data/lib/sequel_core/schema.rb +0 -2
  41. data/lib/sequel_core/schema/generator.rb +0 -239
  42. data/lib/sequel_core/schema/sql.rb +0 -326
  43. data/lib/sequel_core/sql.rb +0 -812
  44. data/lib/sequel_core/worker.rb +0 -68
  45. data/spec/adapters/informix_spec.rb +0 -96
  46. data/spec/adapters/mysql_spec.rb +0 -765
  47. data/spec/adapters/oracle_spec.rb +0 -222
  48. data/spec/adapters/postgres_spec.rb +0 -441
  49. data/spec/adapters/sqlite_spec.rb +0 -413
  50. data/spec/connection_pool_spec.rb +0 -363
  51. data/spec/core_ext_spec.rb +0 -156
  52. data/spec/core_sql_spec.rb +0 -427
  53. data/spec/database_spec.rb +0 -963
  54. data/spec/dataset_spec.rb +0 -2933
  55. data/spec/expression_filters_spec.rb +0 -316
  56. data/spec/migration_spec.rb +0 -261
  57. data/spec/object_graph_spec.rb +0 -230
  58. data/spec/pretty_table_spec.rb +0 -58
  59. data/spec/rcov.opts +0 -6
  60. data/spec/schema_generator_spec.rb +0 -122
  61. data/spec/schema_spec.rb +0 -422
  62. data/spec/spec.opts +0 -0
  63. data/spec/spec_config.rb +0 -7
  64. data/spec/spec_config.rb.example +0 -8
  65. data/spec/spec_helper.rb +0 -55
  66. data/spec/worker_spec.rb +0 -96
@@ -1,197 +0,0 @@
1
- class Array
2
- # True if the array is not empty and all of its elements are
3
- # arrays of size 2. This is used to determine if the array
4
- # could be a specifier of conditions, used similarly to a hash
5
- # but allowing for duplicate keys.
6
- #
7
- # hash.to_a.all_two_pairs? # => true unless hash is empty
8
- def all_two_pairs?
9
- !empty? && all?{|i| (Array === i) && (i.length == 2)}
10
- end
11
-
12
- # Removes and returns the last member of the array if it is a hash. Otherwise,
13
- # an empty hash is returned This method is useful when writing methods that
14
- # take an options hash as the last parameter. For example:
15
- #
16
- # def validate_each(*args, &block)
17
- # opts = args.extract_options!
18
- # ...
19
- # end
20
- def extract_options!
21
- last.is_a?(Hash) ? pop : {}
22
- end
23
- end
24
-
25
- module Enumerable
26
- # Invokes the specified method for each item, along with the supplied
27
- # arguments.
28
- def send_each(sym, *args)
29
- each{|i| i.send(sym, *args)}
30
- end
31
- end
32
-
33
- class FalseClass
34
- # false is always blank
35
- def blank?
36
- true
37
- end
38
- end
39
-
40
- # Add some metaprogramming methods to avoid class << self
41
- class Module
42
- # Defines an instance method within a class/module
43
- def class_def(name, &block)
44
- class_eval{define_method(name, &block)}
45
- end
46
-
47
- private
48
-
49
- # Define instance method(s) that calls class method(s) of the
50
- # same name. Replaces the construct:
51
- #
52
- # define_method(meth){self.class.send(meth)}
53
- def class_attr_reader(*meths)
54
- meths.each{|meth| define_method(meth){self.class.send(meth)}}
55
- end
56
-
57
- # Create an alias for a singleton/class method.
58
- # Replaces the construct:
59
- #
60
- # class << self
61
- # alias_method to, from
62
- # end
63
- def metaalias(to, from)
64
- meta_eval{alias_method to, from}
65
- end
66
-
67
- # Make a singleton/class attribute accessor method(s).
68
- # Replaces the construct:
69
- #
70
- # class << self
71
- # attr_accessor *meths
72
- # end
73
- def metaattr_accessor(*meths)
74
- meta_eval{attr_accessor(*meths)}
75
- end
76
-
77
- # Make a singleton/class method(s) private.
78
- # Make a singleton/class attribute reader method(s).
79
- # Replaces the construct:
80
- #
81
- # class << self
82
- # attr_reader *meths
83
- # end
84
- def metaattr_reader(*meths)
85
- meta_eval{attr_reader(*meths)}
86
- end
87
- end
88
-
89
- # Helpers from Metaid and a bit more
90
- class Object
91
- # Objects are blank if they respond true to empty?
92
- def blank?
93
- respond_to?(:empty?) && empty?
94
- end
95
-
96
- # Returns true if the object is an instance of one of the classes
97
- def is_one_of?(*classes)
98
- !!classes.find{|c| is_a?(c)}
99
- end
100
-
101
- # Add methods to the object's metaclass
102
- def meta_def(name, &block)
103
- meta_eval{define_method(name, &block)}
104
- end
105
-
106
- # Evaluate the block in the context of the object's metaclass
107
- def meta_eval(&block)
108
- metaclass.instance_eval(&block)
109
- end
110
-
111
- # The hidden singleton lurks behind everyone
112
- def metaclass
113
- class << self
114
- self
115
- end
116
- end
117
- end
118
-
119
- class NilClass
120
- # nil is always blank
121
- def blank?
122
- true
123
- end
124
- end
125
-
126
- class Numeric
127
- # Numerics are never blank (not even 0)
128
- def blank?
129
- false
130
- end
131
- end
132
-
133
- class Range
134
- # Returns the interval between the beginning and end of the range.
135
- #
136
- # For exclusive ranges, is one less than the inclusive range:
137
- #
138
- # (0..10).interval # => 10
139
- # (0...10).interval # => 9
140
- #
141
- # Only works for numeric ranges, for other ranges the result is undefined,
142
- # and the method may raise an error.
143
- def interval
144
- last - first - (exclude_end? ? 1 : 0)
145
- end
146
- end
147
-
148
- class String
149
- # Strings are blank if they are empty or include only whitespace
150
- def blank?
151
- strip.empty?
152
- end
153
-
154
- # Converts a string into a Date object.
155
- def to_date
156
- begin
157
- Date.parse(self)
158
- rescue => e
159
- raise Sequel::Error::InvalidValue, "Invalid date value '#{self}' (#{e.message})"
160
- end
161
- end
162
-
163
- # Converts a string into a DateTime object.
164
- def to_datetime
165
- begin
166
- DateTime.parse(self)
167
- rescue => e
168
- raise Sequel::Error::InvalidValue, "Invalid date value '#{self}' (#{e.message})"
169
- end
170
- end
171
-
172
- # Converts a string into a Time or DateTime object, depending on the
173
- # value of Sequel.datetime_class
174
- def to_sequel_time
175
- begin
176
- Sequel.datetime_class.parse(self)
177
- rescue => e
178
- raise Sequel::Error::InvalidValue, "Invalid time value '#{self}' (#{e.message})"
179
- end
180
- end
181
-
182
- # Converts a string into a Time object.
183
- def to_time
184
- begin
185
- Time.parse(self)
186
- rescue => e
187
- raise Sequel::Error::InvalidValue, "Invalid time value '#{self}' (#{e.message})"
188
- end
189
- end
190
- end
191
-
192
- class TrueClass
193
- # true is never blank
194
- def blank?
195
- false
196
- end
197
- end
@@ -1,184 +0,0 @@
1
- class Array
2
- # Return a Sequel::SQL::BooleanExpression created from this array, not matching any of the
3
- # conditions.
4
- def ~
5
- sql_expr_if_all_two_pairs(:OR, true)
6
- end
7
-
8
- # Return a Sequel::SQL::CaseExpression with this array as the conditions and the given
9
- # default value.
10
- def case(default)
11
- ::Sequel::SQL::CaseExpression.new(self, default)
12
- end
13
-
14
- # Return a Sequel::SQL::BooleanExpression created from this array, matching all of the
15
- # conditions.
16
- def sql_expr
17
- sql_expr_if_all_two_pairs
18
- end
19
-
20
- # Return a Sequel::SQL::BooleanExpression created from this array, matching none
21
- # of the conditions.
22
- def sql_negate
23
- sql_expr_if_all_two_pairs(:AND, true)
24
- end
25
-
26
- # Return a Sequel::SQL::BooleanExpression created from this array, matching any of the
27
- # conditions.
28
- def sql_or
29
- sql_expr_if_all_two_pairs(:OR)
30
- end
31
-
32
- # Return a Sequel::SQL::BooleanExpression representing an SQL string made up of the
33
- # concatenation of this array's elements. If an argument is passed
34
- # it is used in between each element of the array in the SQL
35
- # concatenation.
36
- def sql_string_join(joiner=nil)
37
- if joiner
38
- args = self.inject([]) do |m, a|
39
- m << a
40
- m << joiner
41
- end
42
- args.pop
43
- else
44
- args = self
45
- end
46
- args = args.collect{|a| a.is_one_of?(Symbol, ::Sequel::SQL::Expression, ::Sequel::LiteralString, TrueClass, FalseClass, NilClass) ? a : a.to_s}
47
- ::Sequel::SQL::StringExpression.new(:'||', *args)
48
- end
49
-
50
- # Concatenates an array of strings into an SQL string. ANSI SQL and C-style
51
- # comments are removed, as well as excessive white-space.
52
- def to_sql
53
- map {|l| ((m = /^(.*)--/.match(l)) ? m[1] : l).chomp}.join(' '). \
54
- gsub(/\/\*.*\*\//, '').gsub(/\s+/, ' ').strip
55
- end
56
-
57
- private
58
-
59
- # Raise an error if this array is not made up of all two pairs, otherwise create a Sequel::SQL::BooleanExpression from this array.
60
- def sql_expr_if_all_two_pairs(*args)
61
- raise(Sequel::Error, 'Not all elements of the array are arrays of size 2, so it cannot be converted to an SQL expression') unless all_two_pairs?
62
- ::Sequel::SQL::BooleanExpression.from_value_pairs(self, *args)
63
- end
64
- end
65
-
66
- class Hash
67
- # Return a Sequel::SQL::BooleanExpression created from this hash, matching
68
- # all of the conditions in this hash and the condition specified by
69
- # the given argument.
70
- def &(ce)
71
- ::Sequel::SQL::BooleanExpression.new(:AND, self, ce)
72
- end
73
-
74
- # Return a Sequel::SQL::BooleanExpression created from this hash, matching
75
- # all of the conditions in this hash or the condition specified by
76
- # the given argument.
77
- def |(ce)
78
- ::Sequel::SQL::BooleanExpression.new(:OR, self, ce)
79
- end
80
-
81
- # Return a Sequel::SQL::BooleanExpression created from this hash, not matching any of the
82
- # conditions.
83
- def ~
84
- ::Sequel::SQL::BooleanExpression.from_value_pairs(self, :OR, true)
85
- end
86
-
87
- # Return a Sequel::SQL::CaseExpression with this hash as the conditions and the given
88
- # default value. Note that the order of the conditions will be arbitrary, so all
89
- # conditions should be orthogonal.
90
- def case(default)
91
- ::Sequel::SQL::CaseExpression.new(to_a, default)
92
- end
93
-
94
- # Return a Sequel::SQL::BooleanExpression created from this hash, matching all of the
95
- # conditions.
96
- def sql_expr
97
- ::Sequel::SQL::BooleanExpression.from_value_pairs(self)
98
- end
99
-
100
- # Return a Sequel::SQL::BooleanExpression created from this hash, matching none
101
- # of the conditions.
102
- def sql_negate
103
- ::Sequel::SQL::BooleanExpression.from_value_pairs(self, :AND, true)
104
- end
105
-
106
- # Return a Sequel::SQL::BooleanExpression created from this hash, matching any of the
107
- # conditions.
108
- def sql_or
109
- ::Sequel::SQL::BooleanExpression.from_value_pairs(self, :OR)
110
- end
111
- end
112
-
113
- class String
114
- include Sequel::SQL::AliasMethods
115
- include Sequel::SQL::CastMethods
116
-
117
- # Converts a string into an LiteralString, in order to override string
118
- # literalization, e.g.:
119
- #
120
- # DB[:items].filter(:abc => 'def').sql #=>
121
- # "SELECT * FROM items WHERE (abc = 'def')"
122
- #
123
- # DB[:items].filter(:abc => 'def'.lit).sql #=>
124
- # "SELECT * FROM items WHERE (abc = def)"
125
- #
126
- def lit
127
- Sequel::LiteralString.new(self)
128
- end
129
- alias_method :expr, :lit
130
-
131
- # Splits a string into separate SQL statements, removing comments
132
- # and excessive white-space.
133
- def split_sql
134
- to_sql.split(';').map {|s| s.strip}
135
- end
136
-
137
- # Converts a string into an SQL string by removing comments.
138
- # See also Array#to_sql.
139
- def to_sql
140
- split("\n").to_sql
141
- end
142
-
143
- # Returns a Blob that holds the same data as this string. Blobs provide proper
144
- # escaping of binary data.
145
- def to_blob
146
- ::Sequel::SQL::Blob.new self
147
- end
148
- end
149
-
150
- class Symbol
151
- include Sequel::SQL::QualifyingMethods
152
- include Sequel::SQL::IdentifierMethods
153
- include Sequel::SQL::GenericExpressionMethods
154
-
155
- # If no argument is given, returns a Sequel::SQL::ColumnAll object specifying all
156
- # columns for this table.
157
- # If an argument is given, returns a Sequel::SQL::NumericExpression using the *
158
- # (multiplication) operator with this and the given argument.
159
- def *(ce=(arg=false;nil))
160
- return super(ce) unless arg == false
161
- Sequel::SQL::ColumnAll.new(self);
162
- end
163
-
164
- # Returns a Sequel::SQL::Function with this as the function name,
165
- # and the given arguments.
166
- def [](*args)
167
- Sequel::SQL::Function.new(self, *args)
168
- end
169
-
170
- # If the given argument is an Integer or an array containing an Integer, returns
171
- # a Sequel::SQL::Subscript with this column and the given arg.
172
- # Otherwise returns a Sequel::SQL::BooleanExpression where this column (which should be boolean)
173
- # or the given argument is true.
174
- def |(sub)
175
- return super unless (Integer === sub) || ((Array === sub) && sub.any?{|x| Integer === x})
176
- Sequel::SQL::Subscript.new(self, Array(sub))
177
- end
178
-
179
- # Delegate the creation of the resulting SQL to the given dataset,
180
- # since it may be database dependent.
181
- def to_column_ref(ds)
182
- ds.symbol_to_column_ref(self)
183
- end
184
- end
@@ -1,462 +0,0 @@
1
- require 'sequel_core/database/schema'
2
-
3
- module Sequel
4
- # Array of all databases to which Sequel has connected. If you are
5
- # developing an application that can connect to an arbitrary number of
6
- # databases, delete the database objects from this or they will not get
7
- # garbage collected.
8
- DATABASES = []
9
-
10
- # A Database object represents a virtual connection to a database.
11
- # The Database class is meant to be subclassed by database adapters in order
12
- # to provide the functionality needed for executing queries.
13
- class Database
14
- include Schema::SQL
15
-
16
- # Array of supported database adapters
17
- ADAPTERS = %w'ado db2 dbi informix jdbc mysql odbc odbc_mssql openbase oracle postgres sqlite'.collect{|x| x.to_sym}
18
-
19
- SQL_BEGIN = 'BEGIN'.freeze
20
- SQL_COMMIT = 'COMMIT'.freeze
21
- SQL_ROLLBACK = 'ROLLBACK'.freeze
22
-
23
- # Hash of adapters that have been used
24
- @@adapters = Hash.new
25
-
26
- # Whether to use the single threaded connection pool by default
27
- @@single_threaded = false
28
-
29
- # Whether to quote identifiers (columns and tables) by default
30
- @@quote_identifiers = true
31
-
32
- # Array of SQL loggers to use for this database
33
- attr_accessor :loggers
34
-
35
- # The options for this database
36
- attr_reader :opts
37
-
38
- # The connection pool for this database
39
- attr_reader :pool
40
-
41
- # Whether to quote identifiers (columns and tables) for this database
42
- attr_writer :quote_identifiers
43
-
44
- # Constructs a new instance of a database connection with the specified
45
- # options hash.
46
- #
47
- # Sequel::Database is an abstract class that is not useful by itself.
48
- def initialize(opts = {}, &block)
49
- @opts = opts
50
-
51
- @quote_identifiers = opts.include?(:quote_identifiers) ? opts[:quote_identifiers] : @@quote_identifiers
52
- @single_threaded = opts.include?(:single_threaded) ? opts[:single_threaded] : @@single_threaded
53
- @schemas = nil
54
- @pool = (@single_threaded ? SingleThreadedPool : ConnectionPool).new(connection_pool_default_options.merge(opts), &block)
55
- @pool.connection_proc = proc {connect} unless block
56
-
57
- @loggers = Array(opts[:logger]) + Array(opts[:loggers])
58
- ::Sequel::DATABASES.push(self)
59
- end
60
-
61
- ### Class Methods ###
62
-
63
- # The Database subclass for the given adapter scheme.
64
- # Raises Sequel::Error::AdapterNotFound if the adapter
65
- # could not be loaded.
66
- def self.adapter_class(scheme)
67
- scheme = scheme.to_s.gsub('-', '_').to_sym
68
-
69
- if (klass = @@adapters[scheme]).nil?
70
- # attempt to load the adapter file
71
- begin
72
- require "sequel_core/adapters/#{scheme}"
73
- rescue LoadError => e
74
- raise Error::AdapterNotFound, "Could not load #{scheme} adapter:\n #{e.message}"
75
- end
76
-
77
- # make sure we actually loaded the adapter
78
- if (klass = @@adapters[scheme]).nil?
79
- raise Error::AdapterNotFound, "Could not load #{scheme} adapter"
80
- end
81
- end
82
- return klass
83
- end
84
-
85
- # Returns the scheme for the Database class.
86
- def self.adapter_scheme
87
- @scheme
88
- end
89
-
90
- # Connects to a database. See Sequel.connect.
91
- def self.connect(conn_string, opts = nil, &block)
92
- if conn_string.is_a?(String)
93
- uri = URI.parse(conn_string)
94
- scheme = uri.scheme
95
- scheme = :dbi if scheme =~ /^dbi-(.+)/
96
- c = adapter_class(scheme)
97
- opts = c.uri_to_options(uri).merge(opts || {})
98
- else
99
- opts = conn_string.merge(opts || {})
100
- c = adapter_class(opts[:adapter] || opts['adapter'])
101
- end
102
- # process opts a bit
103
- opts = opts.inject({}) do |m, kv| k, v = *kv
104
- k = :user if k.to_s == 'username'
105
- m[k.to_sym] = v
106
- m
107
- end
108
- if block
109
- begin
110
- yield(db = c.new(opts))
111
- ensure
112
- db.disconnect if db
113
- ::Sequel::DATABASES.delete(db)
114
- end
115
- nil
116
- else
117
- c.new(opts)
118
- end
119
- end
120
-
121
- # Sets the default quote_identifiers mode for new databases.
122
- # See Sequel.quote_identifiers=.
123
- def self.quote_identifiers=(value)
124
- @@quote_identifiers = value
125
- end
126
-
127
- # Sets the default single_threaded mode for new databases.
128
- # See Sequel.single_threaded=.
129
- def self.single_threaded=(value)
130
- @@single_threaded = value
131
- end
132
-
133
- # Converts a uri to an options hash. These options are then passed
134
- # to a newly created database object.
135
- def self.uri_to_options(uri)
136
- uri = URI.parse(uri) if uri.is_a?(String)
137
- # special case for sqlite
138
- opts = if uri.scheme == 'sqlite'
139
- { :user => uri.user,
140
- :password => uri.password,
141
- :database => (uri.host.nil? && uri.path == '/') ? nil : "#{uri.host}#{uri.path}" }
142
- else
143
- { :user => uri.user,
144
- :password => uri.password,
145
- :host => uri.host,
146
- :port => uri.port,
147
- :database => (m = /\/(.*)/.match(uri.path)) && (m[1]) }
148
- end
149
- uri.query.split('&').collect{|s| s.split('=')}.each{|k,v| opts[k.to_sym] = v} unless uri.query.blank?
150
- opts
151
- end
152
-
153
- ### Private Class Methods ###
154
-
155
- # Sets the adapter scheme for the Database class. Call this method in
156
- # descendnants of Database to allow connection using a URL. For example the
157
- # following:
158
- #
159
- # class Sequel::MyDB::Database < Sequel::Database
160
- # set_adapter_scheme :mydb
161
- # ...
162
- # end
163
- #
164
- # would allow connection using:
165
- #
166
- # Sequel.connect('mydb://user:password@dbserver/mydb')
167
- def self.set_adapter_scheme(scheme) # :nodoc:
168
- @scheme = scheme
169
- @@adapters[scheme.to_sym] = self
170
- end
171
-
172
- private_class_method :set_adapter_scheme
173
-
174
- ### Instance Methods ###
175
-
176
- # Executes the supplied SQL statement. The SQL can be supplied as a string
177
- # or as an array of strings. If an array is given, comments and excessive
178
- # white space are removed. See also Array#to_sql.
179
- def <<(sql)
180
- execute((Array === sql) ? sql.to_sql : sql)
181
- end
182
-
183
- # Returns a dataset from the database. If the first argument is a string,
184
- # the method acts as an alias for Database#fetch, returning a dataset for
185
- # arbitrary SQL:
186
- #
187
- # DB['SELECT * FROM items WHERE name = ?', my_name].print
188
- #
189
- # Otherwise, acts as an alias for Database#from, setting the primary
190
- # table for the dataset:
191
- #
192
- # DB[:items].sql #=> "SELECT * FROM items"
193
- def [](*args, &block)
194
- (String === args.first) ? fetch(*args, &block) : from(*args, &block)
195
- end
196
-
197
- # Connects to the database. This method should be overridden by descendants.
198
- def connect
199
- raise NotImplementedError, "#connect should be overridden by adapters"
200
- end
201
-
202
- # Returns a blank dataset
203
- def dataset
204
- ds = Sequel::Dataset.new(self)
205
- end
206
-
207
- # Disconnects from the database. This method should be overridden by
208
- # descendants.
209
- def disconnect
210
- raise NotImplementedError, "#disconnect should be overridden by adapters"
211
- end
212
-
213
- # Executes the given SQL. This method should be overridden in descendants.
214
- def execute(sql)
215
- raise NotImplementedError, "#execute should be overridden by adapters"
216
- end
217
-
218
- # Fetches records for an arbitrary SQL statement. If a block is given,
219
- # it is used to iterate over the records:
220
- #
221
- # DB.fetch('SELECT * FROM items'){|r| p r}
222
- #
223
- # The method returns a dataset instance:
224
- #
225
- # DB.fetch('SELECT * FROM items').print
226
- #
227
- # Fetch can also perform parameterized queries for protection against SQL
228
- # injection:
229
- #
230
- # DB.fetch('SELECT * FROM items WHERE name = ?', my_name).print
231
- def fetch(sql, *args, &block)
232
- ds = dataset
233
- sql = sql.gsub('?') {|m| ds.literal(args.shift)}
234
- ds.opts[:sql] = sql
235
- ds.fetch_rows(sql, &block) if block
236
- ds
237
- end
238
- alias_method :>>, :fetch
239
-
240
- # Returns a new dataset with the from method invoked. If a block is given,
241
- # it is used as a filter on the dataset.
242
- def from(*args, &block)
243
- ds = dataset.from(*args)
244
- block ? ds.filter(&block) : ds
245
- end
246
-
247
- # Returns a single value from the database, e.g.:
248
- #
249
- # # SELECT 1
250
- # DB.get(1) #=> 1
251
- #
252
- # # SELECT version()
253
- # DB.get(:version[]) #=> ...
254
- def get(expr)
255
- dataset.get(expr)
256
- end
257
-
258
- # Returns a string representation of the database object including the
259
- # class name and the connection URI (or the opts if the URI
260
- # cannot be constructed).
261
- def inspect
262
- "#<#{self.class}: #{(uri rescue opts).inspect}>"
263
- end
264
-
265
- # Log a message at level info to all loggers. All SQL logging
266
- # goes through this method.
267
- def log_info(message)
268
- @loggers.each{|logger| logger.info(message)}
269
- end
270
-
271
- # Return the first logger or nil if no loggers are being used.
272
- # Should only be used for backwards compatibility.
273
- def logger
274
- @loggers.first
275
- end
276
-
277
- # Replace the array of loggers with the given logger(s).
278
- def logger=(logger)
279
- @loggers = Array(logger)
280
- end
281
-
282
- # Returns true unless the database is using a single-threaded connection pool.
283
- def multi_threaded?
284
- !@single_threaded
285
- end
286
-
287
- # Returns a dataset modified by the given query block. See Dataset#query.
288
- def query(&block)
289
- dataset.query(&block)
290
- end
291
-
292
- # Returns true if the database quotes identifiers.
293
- def quote_identifiers?
294
- @quote_identifiers
295
- end
296
-
297
- # Returns a new dataset with the select method invoked.
298
- def select(*args)
299
- dataset.select(*args)
300
- end
301
-
302
- # Default serial primary key options.
303
- def serial_primary_key_options
304
- {:primary_key => true, :type => :integer, :auto_increment => true}
305
- end
306
-
307
- # Returns true if the database is using a single-threaded connection pool.
308
- def single_threaded?
309
- @single_threaded
310
- end
311
-
312
- # Acquires a database connection, yielding it to the passed block.
313
- def synchronize(&block)
314
- @pool.hold(&block)
315
- end
316
-
317
- # Returns true if a table with the given name exists.
318
- def table_exists?(name)
319
- begin
320
- if respond_to?(:tables)
321
- tables.include?(name.to_sym)
322
- else
323
- from(name).first
324
- true
325
- end
326
- rescue
327
- false
328
- end
329
- end
330
-
331
- # Attempts to acquire a database connection. Returns true if successful.
332
- # Will probably raise an error if unsuccessful.
333
- def test_connection
334
- synchronize{|conn|}
335
- true
336
- end
337
-
338
- # A simple implementation of SQL transactions. Nested transactions are not
339
- # supported - calling #transaction within a transaction will reuse the
340
- # current transaction. Should be overridden for databases that support nested
341
- # transactions.
342
- def transaction
343
- @pool.hold do |conn|
344
- @transactions ||= []
345
- if @transactions.include? Thread.current
346
- return yield(conn)
347
- end
348
- log_info(SQL_BEGIN)
349
- conn.execute(SQL_BEGIN)
350
- begin
351
- @transactions << Thread.current
352
- yield(conn)
353
- rescue Exception => e
354
- log_info(SQL_ROLLBACK)
355
- conn.execute(SQL_ROLLBACK)
356
- raise e unless Error::Rollback === e
357
- ensure
358
- unless e
359
- log_info(SQL_COMMIT)
360
- conn.execute(SQL_COMMIT)
361
- end
362
- @transactions.delete(Thread.current)
363
- end
364
- end
365
- end
366
-
367
- # Typecast the value to the given column_type. Can be overridden in
368
- # adapters to support database specific column types.
369
- def typecast_value(column_type, value)
370
- return nil if value.nil?
371
- case column_type
372
- when :integer
373
- Integer(value)
374
- when :string
375
- value.to_s
376
- when :float
377
- Float(value)
378
- when :decimal
379
- case value
380
- when BigDecimal
381
- value
382
- when String, Float
383
- value.to_d
384
- when Integer
385
- value.to_s.to_d
386
- else
387
- raise ArgumentError, "invalid value for BigDecimal: #{value.inspect}"
388
- end
389
- when :boolean
390
- case value
391
- when false, 0, "0", /\Af(alse)?\z/i
392
- false
393
- else
394
- value.blank? ? nil : true
395
- end
396
- when :date
397
- case value
398
- when Date
399
- value
400
- when DateTime, Time
401
- Date.new(value.year, value.month, value.day)
402
- when String
403
- value.to_date
404
- else
405
- raise ArgumentError, "invalid value for Date: #{value.inspect}"
406
- end
407
- when :time
408
- case value
409
- when Time
410
- value
411
- when String
412
- value.to_time
413
- else
414
- raise ArgumentError, "invalid value for Time: #{value.inspect}"
415
- end
416
- when :datetime
417
- raise(ArgumentError, "invalid value for #{tc}: #{value.inspect}") unless value.is_one_of?(DateTime, Date, Time, String)
418
- if Sequel.datetime_class === value
419
- # Already the correct class, no need to convert
420
- value
421
- else
422
- # First convert it to standard ISO 8601 time, then
423
- # parse that string using the time class.
424
- (Time === value ? value.iso8601 : value.to_s).to_sequel_time
425
- end
426
- when :blob
427
- value.to_blob
428
- else
429
- value
430
- end
431
- end
432
-
433
- # Returns the URI identifying the database.
434
- # This method can raise an error if the database used options
435
- # instead of a connection string.
436
- def uri
437
- uri = URI::Generic.new(
438
- self.class.adapter_scheme.to_s,
439
- nil,
440
- @opts[:host],
441
- @opts[:port],
442
- nil,
443
- "/#{@opts[:database]}",
444
- nil,
445
- nil,
446
- nil
447
- )
448
- uri.user = @opts[:user]
449
- uri.password = @opts[:password] if uri.user
450
- uri.to_s
451
- end
452
- alias_method :url, :uri
453
-
454
- private
455
-
456
- # The default options for the connection pool.
457
- def connection_pool_default_options
458
- {}
459
- end
460
- end
461
- end
462
-