Add where_object query to PaperTrail::Version.
This commit is contained in:
parent
3a237d1bd1
commit
703ec9ae88
|
@ -12,6 +12,25 @@ module PaperTrail
|
|||
def dump(object)
|
||||
ActiveSupport::JSON.encode object
|
||||
end
|
||||
|
||||
# Returns a SQL condition to be used to match the given field and value in
|
||||
# the serialized object.
|
||||
def where_object_condition(arel_field, field, value)
|
||||
# Convert to JSON to handle strings and nulls correctly.
|
||||
json_value = value.to_json
|
||||
|
||||
# If the value is a number, we need to ensure that we find the next
|
||||
# character too, which is either `,` or `}`, to ensure that searching
|
||||
# for the value 12 doesn't yield false positives when the value is
|
||||
# 123.
|
||||
if value.is_a? Numeric
|
||||
arel_field.matches("%\"#{field}\":#{json_value},%").
|
||||
or(
|
||||
arel_field.matches("%\"#{field}\":#{json_value}}%"))
|
||||
else
|
||||
arel_field.matches("%\"#{field}\":#{json_value}%")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,12 @@ module PaperTrail
|
|||
def dump(object)
|
||||
::YAML.dump object
|
||||
end
|
||||
|
||||
# Returns a SQL condition to be used to match the given field and value in
|
||||
# the serialized object.
|
||||
def where_object_condition(arel_field, field, value)
|
||||
arel_field.matches("%\n#{field}: #{value}\n%")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -68,6 +68,20 @@ module PaperTrail
|
|||
end
|
||||
end
|
||||
|
||||
# Performs an attribute search on the serialized object by invoking the
|
||||
# identically-named method in the serializer being used.
|
||||
def where_object(**args)
|
||||
arel_field = arel_table[:object]
|
||||
|
||||
where_conditions = args.map do |field, value|
|
||||
PaperTrail.serializer.where_object_condition(arel_field, field, value)
|
||||
end.reduce do |condition1, condition2|
|
||||
condition1.and(condition2)
|
||||
end
|
||||
|
||||
where(where_conditions)
|
||||
end
|
||||
|
||||
def primary_key_is_int?
|
||||
@primary_key_is_int ||= columns_hash[primary_key].type == :integer
|
||||
rescue
|
||||
|
@ -190,7 +204,7 @@ module PaperTrail
|
|||
|
||||
def index
|
||||
table = self.class.arel_table unless @index
|
||||
@index ||=
|
||||
@index ||=
|
||||
if self.class.primary_key_is_int?
|
||||
sibling_versions.select(table[self.class.primary_key]).order(table[self.class.primary_key].asc).index(self)
|
||||
else
|
||||
|
|
|
@ -11,6 +11,7 @@ end
|
|||
|
||||
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
||||
require "rails/test_help"
|
||||
require 'minitest/mock'
|
||||
require 'shoulda'
|
||||
require 'ffaker'
|
||||
require 'database_cleaner' if using_mysql?
|
||||
|
|
|
@ -37,4 +37,37 @@ class JSONTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
context '`where_object` class method' do
|
||||
context "when value is a string" do
|
||||
should 'construct correct WHERE query' do
|
||||
sql = PaperTrail::Serializers::JSON.where_object_condition(
|
||||
PaperTrail::Version.arel_table[:object], :arg1, "Val 1").
|
||||
to_sql
|
||||
|
||||
assert sql.include?("LIKE '%\"arg1\":\"Val 1\"%'")
|
||||
end
|
||||
end
|
||||
|
||||
context "when value is `null`" do
|
||||
should 'construct correct WHERE query' do
|
||||
sql = PaperTrail::Serializers::JSON.where_object_condition(
|
||||
PaperTrail::Version.arel_table[:object], :arg1, nil).
|
||||
to_sql
|
||||
|
||||
assert sql.include?("LIKE '%\"arg1\":null%'")
|
||||
end
|
||||
end
|
||||
|
||||
context "when value is a number" do
|
||||
should 'construct correct WHERE query' do
|
||||
sql = PaperTrail::Serializers::JSON.where_object_condition(
|
||||
PaperTrail::Version.arel_table[:object], :arg1, -3.5).
|
||||
to_sql
|
||||
|
||||
assert_equal sql,
|
||||
"(\"versions\".\"object\" LIKE '%\"arg1\":-3.5,%' OR "\
|
||||
"\"versions\".\"object\" LIKE '%\"arg1\":-3.5}%')"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,4 +37,12 @@ class YamlTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
context '`where_object` class method' do
|
||||
should 'construct correct WHERE query' do
|
||||
sql = PaperTrail::Serializers::YAML.where_object_condition(
|
||||
PaperTrail::Version.arel_table[:object], :arg1, "Val 1").
|
||||
to_sql
|
||||
assert sql.include?("LIKE '%\narg1: Val 1\n%'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -98,4 +98,34 @@ class PaperTrail::VersionTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "PaperTrail::Version.where_object" do
|
||||
should "call `where_object` on the serializer" do
|
||||
# Create some args to fake-query on.
|
||||
args = { a: 1, b: "2", c: false, d: nil }
|
||||
arel_field = PaperTrail::Version.arel_table[:object]
|
||||
|
||||
# Create a dummy value for us to return for each condition that can be
|
||||
# chained together with other conditions with Arel's `and`.
|
||||
chainable_dummy = arel_field.matches("")
|
||||
|
||||
# Mock a serializer to expect to receive `where_object_condition` with the
|
||||
# correct args.
|
||||
serializer = MiniTest::Mock.new
|
||||
serializer.expect :where_object_condition, chainable_dummy, [arel_field, :a, 1]
|
||||
serializer.expect :where_object_condition, chainable_dummy, [arel_field, :b, "2"]
|
||||
serializer.expect :where_object_condition, chainable_dummy, [arel_field, :c, false]
|
||||
serializer.expect :where_object_condition, chainable_dummy, [arel_field, :d, nil]
|
||||
|
||||
# Stub out PaperTrail.serializer to return our mock, and then make the
|
||||
# query call.
|
||||
PaperTrail.stub :serializer, serializer do
|
||||
PaperTrail::Version.where_object(**args)
|
||||
end
|
||||
|
||||
# Verify that our serializer mock received the correct
|
||||
# `where_object_condition` calls.
|
||||
assert serializer.verify
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue