Skip to content

Commit

Permalink
Support nested json
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkamel committed Jan 31, 2024
1 parent 85b1031 commit 534219f
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 12 deletions.
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
- MYSQL_ROOT_PASSWORD=
- MYSQL_DATABASE=search_cop
ports:
- 3306:3306
postgres:
Expand Down
2 changes: 1 addition & 1 deletion lib/search_cop/visitors/mysql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Mysql
# rubocop:disable Naming/MethodName

def visit_SearchCopGrammar_Attributes_Json(attribute)
"#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}->#{quote "$.#{attribute.field_name}"}"
"#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}->#{quote "$.#{attribute.field_names.join(".")}"}"
end

class FulltextQuery < Visitor
Expand Down
10 changes: 7 additions & 3 deletions lib/search_cop/visitors/postgres.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ module Postgres
# rubocop:disable Naming/MethodName

def visit_SearchCopGrammar_Attributes_Json(attribute)
"#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}->>#{quote attribute.field_name}"
elements = ["#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}", *attribute.field_names.map { |field_name| quote(field_name) }]

"#{elements[0...-1].join("->")}->>#{elements.last}"
end

def visit_SearchCopGrammar_Attributes_Jsonb(attribute)
"#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}->>#{quote attribute.field_name}"
elements = ["#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}", *attribute.field_names.map { |field_name| quote(field_name) }]

"#{elements[0...-1].join("->")}->>#{elements.last}"
end

def visit_SearchCopGrammar_Attributes_Hstore(attribute)
"#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}->#{quote attribute.field_name}"
"#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}->#{quote attribute.field_names.first}"
end

class FulltextQuery < Visitor
Expand Down
12 changes: 6 additions & 6 deletions lib/search_cop_grammar/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ def alias_for(name)
def attribute_for(attribute_definition)
query_info.references.push attribute_definition

table, column_with_field = attribute_definition.split(".")
column, field = column_with_field.split("->")
table, column_with_fields = attribute_definition.split(".")
column, *fields = column_with_fields.split("->")
klass = klass_for(table)

raise(SearchCop::UnknownAttribute, "Unknown attribute #{attribute_definition}") unless klass.columns_hash[column]

Attributes.const_get(klass.columns_hash[column].type.to_s.classify).new(klass, alias_for(table), column, field, options)
Attributes.const_get(klass.columns_hash[column].type.to_s.classify).new(klass, alias_for(table), column, fields, options)
end

def generator_for(name)
Expand All @@ -111,14 +111,14 @@ def generators
end

class Base
attr_reader :attribute, :table_alias, :column_name, :field_name, :options
attr_reader :attribute, :table_alias, :column_name, :field_names, :options

def initialize(klass, table_alias, column_name, field_name, options = {})
def initialize(klass, table_alias, column_name, field_names, options = {})
@attribute = klass.arel_table.alias(table_alias)[column_name]
@klass = klass
@table_alias = table_alias
@column_name = column_name
@field_name = field_name
@field_names = field_names
@options = (options || {})
end

Expand Down
18 changes: 18 additions & 0 deletions test/string_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ def test_jsonb
refute_includes Product.search("jsonb_name: rejected"), product
end

def test_nested_jsonb
return if DATABASE != "postgres"

product = create(:product, nested_jsonb: { nested: { name: "expected" } })

assert_includes Product.search("nested_jsonb_name: expected"), product
refute_includes Product.search("nested_jsonb_name: rejected"), product
end

def test_json
return if DATABASE != "postgres" && DATABASE != "mysql"

Expand All @@ -158,6 +167,15 @@ def test_json
refute_includes Product.search("json_name: rejected"), product
end

def test_nested_json
return if DATABASE != "postgres" && DATABASE != "mysql"

product = create(:product, nested_json: { nested: { name: "expected" } })

assert_includes Product.search("nested_json_name: expected"), product
refute_includes Product.search("nested_json_name: rejected"), product
end

def test_hstore
return if DATABASE != "postgres"

Expand Down
7 changes: 5 additions & 2 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ class Product < ActiveRecord::Base
end

if DATABASE == "postgres"
attributes json_name: "json->name", jsonb_name: "jsonb->name", hstore_name: "hstore->name"
attributes nested_json_name: "nested_json->nested->name", nested_jsonb_name: "nested_jsonb->nested->name", json_name: "json->name", jsonb_name: "jsonb->name", hstore_name: "hstore->name"

options :title, dictionary: "english"
end

if DATABASE == "mysql"
attributes json_name: "json->name"
attributes nested_json_name: "nested_json->nested->name", json_name: "json->name"
end

generator :custom_eq do |column_name, raw_value|
Expand Down Expand Up @@ -137,12 +137,15 @@ class AvailableProduct < Product

if DATABASE == "postgres"
t.json :json
t.json :nested_json
t.jsonb :jsonb
t.jsonb :nested_jsonb
t.hstore :hstore
end

if DATABASE == "mysql"
t.json :json
t.json :nested_json
end
end

Expand Down

0 comments on commit 534219f

Please sign in to comment.