Implement metadata model concern [SCI-11774]

This commit is contained in:
Martin Artnik 2025-04-09 11:38:38 +02:00
parent a274ffce7e
commit 65b94afafa
3 changed files with 79 additions and 0 deletions

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
module MetadataModel
extend ActiveSupport::Concern
included do
scope :with_metadata_value, lambda { |key, value|
# sanitize key, replace . with -> and replace last -> with ->> to ensure string comparison at last level
db_key =
"metadata->#{key.to_s.split('.').map { |k| "'#{k.parameterize(separator: '_')}'" }.join('->')}".sub(/->(?!.*->)/, '->>')
where("#{db_key} = ?", value.to_s)
}
before_save :sanitize_metadata_keys!
def sanitize_metadata_keys!
return unless metadata
self.metadata = metadata.deep_transform_keys { |k| k.parameterize(separator: '_') }
end
end
end

View file

@ -11,6 +11,7 @@ class Project < ApplicationRecord
include ViewableModel
include PermissionCheckableModel
include Assignable
include MetadataModel
enum visibility: { hidden: 0, visible: 1 }

View file

@ -0,0 +1,56 @@
# frozen_string_literal: true
require 'rails_helper'
describe MetadataModel, type: :concern do
let!(:user) { create :user }
let!(:team) { create :team, created_by: user }
let!(:project_1) do
Project.create!(
name: 'Project 1',
team: user.teams.first,
created_by: user,
metadata: {
status: 'processed',
info: {
tag: 'important',
number: 2
}
}
)
end
let!(:project_2) do
Project.create!(
name: 'Project 2',
team: user.teams.first,
created_by: user,
metadata: {
status: 'failed'
}
)
end
it '#with_metadata_value finds the correct project by metadata value' do
results = Project.with_metadata_value(:status, 'processed')
expect(results.count).to eq 1
expect(results.last.id).to eq project_1.id
end
it '#with_metadata_value finds the correct project by nested metadata value' do
results = Project.with_metadata_value('info.tag', 'important')
expect(results.count).to eq 1
expect(results.last.id).to eq project_1.id
results = Project.with_metadata_value('info.number', 2)
expect(results.count).to eq 1
expect(results.last.id).to eq project_1.id
end
it '#with_metadata_value escapes key input' do
results = nil
expect { results = Project.with_metadata_value("project'->>'tag' = \'one\') AND name", nil) }.to_not raise_error
expect(results.count).to eq 0
end
end