Swift PostgreSQL adapter
MRI adapter for PostgreSQL
Features
- Lightweight & fast
- Result typecasting
- Prepared statements
- Asynchronous support using PQsendQuery family of functions
- Nested transactions
Requirements
- postgresql client deveopment libraries (libpq-dev)
- uuid development libraries (uuid-dev)
Building
git submodule update --init
rake
API
``` Swift::DB::Postgres .new(options) #execute(sql, *bind) #prepare(sql) #begin(savepoint = nil) #commit(savepoint = nil) #rollback(savepoint = nil) #transaction(savepoint = nil, &block) #native_bind_format(&block) #native_bind_format=(value) #ping #close #closed? #escape(text) #query(sql, *bind) #fileno #result #write(table = nil, fields = nil, io_or_string) #read(table = nil, fields = nil, io = nil, &block)
Swift::DB::Postgres::Statement .new(Swift::DB::Postgres, sql) #execute(*bind) #release
Swift::DB::Postgres::Result #selected_rows #affected_rows #fields #types #each #insert_id ```
Connection options
╭────────────────────╥────────────┬─────────────╮
│ Name ║ Default │ Optional │
╞════════════════════╬════════════╪═════════════╡
│ db ║ - │ No │
│ host ║ 127.0.0.1 │ Yes │
│ port ║ 5432 │ Yes │
│ user ║ Etc.login │ Yes │
│ password ║ nil │ Yes │
│ encoding ║ utf8 │ Yes │
│ ssl[:sslmode] ║ allow │ Yes │
│ ssl[:sslcert] ║ nil │ Yes │
│ ssl[:sslkey] ║ nil │ Yes │
│ ssl[:sslrootcert] ║ nil │ Yes │
│ ssl[:sslcrl] ║ nil │ Yes │
└────────────────────╨────────────┴─────────────┘
Bind parameters and hstore operators
Swift::DB::Postgres uses ‘?’ as a bind parameter and replaces them with the ‘$’ equivalents. This causes issues when you try to use the HStore ‘?’ operator. You can permanently or temporarily disable the replacement strategy as below:
```ruby
db.native_bind_format = true db.execute(“select * from users where tags ? $1”, ‘mayor’) db.native_bind_format = false
db.native_bind_format do db.execute(“select * from users where tags ? $1”, ‘mayor’) end ```
Example
```ruby require ‘swift/db/postgres’
db = Swift::DB::Postgres.new(db: ‘swift_test’, encoding: ‘utf8’)
db.execute(‘drop table if exists users’) db.execute(‘create table users (id serial, name text, age integer, created_at timestamp)’) db.execute(‘insert into users(name, age, created_at) values(?, ?, ?)’, ‘test’, 30, Time.now.utc)
row = db.execute(‘select * from users’).first p row #=> => 1, :name => ‘test’, :age => 30, :created_at=> #<Swift::DateTime> ```
Asynchronous
Hint: You can use Adapter#fileno
and EventMachine.watch
if you need to use this with EventMachine.
```ruby require ‘swift/db/postgres’
rows = [] pool = 3.times.map ‘swift_test’)
3.times do |n| Thread.new do pool[n].query(“select pg_sleep(#- n) / 10.0), #+ 1 as query_id”) do |row| rows « row[:query_id] end end end
Thread.list.reject {|thread| Thread.current == thread}.each(&:join) rows #=> [3, 2, 1] ```
Data I/O
The adapter supports data read and write via COPY command.
```ruby require ‘swift/db/postgres’
db = Swift::DB::Postgres.new(db: ‘swift_test’) db.execute(‘drop table if exists users’) db.execute(‘create table users (id serial, name text)’)
db.write(‘users’, %wname, “foo\nbar\nbaz\n”) db.write(‘users’, %wname, StringIO.new(“foo\nbar\nbaz\n”)) db.write(‘users’, %wname, File.open(“users.dat”))
db.read(‘users’, %wname) do |data| p data end
csv = File.open(‘users.csv’, ‘w’) db.execute(‘copy users to stdout with csv’) db.read(csv) ```
Performance
Don’t read too much into it. Each library has its advantages and disadvantages.
- insert 1000 rows and read them back 100 times with typecast enabled
- pg uses the pg_typecast extension
``` $ ruby -v
ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-linux]
$ ruby check.rb user system total real do_postgres insert 0.190000 0.080000 0.270000 ( 0.587877) do_postgres select 1.440000 0.020000 1.460000 ( 2.081172)
pg insert 0.100000 0.030000 0.130000 ( 0.395280) pg select 0.630000 0.220000 0.850000 ( 1.284905)
swift insert 0.070000 0.040000 0.110000 ( 0.348211) swift select 0.640000 0.030000 0.670000 ( 1.111561) ```
License
MIT