e03cc01109
#171 #171 #171 #171 #171 #171 #171 Co-authored-by: miteruzo <miteruzo@naver.com> Reviewed-on: #345
88 lines
2.3 KiB
Ruby
88 lines
2.3 KiB
Ruby
class VersionRecorder
|
|
EVENT_TYPES = ['create', 'update', 'discard', 'restore'].freeze
|
|
|
|
def initialize record:, event_type:, created_by_user:
|
|
@record = record
|
|
@event_type = event_type.to_s
|
|
@created_by_user = created_by_user
|
|
|
|
validate_event_type!
|
|
end
|
|
|
|
def record!
|
|
raise "#{ record_class.name } must be persisted" unless @record.persisted?
|
|
|
|
ApplicationRecord.transaction do
|
|
@record = record_class.unscoped.lock.find(@record.id)
|
|
latest = latest_version
|
|
|
|
validate_version_sequence!(latest)
|
|
|
|
attrs = snapshot_attributes
|
|
|
|
if @event_type == 'update' && latest && same_snapshot?(latest, attrs)
|
|
return latest
|
|
end
|
|
|
|
version = version_class.create!(
|
|
base_attributes(latest).merge(record_key => @record).merge(attrs))
|
|
|
|
update_record_version_no!(version.version_no)
|
|
|
|
version
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def latest_version = versions.order(version_no: :desc).first
|
|
|
|
def versions = @record.public_send(version_association)
|
|
|
|
def base_attributes latest
|
|
{ version_no: (latest&.version_no || 0) + 1,
|
|
event_type: @event_type,
|
|
created_at: Time.current,
|
|
created_by_user: @created_by_user }
|
|
end
|
|
|
|
def update_record_version_no! version_no
|
|
@record.update_columns(version_no:)
|
|
@record.version_no = version_no
|
|
end
|
|
|
|
def validate_version_sequence! latest
|
|
if !(latest) && @event_type != 'create'
|
|
raise "#{ version_class.name } first event must be create"
|
|
end
|
|
|
|
if @event_type == 'create' && latest
|
|
raise "#{ version_class.name } create event already exists"
|
|
end
|
|
|
|
return unless latest
|
|
|
|
if @record.version_no != latest.version_no
|
|
raise ("#{ record_class.name }##{ @record.id } version_no is #{ @record.version_no }, " +
|
|
"but latest #{ version_class.name } version_no is #{ latest.version_no }")
|
|
end
|
|
end
|
|
|
|
def same_snapshot? version, attrs
|
|
attrs.all? { |k, v| version.public_send(k) == v }
|
|
end
|
|
|
|
def validate_event_type!
|
|
return if EVENT_TYPES.include?(@event_type)
|
|
|
|
raise ArgumentError, "Invalid event_type: #{ @event_type }"
|
|
end
|
|
|
|
def version_class = raise NotImplementedError
|
|
def version_association = raise NotImplementedError
|
|
def record_key = raise NotImplementedError
|
|
def snapshot_attributes = raise NotImplementedError
|
|
|
|
def record_class = @record.class
|
|
end
|