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,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 0
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'sequel'
6
+
7
+ db_opts = {}
8
+ echo = nil
9
+ env = nil
10
+ logfile = nil
11
+ migrate_dir = nil
12
+ migrate_ver = nil
13
+ load_dir = nil
14
+
15
+ opts = OptionParser.new do |opts|
16
+ opts.banner = "Sequel: The Database Toolkit for Ruby"
17
+ opts.define_head "Usage: sequel <uri|path> [options]"
18
+ opts.separator ""
19
+ opts.separator "Examples:"
20
+ opts.separator " sequel sqlite://blog.db"
21
+ opts.separator " sequel postgres://localhost/my_blog"
22
+ opts.separator " sequel config/database.yml"
23
+ opts.separator ""
24
+ opts.separator "For more information see http://sequel.rubyforge.org"
25
+ opts.separator ""
26
+ opts.separator "Options:"
27
+
28
+ opts.on_tail("-?", "--help", "Show this message") do
29
+ puts opts
30
+ exit
31
+ end
32
+
33
+ opts.on("-e", "--env ENV", "use environment config for database") do |v|
34
+ env = v
35
+ end
36
+
37
+ opts.on("-E", "--echo", "echo SQL statements") do
38
+ echo = true
39
+ end
40
+
41
+ opts.on("-l", "--log logfile", "log SQL statements to log file") do |v|
42
+ logfile = v
43
+ end
44
+
45
+ opts.on("-L", "--load-dir DIR", "loads all *.rb from specifed directory") do |v|
46
+ load_dir = v
47
+ end
48
+
49
+ opts.on("-m", "--migrate-directory DIR", "run the migrations in directory") do |v|
50
+ migrate_dir = v
51
+ end
52
+
53
+ opts.on("-M", "--migrate-version VER", "migrate the database to version given") do |v|
54
+ migrate_ver = Integer(v)
55
+ end
56
+
57
+ opts.on_tail("-v", "--version", "Show version") do
58
+ puts "sequel #{Sequel.version}"
59
+ exit
60
+ end
61
+ end
62
+ opts.parse!
63
+
64
+ db = ARGV.shift
65
+
66
+ if db.blank?
67
+ puts opts
68
+ exit 1
69
+ end
70
+
71
+ if logfile || echo
72
+ require 'logger'
73
+ db_opts[:loggers] = []
74
+ db_opts[:loggers] << Logger.new(logfile) if logfile
75
+ db_opts[:loggers] << Logger.new($stdout) if echo
76
+ end
77
+
78
+ if File.exist?(db)
79
+ require 'yaml'
80
+ env ||= "development"
81
+ db_config = YAML.load_file(db)
82
+ db_config = db_config[env] || db_config[env.to_sym] || db_config
83
+ db_config.each{|(k,v)| db_config[k.to_sym] = db_config.delete(k)}
84
+ db_config.merge!(db_opts)
85
+ end
86
+
87
+ begin
88
+ DB = Sequel.connect(*(db_config ? [db_config] : [db, db_opts]))
89
+ DB.test_connection
90
+ if migrate_dir
91
+ Sequel::Migrator.apply(DB, migrate_dir, migrate_ver)
92
+ exit
93
+ end
94
+ rescue => e
95
+ puts "#{e.class}: #{e.message}"
96
+ puts e.backtrace.first
97
+ exit 1
98
+ end
99
+
100
+ Dir["#{load_dir}/**/*.rb"].each{|f| load(f)} if load_dir
101
+
102
+ require 'irb'
103
+ puts "Your database is stored in DB..."
104
+ IRB.start
@@ -0,0 +1 @@
1
+ require 'sequel/model'
@@ -0,0 +1,85 @@
1
+ Sequel.require 'adapters/utils/date_format'
2
+ require 'win32ole'
3
+
4
+ module Sequel
5
+ # The ADO adapter provides connectivity to ADO databases in Windows. ADO
6
+ # databases can be opened using a URL with the ado schema:
7
+ #
8
+ # DB = Sequel.connect('ado://mydb')
9
+ #
10
+ # or using the Sequel.ado method:
11
+ #
12
+ # DB = Sequel.ado('mydb')
13
+ #
14
+ module ADO
15
+ class Database < Sequel::Database
16
+ set_adapter_scheme :ado
17
+
18
+ def initialize(opts)
19
+ super(opts)
20
+ opts[:driver] ||= 'SQL Server'
21
+ case opts[:driver]
22
+ when 'SQL Server'
23
+ Sequel.require 'adapters/shared/mssql'
24
+ extend Sequel::MSSQL::DatabaseMethods
25
+ end
26
+ end
27
+
28
+ def connect(server)
29
+ opts = server_opts(server)
30
+ s = "driver=#{opts[:driver]};server=#{opts[:host]};database=#{opts[:database]}#{";uid=#{opts[:user]};pwd=#{opts[:password]}" if opts[:user]}"
31
+ handle = WIN32OLE.new('ADODB.Connection')
32
+ handle.Open(s)
33
+ handle
34
+ end
35
+
36
+ def dataset(opts = nil)
37
+ ADO::Dataset.new(self, opts)
38
+ end
39
+
40
+ def execute(sql, opts={})
41
+ log_info(sql)
42
+ synchronize(opts[:server]) do |conn|
43
+ r = conn.Execute(sql)
44
+ yield(r) if block_given?
45
+ r
46
+ end
47
+ end
48
+ alias_method :do, :execute
49
+
50
+ private
51
+
52
+ def disconnect_connection(conn)
53
+ conn.Close
54
+ end
55
+ end
56
+
57
+ class Dataset < Sequel::Dataset
58
+ include Dataset::SQLStandardDateFormat
59
+
60
+ def fetch_rows(sql)
61
+ execute(sql) do |s|
62
+ @columns = s.Fields.extend(Enumerable).map do |column|
63
+ name = column.Name.empty? ? '(no column name)' : column.Name
64
+ output_identifier(name)
65
+ end
66
+
67
+ unless s.eof
68
+ s.moveFirst
69
+ s.getRows.transpose.each {|r| yield hash_row(r)}
70
+ end
71
+ end
72
+ self
73
+ end
74
+
75
+ private
76
+
77
+ def hash_row(row)
78
+ @columns.inject({}) do |m, c|
79
+ m[c] = row.shift
80
+ m
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,132 @@
1
+ require 'db2/db2cli'
2
+
3
+ module Sequel
4
+ module DB2
5
+ class Database < Sequel::Database
6
+ set_adapter_scheme :db2
7
+ include DB2CLI
8
+
9
+ rc, @@env = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE)
10
+ #check_error(rc, "Could not allocate DB2 environment")
11
+
12
+ def connect(server)
13
+ opts = server_opts(server)
14
+ rc, dbc = SQLAllocHandle(SQL_HANDLE_DBC, @@env)
15
+ check_error(rc, "Could not allocate database connection")
16
+
17
+ rc = SQLConnect(dbc, opts[:database], opts[:user], opts[:password])
18
+ check_error(rc, "Could not connect to database")
19
+
20
+ dbc
21
+ end
22
+
23
+ def test_connection(server=nil)
24
+ synchronize(server){|conn|}
25
+ true
26
+ end
27
+
28
+ def dataset(opts = nil)
29
+ DB2::Dataset.new(self, opts)
30
+ end
31
+
32
+ def execute(sql, opts={})
33
+ log_info(sql)
34
+ synchronize(opts[:server]) do |conn|
35
+ rc, sth = SQLAllocHandle(SQL_HANDLE_STMT, @handle)
36
+ check_error(rc, "Could not allocate statement")
37
+
38
+ begin
39
+ rc = SQLExecDirect(sth, sql)
40
+ check_error(rc, "Could not execute statement")
41
+
42
+ yield(sth) if block_given?
43
+
44
+ rc, rpc = SQLRowCount(sth)
45
+ check_error(rc, "Could not get RPC")
46
+ rpc
47
+ ensure
48
+ rc = SQLFreeHandle(SQL_HANDLE_STMT, sth)
49
+ check_error(rc, "Could not free statement")
50
+ end
51
+ end
52
+ end
53
+ alias_method :do, :execute
54
+
55
+ private
56
+
57
+ def check_error(rc, msg)
58
+ case rc
59
+ when SQL_SUCCESS, SQL_SUCCESS_WITH_INFO
60
+ nil
61
+ else
62
+ raise DatabaseError, msg
63
+ end
64
+ end
65
+
66
+ def disconnect_connection(conn)
67
+ rc = SQLDisconnect(conn)
68
+ check_error(rc, "Could not disconnect from database")
69
+
70
+ rc = SQLFreeHandle(SQL_HANDLE_DBC, conn)
71
+ check_error(rc, "Could not free Database handle")
72
+ end
73
+ end
74
+
75
+ class Dataset < Sequel::Dataset
76
+ MAX_COL_SIZE = 256
77
+
78
+ def fetch_rows(sql)
79
+ execute(sql) do |sth|
80
+ @column_info = get_column_info(sth)
81
+ @columns = @column_info.map {|c| output_identifier(c[:name])}
82
+ while (rc = SQLFetch(@handle)) != SQL_NO_DATA_FOUND
83
+ @db.check_error(rc, "Could not fetch row")
84
+ yield hash_row(sth)
85
+ end
86
+ end
87
+ self
88
+ end
89
+
90
+ private
91
+
92
+ def get_column_info(sth)
93
+ rc, column_count = SQLNumResultCols(sth)
94
+ @db.check_error(rc, "Could not get number of result columns")
95
+
96
+ (1..column_count).map do |i|
97
+ rc, name, buflen, datatype, size, digits, nullable = SQLDescribeCol(sth, i, MAX_COL_SIZE)
98
+ @b.check_error(rc, "Could not describe column")
99
+
100
+ {:name => name, :db2_type => datatype, :precision => size}
101
+ end
102
+ end
103
+
104
+ def hash_row(sth)
105
+ row = {}
106
+ @column_info.each_with_index do |c, i|
107
+ rc, v = SQLGetData(sth, i+1, c[:db2_type], c[:precision])
108
+ @db.check_error(rc, "Could not get data")
109
+
110
+ row[output_identifier(c[:name])] = convert_type(v)
111
+ end
112
+ row
113
+ end
114
+
115
+ def convert_type(v)
116
+ case v
117
+ when DB2CLI::Date
118
+ DBI::Date.new(v.year, v.month, v.day)
119
+ when DB2CLI::Time
120
+ DBI::Time.new(v.hour, v.minute, v.second)
121
+ when DB2CLI::Timestamp
122
+ DBI::Timestamp.new(v.year, v.month, v.day,
123
+ v.hour, v.minute, v.second, v.fraction)
124
+ when DB2CLI::Null
125
+ nil
126
+ else
127
+ v
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,101 @@
1
+ require 'dbi'
2
+
3
+ module Sequel
4
+ module DBI
5
+ class Database < Sequel::Database
6
+ set_adapter_scheme :dbi
7
+
8
+ DBI_ADAPTERS = {
9
+ :ado => "ADO",
10
+ :db2 => "DB2",
11
+ :frontbase => "FrontBase",
12
+ :interbase => "InterBase",
13
+ :msql => "Msql",
14
+ :mysql => "Mysql",
15
+ :odbc => "ODBC",
16
+ :oracle => "Oracle",
17
+ :pg => "pg",
18
+ :proxy => "Proxy",
19
+ :sqlite => "SQLite",
20
+ :sqlrelay => "SQLRelay"
21
+ }
22
+
23
+ # Converts a uri to an options hash. These options are then passed
24
+ # to a newly created database object.
25
+ def self.uri_to_options(uri) # :nodoc:
26
+ database = (m = /\/(.*)/.match(uri.path)) && (m[1])
27
+ if m = /dbi-(.+)/.match(uri.scheme)
28
+ adapter = DBI_ADAPTERS[m[1].to_sym] || m[1]
29
+ database = "#{adapter}:dbname=#{database}"
30
+ end
31
+ {
32
+ :user => uri.user,
33
+ :password => uri.password,
34
+ :host => uri.host,
35
+ :port => uri.port,
36
+ :database => database
37
+ }
38
+ end
39
+
40
+ private_class_method :uri_to_options
41
+
42
+ def connect(server)
43
+ opts = server_opts(server)
44
+ dbname = opts[:database]
45
+ if dbname !~ /^DBI:/ then
46
+ dbname = "DBI:#{dbname}"
47
+ [:host, :port].each{|sym| dbname += ";#{sym}=#{opts[sym]}" unless blank_object?(opts[sym])}
48
+ end
49
+ ::DBI.connect(dbname, opts[:user], opts[:password])
50
+ end
51
+
52
+ def dataset(opts = nil)
53
+ DBI::Dataset.new(self, opts)
54
+ end
55
+
56
+ def execute(sql, opts={})
57
+ log_info(sql)
58
+ synchronize(opts[:server]) do |conn|
59
+ r = conn.execute(sql)
60
+ yield(r) if block_given?
61
+ r
62
+ end
63
+ end
64
+
65
+ def do(sql, opts={})
66
+ log_info(sql)
67
+ synchronize(opts[:server]){|conn| conn.do(sql)}
68
+ end
69
+ alias_method :execute_dui, :do
70
+
71
+ private
72
+
73
+ def disconnect_connection(c)
74
+ c.disconnect
75
+ end
76
+ end
77
+
78
+ class Dataset < Sequel::Dataset
79
+ def fetch_rows(sql, &block)
80
+ execute(sql) do |s|
81
+ begin
82
+ @columns = s.column_names.map{|c| output_identifier(c)}
83
+ s.fetch{|r| yield hash_row(s, r)}
84
+ ensure
85
+ s.finish rescue nil
86
+ end
87
+ end
88
+ self
89
+ end
90
+
91
+ private
92
+
93
+ def hash_row(stmt, row)
94
+ @columns.inject({}) do |m, c|
95
+ m[c] = row.shift
96
+ m
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,197 @@
1
+ require 'data_objects'
2
+
3
+ module Sequel
4
+ # Module holding the DataObjects support for Sequel. DataObjects is a
5
+ # ruby library with a standard API for accessing databases.
6
+ #
7
+ # The DataObjects adapter currently supports PostgreSQL, MySQL, and
8
+ # SQLite:
9
+ #
10
+ # * Sequel.connect('do:sqlite3::memory:')
11
+ # * Sequel.connect('do:postgres://user:password@host/database')
12
+ # * Sequel.connect('do:mysql://user:password@host/database')
13
+ module DataObjects
14
+ # Contains procs keyed on sub adapter type that extend the
15
+ # given database object so it supports the correct database type.
16
+ DATABASE_SETUP = {:postgres=>proc do |db|
17
+ require 'do_postgres'
18
+ Sequel.require 'adapters/do/postgres'
19
+ db.converted_exceptions << PostgresError
20
+ db.extend(Sequel::DataObjects::Postgres::DatabaseMethods)
21
+ end,
22
+ :mysql=>proc do |db|
23
+ require 'do_mysql'
24
+ Sequel.require 'adapters/do/mysql'
25
+ db.converted_exceptions << MysqlError
26
+ db.extend(Sequel::DataObjects::MySQL::DatabaseMethods)
27
+ end,
28
+ :sqlite3=>proc do |db|
29
+ require 'do_sqlite3'
30
+ Sequel.require 'adapters/do/sqlite'
31
+ db.converted_exceptions << Sqlite3Error
32
+ db.extend(Sequel::DataObjects::SQLite::DatabaseMethods)
33
+ end
34
+ }
35
+
36
+ # DataObjects uses it's own internal connection pooling in addition to the
37
+ # pooling that Sequel uses. You should make sure that you don't set
38
+ # the connection pool size to more than 8 for a
39
+ # Sequel::DataObjects::Database object, or hack DataObjects (or Extlib) to
40
+ # use a pool size at least as large as the pool size being used by Sequel.
41
+ class Database < Sequel::Database
42
+ set_adapter_scheme :do
43
+
44
+ # Convert the given exceptions to Sequel:Errors, necessary
45
+ # because DO raises errors specific to database types in
46
+ # certain cases.
47
+ attr_accessor :converted_exceptions
48
+
49
+ # Call the DATABASE_SETUP proc directly after initialization,
50
+ # so the object always uses sub adapter specific code. Also,
51
+ # raise an error immediately if the connection doesn't have a
52
+ # uri, since DataObjects requires one.
53
+ def initialize(opts)
54
+ @opts = opts
55
+ @converted_exceptions = []
56
+ raise(Error, "No connection string specified") unless uri
57
+ if prok = DATABASE_SETUP[subadapter.to_sym]
58
+ prok.call(self)
59
+ end
60
+ super(opts)
61
+ end
62
+
63
+ # Setup a DataObjects::Connection to the database.
64
+ def connect(server)
65
+ setup_connection(::DataObjects::Connection.new(uri(server_opts(server))))
66
+ end
67
+
68
+ # Return a Sequel::DataObjects::Dataset object for this database.
69
+ def dataset(opts = nil)
70
+ DataObjects::Dataset.new(self, opts)
71
+ end
72
+
73
+ # Execute the given SQL. If a block is given, the DataObjects::Reader
74
+ # created is yielded to it. A block should not be provided unless a
75
+ # a SELECT statement is being used (or something else that returns rows).
76
+ # Otherwise, the return value is the insert id if opts[:type] is :insert,
77
+ # or the number of affected rows, otherwise.
78
+ def execute(sql, opts={})
79
+ log_info(sql)
80
+ synchronize(opts[:server]) do |conn|
81
+ begin
82
+ command = conn.create_command(sql)
83
+ res = block_given? ? command.execute_reader : command.execute_non_query
84
+ rescue Exception => e
85
+ raise_error(e, :classes=>@converted_exceptions)
86
+ end
87
+ if block_given?
88
+ begin
89
+ yield(res)
90
+ ensure
91
+ res.close if res
92
+ end
93
+ elsif opts[:type] == :insert
94
+ res.insert_id
95
+ else
96
+ res.affected_rows
97
+ end
98
+ end
99
+ end
100
+
101
+ # Execute the SQL on the this database, returning the number of affected
102
+ # rows.
103
+ def execute_dui(sql, opts={})
104
+ execute(sql, opts)
105
+ end
106
+
107
+ # Execute the SQL on this database, returning the primary key of the
108
+ # table being inserted to.
109
+ def execute_insert(sql, opts={})
110
+ execute(sql, opts.merge(:type=>:insert))
111
+ end
112
+
113
+ # Return the subadapter type for this database, i.e. sqlite3 for
114
+ # do:sqlite3::memory:.
115
+ def subadapter
116
+ uri.split(":").first
117
+ end
118
+
119
+ # Use DataObject's transaction support for transactions. This
120
+ # only supports single level transactions, and it always prepares
121
+ # transactions and commits them immediately after. It's wasteful,
122
+ # but required by DataObject's API.
123
+ def transaction(opts={})
124
+ unless opts.is_a?(Hash)
125
+ Deprecation.deprecate('Passing an argument other than a Hash to Database#transaction', "Use DB.transaction(:server=>#{opts.inspect})")
126
+ opts = {:server=>opts}
127
+ end
128
+ th = Thread.current
129
+ synchronize(opts[:server]) do |conn|
130
+ return yield(conn) if @transactions.include?(th)
131
+ t = ::DataObjects::Transaction.create_for_uri(uri)
132
+ t.instance_variable_get(:@connection).close
133
+ t.instance_variable_set(:@connection, conn)
134
+ begin
135
+ log_info("Transaction.begin")
136
+ t.begin
137
+ @transactions << th
138
+ yield(conn)
139
+ rescue Exception => e
140
+ log_info("Transaction.rollback")
141
+ t.rollback
142
+ transaction_error(e)
143
+ ensure
144
+ unless e
145
+ log_info("Transaction.commit")
146
+ t.prepare
147
+ t.commit
148
+ end
149
+ @transactions.delete(th)
150
+ end
151
+ end
152
+ end
153
+
154
+ # Return the DataObjects URI for the Sequel URI, removing the do:
155
+ # prefix.
156
+ def uri(opts={})
157
+ opts = @opts.merge(opts)
158
+ (opts[:uri] || opts[:url]).sub(/\Ado:/, '')
159
+ end
160
+
161
+ private
162
+
163
+ # Close the given database connection.
164
+ def disconnect_connection(c)
165
+ c.close
166
+ end
167
+
168
+ # Allow extending the given connection when it is first created.
169
+ # By default, just returns the connection.
170
+ def setup_connection(conn)
171
+ conn
172
+ end
173
+
174
+ # The DataObjects adapter should convert exceptions by default.
175
+ def connection_pool_default_options
176
+ super.merge(:pool_convert_exceptions=>false)
177
+ end
178
+ end
179
+
180
+ # Dataset class for Sequel::DataObjects::Database objects.
181
+ class Dataset < Sequel::Dataset
182
+ # Execute the SQL on the database and yield the rows as hashes
183
+ # with symbol keys.
184
+ def fetch_rows(sql)
185
+ execute(sql) do |reader|
186
+ cols = @columns = reader.fields.map{|f| output_identifier(f)}
187
+ while(reader.next!) do
188
+ h = {}
189
+ cols.zip(reader.values).each{|k, v| h[k] = v}
190
+ yield h
191
+ end
192
+ end
193
+ self
194
+ end
195
+ end
196
+ end
197
+ end