Class: Swift::Adapter

Inherits:
Object
  • Object
show all
Defined in:
lib/swift/adapter.rb,
lib/swift/synchrony.rb,
lib/swift/adapter/sql.rb,
lib/swift/eventmachine.rb,
lib/swift/identity_map.rb,
lib/swift/adapter/mysql.rb,
lib/swift/adapter/sqlite3.rb,
lib/swift/adapter/postgres.rb

Overview

IdentityMap

Direct Known Subclasses

Sql

Defined Under Namespace

Classes: EMHandler, Mysql, Postgres, Sql, Sqlite3

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db) ⇒ Adapter

Returns a new instance of Adapter.



13
14
15
# File 'lib/swift/adapter.rb', line 13

def initialize db
  @db = db
end

Instance Attribute Details

#dbObject (readonly)

Returns the value of attribute db.



11
12
13
# File 'lib/swift/adapter.rb', line 11

def db
  @db
end

Instance Method Details

#execute(record, command, *bind) ⇒ Swift::Result, ... #execute(command, *bind) ⇒ Swift::Result, ...

Execute a command using the underlying concrete adapter.

Examples:

Swift.db.execute("select * from users")
Swift.db.execute(User, "select * from users where id = ?", 1)

Overloads:

  • #execute(record, command, *bind) ⇒ Swift::Result, ...

    Parameters:

    • record (Swift::Record)

      Concrete record subclass to load.

    • command (String)

      Command to be executed by the adapter.

    • bind (*Object)

      Bind values.

  • #execute(command, *bind) ⇒ Swift::Result, ...

    Parameters:

    • command (String)

      Command to be executed by the adapter.

    • bind (*Object)

      Bind values.

Returns:

  • (Swift::Result, Swift::DB::Mysql::Result, Swift::DB::Sqlite3::Result, ...)


10
11
12
13
14
15
16
# File 'lib/swift/synchrony.rb', line 10

def execute command, *bind
  start = Time.now
  record, command = command, bind.shift if command.kind_of?(Class) && command < Record
  record ? Result.new(record, db.execute(command, *bind)) : db.execute(command, *bind)
ensure
  log_command(start, command, bind) if @trace
end

#blocking_execute {|res| ... } ⇒ Object

Execute a command asynchronously and pause the Fiber until the command finishes.

Examples:

EM.run do
  3.times.each do |n|
    EM.synchrony do
      db     = Swift.setup(:default, Swift::Adapter::Postgres, db: "swift_test")
      result = db.execute("select pg_sleep(3 - #{n}), #{n + 1} as qid")

      p result.first
      EM.stop if n == 0
    end
  end
end

Yields:

  • (res)

See Also:

  • Swift::Adapter.[Swift[Swift::Adapter]


9
10
11
12
13
14
15
# File 'lib/swift/eventmachine.rb', line 9

def execute command, *bind
  start = Time.now
  record, command = command, bind.shift if command.kind_of?(Class) && command < Record
  record ? Result.new(record, db.execute(command, *bind)) : db.execute(command, *bind)
ensure
  log_command(start, command, bind) if @trace
end

#create(record, resources) ⇒ Swift::Record+

Note:

Hashes will be coerced into a Swift::Record resource via Swift::Record#new

Note:

Passing a scalar will result in a scalar.

Create one or more.

Examples:

Record.

user = User.new(name: 'Apply Arthurton', age: 32)
Swift.db.create(User, user)
#=> Swift::Record

Coerce hash to record.

Swif.db.create(User, name: 'Apple Arthurton', age: 32)
#=> Swift::Record

Multiple resources.

apple = User.new(name: 'Apple Arthurton', age: 32)
benny = User.new(name: 'Benny Arthurton', age: 30)
Swift.db.create(User, [apple, benny])
#=> Array<Swift::Record>

Coerce multiple resources.

Swift.db.create(User, [{name: 'Apple Arthurton', age: 32}, {name: 'Benny Arthurton', age: 30}])
#=> Array<Swift::Record>

Parameters:

Returns:

See Also:



59
60
61
62
63
64
65
66
67
# File 'lib/swift/adapter.rb', line 59

def create record, resources
  result = [resources].flatten.map do |resource|
    resource = record.new(resource) unless resource.kind_of?(record)
    result   = execute(command_create(record), *resource.tuple.values_at(*record.header.insertable))
    resource.tuple[record.header.serial] = result.insert_id if record.header.serial
    resource
  end
  resources.kind_of?(Array) ? result : result.first
end

#delete(record, resources) ⇒ Swift::Record+

Note:

Hashes will be coerced into a Swift::Record resource via Swift::Record#new

Note:

Passing a scalar will result in a scalar.

Delete one or more.

Examples:

Record.

user      = Swift.db.create(User, name: 'Apply Arthurton', age: 32)
user.name = 'Arthur Appleton'
Swift.db.delete(User, user)

Coerce hash to record.

user      = Swift.db.create(User, name: 'Apply Arthurton', age: 32)
user.name = 'Arthur Appleton'
Swif.db.delete(User, user.tuple)

Multiple resources.

apple = Swift.db.create(User, name: 'Apple Arthurton', age: 32)
benny = Swift.db.create(User, name: 'Benny Arthurton', age: 30)
Swift.db.delete(User, [apple, benny])

Coerce multiple resources.

apple = Swift.db.create(User, name: 'Apple Arthurton', age: 32)
benny = Swift.db.create(User, name: 'Benny Arthurton', age: 30)
Swift.db.delete(User, [apple.tuple, benny.tuple])

Parameters:

Returns:

See Also:



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/swift/adapter.rb', line 138

def delete record, resources
  result = [resources].flatten.map do |resource|
    resource = record.new(resource) unless resource.kind_of?(record)
    keys     = resource.tuple.values_at(*record.header.keys)

    # TODO: Name the key field(s) missing.
    raise ArgumentError, "#{record} resource has incomplete key: #{resource.inspect}" \
      unless keys.select(&:nil?).empty?

    if result = execute(command_delete(record), *keys)
      resource.freeze
    end
    result
  end
  resources.kind_of?(Array) ? result : result.first
end

#execute(command, *bind) ⇒ Object

Execute a command asynchronously.

Examples:

defer = Swift.db.execute(User, "select * from users where id = ?", 1)
defer.callback do |user|
  p user.id
end
defer.errback do |error|
  p error
end

Raises:

See Also:

  • Swift::Adapter.[Swift[Swift::Adapter]


214
215
216
217
218
219
220
# File 'lib/swift/adapter.rb', line 214

def execute command, *bind
  start = Time.now
  record, command = command, bind.shift if command.kind_of?(Class) && command < Record
  record ? Result.new(record, db.execute(command, *bind)) : db.execute(command, *bind)
ensure
  log_command(start, command, bind) if @trace
end

#get(record, keys) ⇒ Swift::Record?

Select by id(s).

– NOTE: Not significantly shorter than Record.db.first(User, ‘id = ?’, 12)

Examples:

Single key.

Swift.db.get(User, id: 12)

Complex primary key.

Swift.db.get(UserAddress, user_id: 12, address_id: 15)

Parameters:

  • record (Swift::Record)

    Concrete record subclass to load.

  • keys (Hash)

    Hash of id(s) {id_name: value}.

Returns:

See Also:



30
31
32
33
# File 'lib/swift/adapter.rb', line 30

def get record, keys
  resource = record.new(keys)
  execute(record, command_get(record), *resource.tuple.values_at(*record.header.keys)).first
end

#identity_mapObject



31
32
33
# File 'lib/swift/identity_map.rb', line 31

def identity_map
  @identity_map ||= IdentityMap.new
end

#log_command(start, command, bind) ⇒ Object

:nodoc:



223
224
225
226
227
# File 'lib/swift/adapter.rb', line 223

def log_command start, command, bind
  @trace.print Time.now.strftime('%F %T.%N'), ' - %.9f' % (Time.now - start).to_f, ' - ', command
  @trace.print ' ', bind if bind && bind.size > 0
  @trace.print $/
end

#pendingObject



57
58
59
# File 'lib/swift/eventmachine.rb', line 57

def pending
  @pending ||= []
end

#prepare(record, command) ⇒ Swift::Statement, ... #prepare(command) ⇒ Swift::Statement, ...

Create a server side prepared statement

Examples:

finder = Swift.db.prepare(User, "select * from users where id > ?")
user   = finder.execute(1).first
user.id

Overloads:

  • #prepare(record, command) ⇒ Swift::Statement, ...

    Parameters:

    • record (Swift::Record)

      Concrete record subclass to load.

    • command (String)

      Command to be prepared by the underlying concrete adapter.

  • #prepare(command) ⇒ Swift::Statement, ...

    Parameters:

    • command (String)

      Command to be prepared by the underlying concrete adapter.

Returns:

  • (Swift::Statement, Swift::DB::Mysql::Statement, Swift::DB::Sqlite3::Statement, ...)


169
170
171
# File 'lib/swift/adapter.rb', line 169

def prepare record = nil, command
  record ? Statement.new(record, command) : db.prepare(command)
end

#trace(io = $stdout) ⇒ Object

Trace commands being executed.

Examples:

Swift.db.trace { Swift.db.execute("select * from users") }
Swift.db.trace(StringIO.new) { Swift.db.execute("select * from users") }
Swift.db.trace(File.open('command.log', 'w')) { Swift.db.execute("select * from users") }

Parameters:

  • io (IO) (defaults to: $stdout)

    An optional IO object to log commands

Returns:

  • (Object)

    result Result from the block yielded to



184
185
186
187
188
189
# File 'lib/swift/adapter.rb', line 184

def trace io = $stdout
  @trace = io
  result = yield
  @trace = false
  result
end

#trace?TrueClass, FalseClass

Check if the adapter commands are being traced.

Returns:

  • (TrueClass, FalseClass)


194
195
196
# File 'lib/swift/adapter.rb', line 194

def trace?
  !!@trace
end

#update(record, resources) ⇒ Swift::Record, Swift::Result

Note:

Hashes will be coerced into a Swift::Record resource via Swift::Record#new

Note:

Passing a scalar will result in a scalar.

Update one or more.

Examples:

Record.

user      = Swift.db.create(User, name: 'Apply Arthurton', age: 32)
user.name = 'Arthur Appleton'
Swift.db.update(User, user)
#=> Swift::Record

Coerce hash to record.

user      = Swift.db.create(User, name: 'Apply Arthurton', age: 32)
user.name = 'Arthur Appleton'
Swif.db.update(User, user.tuple)
#=> Swift::Record

Multiple resources.

apple = Swift.db.create(User, name: 'Apple Arthurton', age: 32)
benny = Swift.db.create(User, name: 'Benny Arthurton', age: 30)
Swift.db.update(User, [apple, benny])
#=> Array<Swift::Record>

Coerce multiple resources.

apple = Swift.db.create(User, name: 'Apple Arthurton', age: 32)
benny = Swift.db.create(User, name: 'Benny Arthurton', age: 30)
Swift.db.update(User, [apple.tuple, benny.tuple])
#=> Array<Swift::Record>

Parameters:

Returns:

See Also:



98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/swift/adapter.rb', line 98

def update record, resources
  result = [resources].flatten.map do |resource|
    resource = record.new(resource) unless resource.kind_of?(record)
    keys     = resource.tuple.values_at(*record.header.keys)

    # TODO: Name the key field(s) missing.
    raise ArgumentError, "#{record} resource has incomplete key: #{resource.inspect}" \
      unless keys.select(&:nil?).empty?

    execute(command_update(record), *resource.tuple.values_at(*record.header.updatable), *keys)
    resource
  end
  resources.kind_of?(Array) ? result : result.first
end