2016-02-03 21:29:09 +00:00
|
|
|
require "uri"
|
|
|
|
|
2016-01-31 22:40:02 +00:00
|
|
|
# The DB module is a unified interface to database access.
|
|
|
|
# Database dialects is supported by custom database driver shards.
|
|
|
|
# Check [manastech/crystal-sqlite3](https://github.com/manastech/crystal-sqlite3) for example.
|
|
|
|
#
|
|
|
|
# Drivers implementors check `Driver` class.
|
|
|
|
#
|
2016-07-07 18:50:09 +00:00
|
|
|
# DB manage a connection pool. The connection pool can be configured by `URI` query. See `Database`.
|
2016-01-31 22:40:02 +00:00
|
|
|
#
|
|
|
|
# ### Usage
|
|
|
|
#
|
|
|
|
# Assuming `crystal-sqlite3` is included a sqlite3 database can be opened with `#open`.
|
|
|
|
#
|
|
|
|
# ```
|
2016-02-16 00:56:45 +00:00
|
|
|
# db = DB.open "sqlite3:./path/to/db/file.db"
|
2016-01-31 22:40:02 +00:00
|
|
|
# db.close
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# If a block is given to `#open` the database is closed automatically
|
|
|
|
#
|
|
|
|
# ```
|
2016-02-16 00:56:45 +00:00
|
|
|
# DB.open "sqlite3:./file.db" do |db|
|
2016-01-31 22:40:02 +00:00
|
|
|
# # work with db
|
|
|
|
# end # db is closed
|
|
|
|
# ```
|
|
|
|
#
|
2016-02-16 00:56:45 +00:00
|
|
|
# In the code above `db` is a `Database`. Methods available for querying it are described in `QueryMethods`.
|
|
|
|
#
|
2016-01-31 22:40:02 +00:00
|
|
|
# Three kind of statements can be performed:
|
|
|
|
# 1. `Database#exec` waits no response from the database.
|
|
|
|
# 2. `Database#scalar` reads a single value of the response.
|
|
|
|
# 3. `Database#query` returns a ResultSet that allows iteration over the rows in the response and column information.
|
|
|
|
#
|
|
|
|
# All of the above methods allows parametrised query. Either positional or named arguments.
|
|
|
|
#
|
|
|
|
# Check a full working version:
|
|
|
|
#
|
|
|
|
# ```
|
|
|
|
# require "db"
|
|
|
|
# require "sqlite3"
|
|
|
|
#
|
2016-02-16 00:56:45 +00:00
|
|
|
# DB.open "sqlite3:./file.db" do |db|
|
2016-01-31 22:40:02 +00:00
|
|
|
# db.exec "create table contacts (name string, age integer)"
|
|
|
|
# db.exec "insert into contacts values (?, ?)", "John Doe", 30
|
2016-02-04 00:28:53 +00:00
|
|
|
#
|
|
|
|
# args = [] of DB::Any
|
|
|
|
# args << "Sarah"
|
|
|
|
# args << 33
|
|
|
|
# db.exec "insert into contacts values (?, ?)", args
|
2016-01-31 22:40:02 +00:00
|
|
|
#
|
|
|
|
# puts "max age:"
|
|
|
|
# puts db.scalar "select max(age) from contacts" # => 33
|
|
|
|
#
|
|
|
|
# puts "contacts:"
|
|
|
|
# db.query "select name, age from contacts order by age desc" do |rs|
|
|
|
|
# puts "#{rs.column_name(0)} (#{rs.column_name(1)})"
|
|
|
|
# # => name (age)
|
|
|
|
# rs.each do
|
|
|
|
# puts "#{rs.read(String)} (#{rs.read(Int32)})"
|
|
|
|
# # => Sarah (33)
|
|
|
|
# # => John Doe (30)
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
# ```
|
|
|
|
#
|
2016-01-28 22:41:12 +00:00
|
|
|
module DB
|
2016-01-31 22:40:02 +00:00
|
|
|
# Types supported to interface with database driver.
|
|
|
|
# These can be used in any `ResultSet#read` or any `Database#query` related
|
|
|
|
# method to be used as query parameters
|
2016-06-22 17:10:09 +00:00
|
|
|
TYPES = [Nil, String, Int32, Int64, Float32, Float64, Bytes]
|
2016-01-31 22:40:02 +00:00
|
|
|
|
2016-06-21 15:08:51 +00:00
|
|
|
# See `DB::TYPES` in `DB`. `Any` is a union of all types in `DB::TYPES`
|
|
|
|
{% begin %}
|
|
|
|
alias Any = Union({{*TYPES}})
|
|
|
|
{% end %}
|
2016-01-29 19:13:01 +00:00
|
|
|
|
2016-02-02 02:02:04 +00:00
|
|
|
# Result of a `#exec` statement.
|
2016-06-21 21:31:13 +00:00
|
|
|
record ExecResult, rows_affected : Int64, last_insert_id : Int64
|
2016-02-02 00:55:30 +00:00
|
|
|
|
2016-02-02 02:02:04 +00:00
|
|
|
# :nodoc:
|
2016-02-19 21:42:30 +00:00
|
|
|
def self.driver_class(driver_name) : Driver.class
|
2016-10-21 14:24:32 +00:00
|
|
|
drivers[driver_name]? ||
|
|
|
|
raise(ArgumentError.new(%(no driver was registered for the schema "#{driver_name}", did you maybe forget to require the database driver?)))
|
2016-01-28 22:41:12 +00:00
|
|
|
end
|
|
|
|
|
2016-02-03 21:29:09 +00:00
|
|
|
# Registers a driver class for a given *driver_name*.
|
2016-01-31 22:40:02 +00:00
|
|
|
# Should be called by drivers implementors only.
|
|
|
|
def self.register_driver(driver_name, driver_class : Driver.class)
|
2016-10-21 14:24:32 +00:00
|
|
|
drivers[driver_name] = driver_class
|
|
|
|
end
|
|
|
|
|
|
|
|
private def self.drivers
|
2016-01-28 22:41:12 +00:00
|
|
|
@@drivers ||= {} of String => Driver.class
|
|
|
|
end
|
|
|
|
|
2016-02-03 21:29:09 +00:00
|
|
|
# Opens a database using the specified *uri*.
|
|
|
|
# The scheme of the *uri* determines the driver to use.
|
2016-01-31 22:40:02 +00:00
|
|
|
# Returned database must be closed by `Database#close`.
|
2016-02-03 21:29:09 +00:00
|
|
|
# If a block is used the database is yielded and closed automatically.
|
|
|
|
def self.open(uri : URI | String)
|
|
|
|
build_database(uri)
|
2016-01-28 22:41:12 +00:00
|
|
|
end
|
2016-01-30 22:46:43 +00:00
|
|
|
|
2016-01-31 22:40:02 +00:00
|
|
|
# Same as `#open` but the database is yielded and closed automatically.
|
2016-02-03 21:29:09 +00:00
|
|
|
def self.open(uri : URI | String, &block)
|
2016-06-29 19:54:16 +00:00
|
|
|
db = build_database(uri)
|
|
|
|
begin
|
|
|
|
yield db
|
|
|
|
ensure
|
|
|
|
db.close
|
2016-01-30 22:46:43 +00:00
|
|
|
end
|
|
|
|
end
|
2016-02-03 21:29:09 +00:00
|
|
|
|
|
|
|
private def self.build_database(connection_string : String)
|
|
|
|
build_database(URI.parse(connection_string))
|
|
|
|
end
|
|
|
|
|
|
|
|
private def self.build_database(uri : URI)
|
2016-02-03 22:30:51 +00:00
|
|
|
Database.new(driver_class(uri.scheme).new, uri)
|
2016-02-03 21:29:09 +00:00
|
|
|
end
|
2016-01-28 22:41:12 +00:00
|
|
|
end
|
|
|
|
|
2016-07-05 18:21:39 +00:00
|
|
|
require "./db/pool"
|
2016-08-30 19:20:18 +00:00
|
|
|
require "./db/string_key_cache"
|
2016-02-26 01:37:10 +00:00
|
|
|
require "./db/query_methods"
|
|
|
|
require "./db/disposable"
|
|
|
|
require "./db/database"
|
|
|
|
require "./db/driver"
|
|
|
|
require "./db/connection"
|
|
|
|
require "./db/statement"
|
2016-08-29 19:56:34 +00:00
|
|
|
require "./db/pool_statement"
|
2016-02-26 01:37:10 +00:00
|
|
|
require "./db/result_set"
|
2016-06-28 17:02:08 +00:00
|
|
|
require "./db/error"
|
2016-03-28 23:45:07 +00:00
|
|
|
require "./db/mapping"
|