Created
October 23, 2020 10:23
-
-
Save estum/04cd73efc353017e5cbd9ba00b5d1363 to your computer and use it in GitHub Desktop.
ActiveRecord's Insert Statement Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require "dry-initializer" | |
# Simply generates insert statement with optional overridings. | |
# === Usage: | |
# | |
# like = Like.last | |
# # => #<Like:0x00007f8a42b07858> { | |
# # :id => "f93c47dc-9e09-4bf4-bbcb-2ec2000a873f", | |
# # :post_id => "e70059b5-983c-4fb6-9aba-b5462c0192d4", | |
# # :user_id => 34, | |
# # :deleted_at => nil, | |
# # :created_at => Tue, 10 Dec 2019 17:30:45 MSK +03:00, | |
# # :updated_at => Tue, 10 Dec 2019 17:30:45 MSK +03:00 | |
# # } | |
# puts InsertStatementGenerator[like, user_id: 1] | |
# # => INSERT INTO "likes" ("id", "post_id", "user_id", "deleted_at", "created_at", "updated_at") | |
# # VALUES ('f93c47dc-9e09-4bf4-bbcb-2ec2000a873f', 'e70059b5-983c-4fb6-9aba-b5462c0192d4', 1, NULL, '2019-12-10 14:30:45.348052', '2019-12-10 14:30:45.348052') | |
class InsertStatementGenerator | |
extend Dry::Initializer | |
class << self | |
# :call-seq: | |
# InsertStatementGenerator[record, **override] → String | |
# InsertStatementGenerator.(record, **override) → String | |
# InsertStatementGenerator.call(record, **override) → String | |
# | |
# Generates a finel SQL +INSERT+ statement for the given record | |
# and overrided values. | |
def call(record, **override) | |
new(record, override).to_sql | |
end | |
alias_method :[], :call | |
end | |
param :record, Types.Instance(ActiveRecord::Base) | |
param :override, optional: true, default: -> { {} } | |
# Returns Arel::InsertManager with a final statement | |
def manager | |
arel_table.compile_insert(values_for_insert) | |
end | |
# Returns a final SQL statement | |
delegate :to_sql, to: :manager | |
# Generates an associative array of column-value pairs with overrided values | |
def values_for_insert | |
record_attributes.map { |col, val| column_value(col, val) } | |
end | |
# Invokes +attributes_with_values_for_create+ for the record with it's attribute names | |
def record_attributes | |
record.send(:attributes_with_values_for_create, record.attribute_names) | |
end | |
private | |
# Returns a single column-value pair with overrided value. | |
def column_value(name, value) | |
arel = arel_attribute(name) | |
value = @override.fetch(name.to_sym, value) | |
[arel, type_cast(arel, value)] | |
end | |
# Type casts value for a given column | |
def type_cast(arel_attr, value) | |
arel_attr.type_cast_for_database(value) | |
end | |
delegate :arel_table, :arel_attribute, to: "record.class" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment