Class: Sequel::Database

Inherits:
Object show all
Includes:
Dataset::SQL, Schema::SQL
Defined in:
lib/sequel/database.rb

Overview

A Database object represents a virtual connection to a database. The Database class is meant to be subclassed by database adapters in order to provide the functionality needed for executing queries.

Constant Summary collapse

SQL_BEGIN =
'BEGIN'.freeze
SQL_COMMIT =
'COMMIT'.freeze
SQL_ROLLBACK =
'ROLLBACK'.freeze
@@adapters =
Hash.new
@@single_threaded =
false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}, &block) ⇒ Database

Constructs a new instance of a database connection with the specified options hash.

Sequel::Database is an abstract class that is not useful by itself.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/sequel/database.rb', line 15

def initialize(opts = {}, &block)
  Model.database_opened(self)
  @opts = opts
  
  # Determine if the DB is single threaded or multi threaded
  @single_threaded = opts[:single_threaded] || @@single_threaded
  # Construct pool
  if @single_threaded
    @pool = SingleThreadedPool.new(&block)
  else
    @pool = ConnectionPool.new(opts[:max_connections] || 4, &block)
  end
  @pool.connection_proc = block || proc {connect}

  @logger = opts[:logger]
end

Instance Attribute Details

#loggerObject

Returns the value of attribute logger.



9
10
11
# File 'lib/sequel/database.rb', line 9

def logger
  @logger
end

#optsObject (readonly)

Returns the value of attribute opts.



8
9
10
# File 'lib/sequel/database.rb', line 8

def opts
  @opts
end

#poolObject (readonly)

Returns the value of attribute pool.



8
9
10
# File 'lib/sequel/database.rb', line 8

def pool
  @pool
end

Class Method Details

.adapter_class(scheme) ⇒ Object

Raises:



259
260
261
262
263
264
265
266
267
# File 'lib/sequel/database.rb', line 259

def self.adapter_class(scheme)
  scheme = scheme.to_s =~ /\-/ ? scheme.to_s.gsub('-', '_').to_sym : scheme.to_sym
  unless c = @@adapters[scheme.to_sym]
    require File.join(File.dirname(__FILE__), "adapters/#{scheme}")
    c = @@adapters[scheme.to_sym]
  end
  raise SequelError, "Invalid database scheme" unless c
  c
end

.adapter_schemeObject

Returns the scheme for the Database class.



243
244
245
# File 'lib/sequel/database.rb', line 243

def self.adapter_scheme
  @scheme
end

.connect(conn_string, opts = nil) ⇒ Object

call-seq:

Sequel::Database.connect(conn_string)
Sequel::Database.connect(opts)
Sequel.connect(conn_string)
Sequel.connect(opts)
Sequel.open(conn_string)
Sequel.open(opts)

Creates a new database object based on the supplied connection string and or options. If a URI is used, the URI scheme determines the database class used, and the rest of the string specifies the connection options. For example:

DB = Sequel.open 'sqlite:///blog.db'

The second form of this method takes an options:

DB = Sequel.open :adapter => :sqlite, :database => 'blog.db'


287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/sequel/database.rb', line 287

def self.connect(conn_string, opts = nil)
  if conn_string.is_a?(String)
    uri = URI.parse(conn_string)
    scheme = uri.scheme
    scheme = :dbi if scheme =~ /^dbi-(.+)/
    c = adapter_class(scheme)
    c.new(c.uri_to_options(uri).merge(opts || {}))
  else
    opts = conn_string.merge(opts || {})
    c = adapter_class(opts[:adapter])
    c.new(opts)
  end
end

.set_adapter_scheme(scheme) ⇒ Object

Sets the adapter scheme for the Database class. Call this method in descendnants of Database to allow connection using a URL. For example the following:

class DB2::Database < Sequel::Database
  set_adapter_scheme :db2
  ...
end

would allow connection using:

Sequel.open('db2://user:password@dbserver/mydb')


237
238
239
240
# File 'lib/sequel/database.rb', line 237

def self.set_adapter_scheme(scheme)
  @scheme = scheme
  @@adapters[scheme.to_sym] = self
end

.single_threaded=(value) ⇒ Object

Sets the default single_threaded mode for new databases.



304
305
306
# File 'lib/sequel/database.rb', line 304

def self.single_threaded=(value)
  @@single_threaded = value
end

.uri_to_options(uri) ⇒ Object

Converts a uri to an options hash. These options are then passed to a newly created database object.



249
250
251
252
253
254
255
256
257
# File 'lib/sequel/database.rb', line 249

def self.uri_to_options(uri)
  {
    :user => uri.user,
    :password => uri.password,
    :host => uri.host,
    :port => uri.port,
    :database => (uri.path =~ /\/(.*)/) && ($1)
  }
end

Instance Method Details

#<<(sql) ⇒ Object

Executes the supplied SQL statement. The SQL can be supplied as a string or as an array of strings. If an array is give, comments and excessive white space are removed. See also Array#to_sql.



147
# File 'lib/sequel/database.rb', line 147

def <<(sql); execute((Array === sql) ? sql.to_sql : sql); end

#[](*args) ⇒ Object

Returns a dataset from the database. If the first argument is a string, the method acts as an alias for Database#fetch, returning a dataset for arbitrary SQL:

DB['SELECT * FROM items WHERE name = ?', my_name].print

Otherwise, the dataset returned has its from option set to the given arguments:

DB[:items].sql #=> "SELECT * FROM items"


135
136
137
# File 'lib/sequel/database.rb', line 135

def [](*args)
  (String === args.first) ? fetch(*args) : from(*args)
end

#connectObject

Connects to the database. This method should be overriden by descendants.

Raises:

  • (NotImplementedError)


33
34
35
# File 'lib/sequel/database.rb', line 33

def connect
  raise NotImplementedError, "#connect should be overriden by adapters"
end

#create_table(name, &block) ⇒ Object

Creates a table. The easiest way to use this method is to provide a block:

DB.create_table :posts do
  primary_key :id, :serial
  column :title, :text
  column :content, :text
  index :title
end


176
177
178
179
# File 'lib/sequel/database.rb', line 176

def create_table(name, &block)
  g = Schema::Generator.new(self, name, &block)
  create_table_sql_list(*g.create_info).each {|sta| execute(sta)}
end

#datasetObject

Returns a blank dataset



73
74
75
# File 'lib/sequel/database.rb', line 73

def dataset
  ds = Sequel::Dataset.new(self)
end

#disconnectObject

Disconnects from the database. This method should be overriden by descendants.

Raises:

  • (NotImplementedError)


39
40
41
# File 'lib/sequel/database.rb', line 39

def disconnect
  raise NotImplementedError, "#disconnect should be overriden by adapters"
end

#drop_table(*names) ⇒ Object

Drops one or more tables corresponding to the given table names.



182
183
184
# File 'lib/sequel/database.rb', line 182

def drop_table(*names)
  names.each {|n| execute(drop_table_sql(n))}
end

#execute(sql) ⇒ Object

Raises a NotImplementedError. This method is overriden in descendants.

Raises:

  • (NotImplementedError)


140
141
142
# File 'lib/sequel/database.rb', line 140

def execute(sql)
  raise NotImplementedError
end

#fetch(sql, *args, &block) ⇒ Object Also known as: >>

Fetches records for an arbitrary SQL statement. If a block is given, it is used to iterate over the records:

DB.fetch('SELECT * FROM items') {|r| p r}

If a block is not given, the method returns a dataset instance:

DB.fetch('SELECT * FROM items').print

Fetch can also perform parameterized queries for protection against SQL injection:

DB.fetch('SELECT * FROM items WHERE name = ?', my_name).print

A short-hand form for Database#fetch is Database#[]:

DB['SELECT * FROM items'].each {|r| p r}


95
96
97
98
99
100
101
102
103
104
105
# File 'lib/sequel/database.rb', line 95

def fetch(sql, *args, &block)
  ds = dataset
  sql = sql.gsub('?') {|m|  ds.literal(args.shift)}
  if block
    ds.fetch_rows(sql, &block)
  else
    ds.meta_def(:select_sql) {|*args| sql}
    ds.meta_def(:sql) {|*args| sql}
    ds
  end
end

#from(*args, &block) ⇒ Object

Returns a new dataset with the from method invoked. If a block is given, it is used as a filter on the dataset.



116
117
118
119
# File 'lib/sequel/database.rb', line 116

def from(*args, &block)
  ds = dataset.from(*args)
  block ? ds.filter(&block) : ds
end

#multi_threaded?Boolean

Returns true if the database is using a multi-threaded connection pool.

Returns:

  • (Boolean)


44
45
46
# File 'lib/sequel/database.rb', line 44

def multi_threaded?
  !@single_threaded
end

#query(&block) ⇒ Object

Converts a query block into a dataset. For more information see Dataset#query.



110
111
112
# File 'lib/sequel/database.rb', line 110

def query(&block)
  dataset.query(&block)
end

#select(*args) ⇒ Object

Returns a new dataset with the select method invoked.



122
# File 'lib/sequel/database.rb', line 122

def select(*args); dataset.select(*args); end

#serial_primary_key_optionsObject

default serial primary key definition. this should be overriden for each adapter.



164
165
166
# File 'lib/sequel/database.rb', line 164

def serial_primary_key_options
  {:primary_key => true, :type => :integer, :auto_increment => true}
end

#single_threaded?Boolean

Returns true if the database is using a single-threaded connection pool.

Returns:

  • (Boolean)


49
50
51
# File 'lib/sequel/database.rb', line 49

def single_threaded?
  @single_threaded
end

#synchronize(&block) ⇒ Object

Acquires a database connection, yielding it to the passed block.



150
151
152
# File 'lib/sequel/database.rb', line 150

def synchronize(&block)
  @pool.hold(&block)
end

#table_exists?(name) ⇒ Boolean

Returns true if the given table exists.

Returns:

  • (Boolean)


187
188
189
190
191
192
193
194
195
# File 'lib/sequel/database.rb', line 187

def table_exists?(name)
  if respond_to?(:tables)
    tables.include?(name.to_sym)
  else
    from(name).first && true
  end
rescue
  false
end

#test_connectionObject

Returns true if there is a database connection



155
156
157
158
# File 'lib/sequel/database.rb', line 155

def test_connection
  @pool.hold {|conn|}
  true
end

#transactionObject

A simple implementation of SQL transactions. Nested transactions are not supported - calling #transaction within a transaction will reuse the current transaction. May be overridden for databases that support nested transactions.



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/sequel/database.rb', line 205

def transaction
  @pool.hold do |conn|
    @transactions ||= []
    if @transactions.include? Thread.current
      return yield(conn)
    end
    conn.execute(SQL_BEGIN)
    begin
      @transactions << Thread.current
      result = yield(conn)
      conn.execute(SQL_COMMIT)
      result
    rescue => e
      conn.execute(SQL_ROLLBACK)
      raise e unless SequelRollbackError === e
    ensure
      @transactions.delete(Thread.current)
    end
  end
end

#uriObject Also known as: url

Returns the URI identifying the database.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/sequel/database.rb', line 54

def uri
  uri = URI::Generic.new(
    self.class.adapter_scheme.to_s,
    nil,
    @opts[:host],
    @opts[:port],
    nil,
    "/#{@opts[:database]}",
    nil,
    nil,
    nil
  )
  uri.user = @opts[:user]
  uri.password = @opts[:password] if uri.user
  uri.to_s
end