Skip to content

Instantly share code, notes, and snippets.

@rodloboz
Created February 12, 2020 20:02
Show Gist options
  • Select an option

  • Save rodloboz/6b918f977291f90f8c53b011bdc9f3c1 to your computer and use it in GitHub Desktop.

Select an option

Save rodloboz/6b918f977291f90f8c53b011bdc9f3c1 to your computer and use it in GitHub Desktop.
class Record
def initialize(attributes)
initialize_accessors
assign_attributes(attributes)
end
def self.attr_accessor(*vars)
@attributes ||= []
@attributes.concat vars
super(*vars)
end
# Class Methods:
class << self
attr_reader :attributes
def create(attributes = {})
new(attributes).save
end
# Read
def find(id)
result = DB.execute("SELECT * FROM #{table_name} WHERE id = ?", id).first
result.nil? ? nil : build_record(result)
end
def all
rows = DB.execute("SELECT * FROM #{table_name}")
return [] if rows.empty?
rows.map { |row| build_record(row) }
end
def last
all.last
end
def first
all.first
end
private
def build_record(row)
new(row.transform_keys!(&:to_sym))
end
def table_columns
DB.execute("PRAGMA table_info(#{table_name})").map { |a| a[1].to_sym }
end
def table_name
to_s.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase + 's'
end
end
def attributes
self.class.attributes
end
def update(attributes = {})
attributes.delete(:id)
assign_attributes(attributes)
save
end
# Saves the attributes to the DB table
# Called on #create and #update
def save
if @id.nil?
# 1. Create
DB.execute(build_insert_query)
@id = DB.last_insert_row_id
else
# 2. Update
DB.execute(build_update_query, *row_values)
end
end
# Destroy
def destroy
DB.execute("DELETE FROM #{table_name} WHERE id = ?", @id)
nil
end
# Assigns the values in the attributes hash
# into instance variable with the respective attributes key
# on #new, #create, #save, and #update
def assign_attributes(attributes)
attributes.each do |key, value|
instance_variable_set("@#{key}", value)
end
end
private
def build_insert_query
"INSERT INTO #{table_name} (#{row_headers.join(',')}) "\
"VALUES (#{row_values.map { |v| cast(v) }.join(',')})"
end
def build_update_query
"UPDATE #{table_name} SET #{update_statement} WHERE id = #{@id}"
end
# Creates an attr_accessor for each table column
#
# Given a Posts table with :id, :title and :content,
# it creates attr_accessor :id, :title, :content
def initialize_accessors
self.class.__send__(:attr_accessor, *self.class.__send__(:table_columns))
# self.class.table_columns.each { |c| self.class.__send__(:attr_accessor, c) }
end
def row_headers
attributes.reject { |attr| attr == :id }.uniq
end
def row_values
row_headers.map { |attr| send(attr) }
end
def update_statement
row_headers.map { |attr| "#{attr} = ?" }.join(',')
end
def table_name
self.class.__send__(:table_name)
end
def cast(value)
case value.class.to_s
when "String" then "'#{value}'"
when "TrueClass" then "1"
when "FalseClass" then "2"
when "NilClass" then"NULL"
else
value.to_s
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment