このコミットが含まれているのは:
2026-10-28 19:28:11 +09:00
コミット 8ea3d211dc
49個のファイルの変更、967行の追加、356行の削除
+54 -13
ファイルの表示
@@ -33,12 +33,13 @@ class CountsCondition
multiple: prefix.present? || field[:children].present?,
collection: field[:children].present? || type == :interval,
operators: CountsResourceDefinition::OPERATORS.fetch(type) }
entry[:label_values] = field[:label_values] if field[:label_values]
result.reject! { _1[:key] == key }
result << entry
visit.call(field[:children] || [], key, path_labels)
end
end
visit.call(definition.output_fields, nil, [])
visit.call(definition.condition_fields, nil, [])
# The raw JSON alias has the same membership semantics as the public tag field.
if definition.resource == 'posts'
result.find { _1[:key] == 'tags_json' }.merge!(type: :string, multiple: true, collection: true,
@@ -75,7 +76,6 @@ class CountsCondition
@population = population
@definition = population.definition
@connection = @definition.model.connection
@language = Locale.find_by!(code: population.params.fetch('locale', 'ja')).language_code
end
def apply(scope, entry)
@@ -149,6 +149,25 @@ class CountsCondition
scope.where(predicate, *binds)
end
def tag_name_match(value)
source = post_tag_source
bound = @population.history ? 'v.created_at' : @connection.quote(point)
source += ' LEFT JOIN nico_tag_versions external_snapshot ON external_snapshot.tag_id = ' +
scalar('tag_snapshot.item', 'external_tag_id', :integer) +
" AND external_snapshot.created_at <= #{ bound } AND " +
@population.access_sql(NicoTagVersion, 'external_snapshot') +
' AND NOT EXISTS (SELECT 1 FROM nico_tag_versions newer_external ' +
'WHERE newer_external.tag_id = external_snapshot.tag_id ' +
"AND newer_external.created_at <= #{ bound } " +
'AND newer_external.version_no > external_snapshot.version_no)'
document = "JSON_MERGE_PRESERVE(JSON_ARRAY(#{ scalar('tag_snapshot.item', 'name') }, " +
"referenced_tag.name, CONCAT('nico:', external_snapshot.name)), " +
"COALESCE(JSON_EXTRACT(referenced_tag.names, '$**.name'), JSON_ARRAY()))"
source += ' JOIN ' + json_table(document, '$[*]', 'search_name')
@definition.model.sanitize_sql_array([
"EXISTS (SELECT 1 FROM #{ source } WHERE JSON_UNQUOTE(search_name.item) = ?)", value])
end
private
def set_condition(scope, entry, field)
@@ -268,10 +287,10 @@ class CountsCondition
@population.timestamp(@population.params['at']) || @population.at
end
def name_expression(row)
language_path = @connection.quote("$.#{ @language.to_json }.name")
name = "JSON_UNQUOTE(JSON_EXTRACT(#{ row }.names, #{ language_path }))"
"COALESCE(#{ name }, #{ row }.name)"
def name_source(row, name)
document = "JSON_MERGE_PRESERVE(JSON_ARRAY(#{ row }.name), " +
"COALESCE(JSON_EXTRACT(#{ row }.names, '$.*.name'), JSON_ARRAY()))"
[json_table(document, '$[*]', name), "JSON_UNQUOTE(#{ name }.item)"]
end
def parent_source
@@ -282,7 +301,7 @@ class CountsCondition
id = 'CAST(parent_entry.item AS UNSIGNED)'
return [source, id] if @definition.resource == 'posts'
bound = @connection.quote(point)
bound = @population.history ? 'v.created_at' : @connection.quote(point)
source += ' LEFT JOIN tag_versions parent_version ON parent_version.tag_id = ' + id +
" AND parent_version.created_at <= #{ bound } AND " +
@population.access_sql(TagVersion, 'parent_version') +
@@ -298,7 +317,8 @@ class CountsCondition
source += ' LEFT JOIN tag_versions referenced_tag ON referenced_tag.tag_id = ' +
scalar('tag_snapshot.item', 'tag_id', :integer) +
' AND referenced_tag.version_no = ' + scalar('tag_snapshot.item', 'version_no', :integer) +
" AND referenced_tag.created_at <= #{ @connection.quote(point) } AND " +
" AND referenced_tag.created_at <= #{ @population.history ? 'v.created_at' :
@connection.quote(point) } AND " +
@population.access_sql(TagVersion, 'referenced_tag')
source
end
@@ -323,6 +343,9 @@ class CountsCondition
def source_for(key)
root, *parts = key.split('.')
if @definition.resource == 'tags' && @definition.name_column(root)
return [nil, @definition.name_expression(root)]
end
return [nil, "(#{ @population.latest_sql })"] if root == 'latest'
if root == 'user' && parts.any?
expression = parts.first == 'id' ? 'v.created_by_user_id' :
@@ -333,7 +356,17 @@ class CountsCondition
return [nil, 'v.deprecated_at'] if root == 'deprecated'
if root == 'parents'
source, id = parent_source
return [source, parts.first == 'name' ? name_expression('parent_version') : id]
if @definition.resource == 'tags' && @definition.name_column(parts.first)
return [source, @definition.name_expression(parts.first, 'parent_version')]
end
if parts.first == 'names'
names, document, language = names_source('parent_version.names', 'parent_language')
return language_field("#{ source } JOIN #{ names }", document, parts.drop(1), language)
end
return [source, id] unless parts.first == 'name'
names, value = name_source('parent_version', 'parent_name')
return ["#{ source } JOIN #{ names }", value]
end
if root == 'tags' || root == 'tags_json'
return post_field(parts)
@@ -360,7 +393,7 @@ class CountsCondition
source, value, profile = names_source('v.export_paths_json', 'export_profile')
return [source, parts.first == 'profile' ? profile : "JSON_UNQUOTE(#{ value })"]
end
return [nil, name_expression('v')] if root == 'name' && @definition.resource == 'tags'
return name_source('v', 'recorded_name') if root == 'name' && @definition.resource == 'tags'
[nil, @definition.expression(root)]
end
@@ -368,10 +401,14 @@ class CountsCondition
def post_field(parts)
source = post_tag_source
document = 'tag_snapshot.item'
if @definition.name_column(parts.first)
return [source, @definition.name_expression(parts.first, 'referenced_tag')]
end
case parts.first
when 'names'
when 'names', 'aliases'
names, entry, language = names_source('referenced_tag.names', 'tag_language')
language_field("#{ source } JOIN #{ names }", entry, parts.drop(1), language)
fields = parts.first == 'aliases' ? ['aliases', *parts.drop(1)] : parts.drop(1)
language_field("#{ source } JOIN #{ names }", entry, fields, language)
when 'sections'
sections = "JSON_EXTRACT(#{ document }, '$.sections')"
source += ' JOIN ' + json_table(sections, '$[*]', 'section_entry')
@@ -386,7 +423,11 @@ class CountsCondition
when 'category'
[source, "COALESCE(#{ scalar(document, 'category') }, referenced_tag.category)"]
else
[source, "COALESCE(#{ scalar(document, 'name') }, referenced_tag.name)"]
names = "JSON_MERGE_PRESERVE(JSON_ARRAY(#{ scalar(document, 'name') }, " +
'referenced_tag.name), ' +
"COALESCE(JSON_EXTRACT(referenced_tag.names, '$.*.name'), JSON_ARRAY()))"
["#{ source } JOIN #{ json_table(names, '$[*]', 'recorded_name') }",
'JSON_UNQUOTE(recorded_name.item)']
end
end