class Perpetuity::Postgres
Constants
- InvalidTableName
- VERSION
Attributes
connection[R]
db[R]
host[R]
password[R]
pool_size[R]
port[R]
username[R]
Public Class Methods
new(options)
click to toggle source
# File lib/perpetuity/postgres.rb, line 19 def initialize options @host = options.fetch(:host) { 'localhost' } @port = options.fetch(:port) { 5432 } @db = options.fetch(:db) @pool_size = options.fetch(:pool_size) { 5 } @username = options.fetch(:username) { ENV['USER'] } @password = options.fetch(:password) {} @connection ||= ConnectionPool.new( db: db, host: host, port: port, username: username, password: password, pool_size: pool_size ) end
Public Instance Methods
activate_index!(index)
click to toggle source
# File lib/perpetuity/postgres.rb, line 169 def activate_index! index return if index.active? attribute_names = index.attribute_names.join('_') index_name = "#{index.table}_#{attribute_names}_index" sql = "CREATE " sql << "UNIQUE " if index.unique? sql << "INDEX \"#{index_name}\" " sql << "ON #{TableName.new(index.table)} (#{attribute_names})" connection.execute(sql) index.activate! rescue PG::UndefinedTable => e create_table_with_attributes index.table, index.attributes retry end
active_indexes(table)
click to toggle source
# File lib/perpetuity/postgres.rb, line 185 def active_indexes table sql = <<-SQL SELECT pg_class.relname AS name, ARRAY( SELECT pg_get_indexdef(pg_index.indexrelid, k + 1, true) FROM generate_subscripts(pg_index.indkey, 1) AS k ORDER BY k ) AS attributes, pg_index.indisunique AS unique, pg_index.indisready AS active FROM pg_class INNER JOIN pg_index ON pg_class.oid = pg_index.indexrelid WHERE pg_class.relname ~ '^#{table}.*index$' SQL indexes = connection.execute(sql).map do |index| Index.from_sql(index) end IndexCollection.new(table, indexes) end
add_column(table_name, column_name, attributes)
click to toggle source
# File lib/perpetuity/postgres.rb, line 286 def add_column table_name, column_name, attributes attr = attributes.detect { |a| a.name.to_s == column_name.to_s } column = Table::Attribute.new(attr.name, attr.type, attr.options) sql = %Q(ALTER TABLE "#{table_name}" ADD #{column.sql_declaration}) connection.execute sql end
cast_id(id, id_attribute)
click to toggle source
# File lib/perpetuity/postgres.rb, line 256 def cast_id id, id_attribute return id if id_attribute.nil? if [Bignum, Fixnum, Integer].include? id_attribute.type id.to_i else id end end
count(klass, query='TRUE', options={})
click to toggle source
# File lib/perpetuity/postgres.rb, line 92 def count klass, query='TRUE', options={}, &block where = if block_given? query(&block) else query end options = translate_options(options).merge(from: klass, where: where) table = table_name(klass) sql = select 'COUNT(*)', options connection.execute(sql).to_a.first['count'].to_i rescue PG::UndefinedTable # Table does not exist, so there are 0 records 0 end
create_table(name, attributes)
click to toggle source
# File lib/perpetuity/postgres.rb, line 236 def create_table name, attributes connection.execute Table.new(name, attributes).create_table_sql end
create_table_with_attributes(klass, attributes)
click to toggle source
# File lib/perpetuity/postgres.rb, line 276 def create_table_with_attributes klass, attributes table_attributes = attributes.map do |attr| name = attr.name type = attr.type options = attr.options Table::Attribute.new name, type, options end create_table klass.to_s, table_attributes end
delete(ids, klass)
click to toggle source
# File lib/perpetuity/postgres.rb, line 73 def delete ids, klass ids = Array(ids) table = TableName.new(klass) if ids.one? id_string = TextValue.new(ids.first) sql = "DELETE FROM #{table} WHERE id = #{id_string}" connection.execute(sql).to_a elsif ids.none? # Do nothing, we weren't given anything to delete else id_string = ids.map { |id| TextValue.new(id) } sql = "DELETE FROM #{table} WHERE id IN (#{id_string.join(',')})" connection.execute(sql).to_a end end
delete_all(klass)
click to toggle source
# File lib/perpetuity/postgres.rb, line 115 def delete_all klass table = table_name(klass) sql = "DELETE FROM #{table}" connection.execute(sql) rescue PG::UndefinedTable # Do nothing. There is already nothing here. end
drop_table(name)
click to toggle source
# File lib/perpetuity/postgres.rb, line 231 def drop_table name connection.execute "DROP TABLE IF EXISTS #{table_name(name)}" end
Also aliased as: drop_collection
find(klass, id)
click to toggle source
# File lib/perpetuity/postgres.rb, line 107 def find klass, id retrieve(klass, query { |o| o.id == id }.to_db).first end
has_table?(name)
click to toggle source
# File lib/perpetuity/postgres.rb, line 240 def has_table? name connection.tables.include? name end
increment(klass, id, attribute, count=1)
click to toggle source
# File lib/perpetuity/postgres.rb, line 270 def increment klass, id, attribute, count=1 table = TableName.new(klass) sql = %Q{UPDATE #{table} SET #{attribute} = #{attribute} + #{count} WHERE id = #{SQLValue.new(id)} RETURNING #{attribute}} connection.execute(sql).to_a end
index(klass, attributes, options={})
click to toggle source
# File lib/perpetuity/postgres.rb, line 154 def index klass, attributes, options={} name = "#{klass}_#{Array(attributes).map(&:name).join('_')}_index" index = Index.new(name: name, attributes: Array(attributes), unique: !!options[:unique], active: false) indexes(klass) << index index end
indexes(klass)
click to toggle source
# File lib/perpetuity/postgres.rb, line 164 def indexes klass @indexes ||= {} @indexes[klass] ||= active_indexes(klass) end
insert(klass, serialized_objects, attributes)
click to toggle source
# File lib/perpetuity/postgres.rb, line 37 def insert klass, serialized_objects, attributes table = TableName.new(klass) data = serialized_objects.reduce(:+) sql = "INSERT INTO #{table} #{data} RETURNING id" results = connection.execute(sql).to_a ids = results.map { |result| cast_id(result['id'], attributes[:id]) } ids rescue PG::UndefinedTable => e # Table doesn't exist, so we create it. retries ||= 0 retries += 1 create_table_with_attributes klass, attributes retry unless retries > 1 raise e rescue PG::UndefinedColumn => e retries ||= 0 retries += 1 error ||= nil if retries > 1 && e.message == error # We've retried more than once and we're getting the same error raise end error = e.message if error =~ /column "(.+)" of relation "(.+)" does not exist/ column_name = $1 table_name = $2 add_column table_name, column_name, attributes retry end raise end
negate_query(&block)
click to toggle source
# File lib/perpetuity/postgres.rb, line 127 def negate_query &block NegatedQuery.new(&block) end
postgresify(value)
click to toggle source
# File lib/perpetuity/postgres.rb, line 244 def postgresify value Serializer.new(nil).serialize_attribute value end
query(&block)
click to toggle source
# File lib/perpetuity/postgres.rb, line 123 def query &block Query.new(&block) end
remove_index(index)
click to toggle source
# File lib/perpetuity/postgres.rb, line 206 def remove_index index sql = %Q{DROP INDEX IF EXISTS #{TableName.new(index.name)}} connection.execute(sql) end
retrieve(klass, criteria, options={})
click to toggle source
# File lib/perpetuity/postgres.rb, line 131 def retrieve klass, criteria, options={} options = translate_options(options).merge from: klass, where: criteria sql = select options connection.execute(sql).to_a rescue PG::UndefinedTable [] end
select(*args)
click to toggle source
# File lib/perpetuity/postgres.rb, line 227 def select *args SQLSelect.new(*args).to_s end
serialize(object, mapper)
click to toggle source
# File lib/perpetuity/postgres.rb, line 248 def serialize object, mapper Serializer.new(mapper).serialize object end
serialize_changed_attributes(object, original, mapper)
click to toggle source
# File lib/perpetuity/postgres.rb, line 252 def serialize_changed_attributes object, original, mapper Serializer.new(mapper).serialize_changes object, original end
table_name(klass)
click to toggle source
# File lib/perpetuity/postgres.rb, line 111 def table_name klass TableName.new(klass) end
translate_options(options)
click to toggle source
# File lib/perpetuity/postgres.rb, line 211 def translate_options options options = options.dup if options[:attribute] options[:order] = options.delete(:attribute) if direction = options.delete(:direction) direction = direction.to_s[/(asc|desc)/i] options[:order] = { options[:order] => direction } end end if options[:skip] options[:offset] = options.delete(:skip) end options end
unserialize(data, mapper)
click to toggle source
# File lib/perpetuity/postgres.rb, line 266 def unserialize data, mapper Serializer.new(mapper).unserialize data end
update(klass, id, attributes)
click to toggle source
# File lib/perpetuity/postgres.rb, line 140 def update klass, id, attributes sql = SQLUpdate.new(klass, id, attributes).to_s connection.execute(sql).to_a rescue PG::UndefinedColumn => e if e.message =~ /column "(.*)" of relation "(.*)" does not exist/ column_name = $1 table_name = $2 add_column table_name, column_name, [Attribute.new(column_name, attributes[column_name].class)] retry else raise e end end