module DB
Overview
The DB module is a unified interface for database access. Individual database systems are supported by specific database driver shards.
Available drivers include:
- crystal-lang/crystal-sqlite3 for SQLite
- crystal-lang/crystal-mysql for MySQL and MariaDB
- will/crystal-pg for PostgreSQL
- kaukas/crystal-cassandra for Cassandra
For basic instructions on implementing a new database driver, check Driver and the existing drivers.
DB manages a connection pool. The connection pool can be configured by query parameters to the
connection URI as described in Database.
Usage
Assuming crystal-sqlite3 is included a SQLite3 database can be opened with #open.
db = DB.open "sqlite3:./path/to/db/file.db"
db.close
If a block is given to #open the database is closed automatically
DB.open "sqlite3:./file.db" do |db|
# work with db
end # db is closed
In the code above db is a Database. Methods available for querying it are described in QueryMethods.
Three kind of statements can be performed:
Database#execwaits no response from the database.Database#scalarreads a single value of the response.Database#queryreturns 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:
The following example uses SQLite where ? indicates the arguments. If PostgreSQL is used $1, $2, etc. should be used. crystal-db does not interpret the statements.
require "db"
require "sqlite3"
DB.open "sqlite3:./file.db" do |db|
# When using the pg driver, use $1, $2, etc. instead of ?
db.exec "create table contacts (name text, age integer)"
db.exec "insert into contacts values (?, ?)", "John Doe", 30
args = [] of DB::Any
args << "Sarah"
args << 33
db.exec "insert into contacts values (?, ?)", args: args
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
Object mapping
The DB::Serializable module implements a declarative mapping from DB result
sets to Crystal types.
Defined in:
db.crdb/begin_transaction.cr
db/connection.cr
db/connection_builder.cr
db/connection_context.cr
db/database.cr
db/disposable.cr
db/driver.cr
db/enumerable_concat.cr
db/error.cr
db/mapping.cr
db/pool.cr
db/pool_prepared_statement.cr
db/pool_statement.cr
db/pool_unprepared_statement.cr
db/query_methods.cr
db/result_set.cr
db/serializable.cr
db/session_methods.cr
db/statement.cr
db/string_key_cache.cr
db/transaction.cr
db/version.cr
spec.cr
Constant Summary
-
Log =
::Log.for(self) -
TYPES =
[Nil, String, Bool, Int32, Int64, Float32, Float64, Time, Bytes] -
Types supported to interface with database driver. These can be used in any
ResultSet#reador anyDatabase#queryrelated method to be used as query parameters -
VERSION =
"0.13.0"
Class Method Summary
-
.connect(uri : URI | String)
Opens a connection using the specified uri.
-
.connect(uri : URI | String, &)
Opens a connection using the specified uri.
-
.open(uri : URI | String)
Creates a
Databasepool and opens initial connection(s) as specified in the connection uri. -
.open(uri : URI | String, &)
Same as
#openbut the database is yielded and closed automatically at the end of the block. -
.register_driver(driver_name, driver_class : Driver.class)
Registers a driver class for a given driver_name.
Macro Summary
-
mapping(properties, strict = true)
The
DB.mappingmacro defines how an object is built from aResultSet.DEPRECATED Use
DB::Serializableinstead -
mapping(**properties)
DEPRECATED Use
DB::Serializableinstead
Class Method Detail
Opens a connection using the specified uri.
The scheme of the uri determines the driver to use.
Returned connection must be closed by Connection#close.
If a block is used the connection is yielded and closed automatically.
Opens a connection using the specified uri.
The scheme of the uri determines the driver to use.
Returned connection must be closed by Connection#close.
If a block is used the connection is yielded and closed automatically.
Creates a Database pool and opens initial connection(s) as specified in the connection uri.
Use DB#connect to open a single connection.
The scheme of the uri determines the driver to use. Connection parameters such as hostname, user, database name, etc. are specified according to each database driver's specific format.
The returned database must be closed by Database#close.
Same as #open but the database is yielded and closed automatically at the end of the block.
Registers a driver class for a given driver_name. Should be called by drivers implementors only.
Macro Detail
The DB.mapping macro defines how an object is built from a ResultSet.
It takes hash literal as argument, in which attributes and types are defined.
Once defined, ResultSet#read(t) populates properties of the class from the
ResultSet.
require "db"
class Employee
DB.mapping({
title: String,
name: String,
})
end
employees = Employee.from_rs(db.query("SELECT title, name FROM employees"))
employees[0].title # => "Manager"
employees[0].name # => "John"
Attributes not mapped with DB.mapping are not defined as properties.
Also, missing attributes raise a DB::MappingException.
You can also define attributes for each property.
class Employee
DB.mapping({
title: String,
name: {
type: String,
nilable: true,
key: "firstname",
},
})
end
Available attributes:
- type (required) defines its type. In the example above, title: String is a shortcut to title: {type: String}.
- nilable defines if a property can be a
Nil. - default: value to use if the property is missing in the result set, or if it's
nullandnilablewas not set totrue. If the default value creates a new instance of an object (for example[1, 2, 3]orSomeObject.new), a different instance will be used each time a row is parsed. - key defines which column to read from a
ResultSet. It defaults to the name of the property. - converter takes an alternate type for parsing. It requires a
#from_rsmethod in that class, and returns an instance of the given type.
The mapping also automatically defines Crystal properties (getters and setters) for each of the keys. It doesn't define a constructor accepting those arguments, but you can provide an overload.
The macro basically defines a constructor accepting a ResultSet that reads from
it and initializes this type's instance variables.
This macro also declares instance variables of the types given in the mapping.
DEPRECATED Use DB::Serializable instead