Added SELECT object mapping, convenience methods, fixed weakref usage after object death

This commit is contained in:
Yessiest 2023-10-08 23:22:39 +04:00
parent 22c4722a8c
commit b35d4926b1
2 changed files with 46 additions and 11 deletions

View File

@ -65,20 +65,53 @@ module LPGAR
# Return either an existing Record or create a new one. # Return either an existing Record or create a new one.
# @param data [Hash{String => Object}] row data # @param data [Hash{String => Object}] row data
def new(data) # @param syncless [Boolean] do not perform any communication with PG
# @return [Object] new record object
def new(data, syncless: false)
check_instantiable check_instantiable
ident = Digest::MD5.hexdigest(data.values_at(*cols_pk).join) ident = Digest::MD5.hexdigest(data.values_at(*cols_pk).join)
if @instances[ident] if @instances[ident] and @instances[ident].weakref_alive?
@instances[ident].sync @instances[ident].sync
@instances[ident] @instances[ident]
end end
new_record = super(data) new_record = super(data)
create(new_record) unless new_record.sync unless syncless
synced = new_record.sync
insert_query(new_record) unless synced
end
track_instance(new_record) track_instance(new_record)
new_record new_record
end end
# Explicitly create a new record. Returns nil if exists.
# @param data [Hash{String => Object}] row data
# @return [(Object,nil)] new record object or nil if exists
def create(data)
instance = new(data, syncless: true)
return if instance.sync
insert_query(instance)
instance
end
# Explicitly request an existing record. Returns nil if doesn't exist.
# @param data [Hash{String => Object}] row data
# @return [(Object,nil)] new record object or nil if doesn't exist.
def get(data)
instance = new(data, syncless: true)
instance if instance.sync
end
# Map returned rows from a query to an array of objects of this table.
# @param query [String] raw postgresql query
# @return [Array(Object)] array of records of this table
def map(query)
conn.exec(query).map do |row|
new(row, syncless: true)
end
end
# Change row identity # Change row identity
# Should not be called directly in most cases. # Should not be called directly in most cases.
# @param original [String] original row identity # @param original [String] original row identity
@ -91,15 +124,15 @@ module LPGAR
# Create sync query. # Create sync query.
# @return [String] # @return [String]
def sync_query def sync_query
return @_memo_query if @_memo_query return @sync_query if @sync_query
selector = @cols_pk.map.with_index do |pk, index| selector = @cols_pk.map.with_index do |key, index|
"#{pk} = $#{index + 1}" "#{key} = $#{index + 1}"
end.join " AND " end.join " AND "
@_memo_query = <<~QUERY @sync_query = <<~QUERY
SELECT * FROM #{@table_name} SELECT * FROM #{@table_name}
WHERE #{selector} WHERE #{selector}
LIMIT 1 LIMIT 1;
QUERY QUERY
end end
@ -139,6 +172,8 @@ module LPGAR
end end
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
private
# Check if Record is properly set up. # Check if Record is properly set up.
# @raise [StandardError] rasied if class is not properly set up # @raise [StandardError] rasied if class is not properly set up
def check_instantiable def check_instantiable
@ -166,7 +201,7 @@ module LPGAR
end end
# Create a new record by "INSERT" # Create a new record by "INSERT"
def create(record) def insert_query(record)
recbody = record.instance_variable_get("@data") recbody = record.instance_variable_get("@data")
# @sg-ignore # @sg-ignore
conn.exec(<<~QUERY, recbody.values) conn.exec(<<~QUERY, recbody.values)
@ -336,7 +371,7 @@ module LPGAR
@conn = conn @conn = conn
@instances = {} @instances = {}
end end
new_class.class_exec(&block) new_class.class_exec(&block) if block
new_class new_class
end end

View File

@ -2,7 +2,7 @@
Gem::Specification.new do |spec| Gem::Specification.new do |spec|
spec.name = "lpgar" spec.name = "lpgar"
spec.version = "0.1" spec.version = "0.2"
spec.summary = "Lightweight Postgres Active Record" spec.summary = "Lightweight Postgres Active Record"
spec.description = <<~DESC spec.description = <<~DESC
Lightweight implementation of Active Record pattern for Postgres. Lightweight implementation of Active Record pattern for Postgres.