Skip to content
This repository was archived by the owner on Jul 14, 2025. It is now read-only.

Commit 12a26cc

Browse files
authored
FEATURE: Add tag group entity support to query results (#380)
The data explorer has special logic (“Automatic Entity Resolution”) to show links to various objects whenever a column name is `user_id`, `group_id`, `topic_id`, `category_id` or `badge_id`. This commit adds the support for `tag_group_id`
1 parent d60c7ac commit 12a26cc

File tree

5 files changed

+49
-3
lines changed

5 files changed

+49
-3
lines changed

assets/javascripts/discourse/components/query-result.gjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import HtmlViewComponent from "./result-types/html";
1919
import JsonViewComponent from "./result-types/json";
2020
import PostViewComponent from "./result-types/post";
2121
import ReltimeViewComponent from "./result-types/reltime";
22+
import TagGroupViewComponent from "./result-types/tag-group";
2223
import TextViewComponent from "./result-types/text";
2324
import TopicViewComponent from "./result-types/topic";
2425
import UrlViewComponent from "./result-types/url";
@@ -36,6 +37,7 @@ const VIEW_COMPONENTS = {
3637
html: HtmlViewComponent,
3738
json: JsonViewComponent,
3839
category: CategoryViewComponent,
40+
tag_group: TagGroupViewComponent,
3941
};
4042

4143
export default class QueryResult extends Component {
@@ -146,6 +148,10 @@ export default class QueryResult extends Component {
146148
return transformedRelTable(this.args.content.relations.topic);
147149
}
148150

151+
get transformedTagGroupTable() {
152+
return transformedRelTable(this.args.content.relations.tag_group);
153+
}
154+
149155
get transformedGroupTable() {
150156
return transformedRelTable(this.site.groups);
151157
}
@@ -203,6 +209,10 @@ export default class QueryResult extends Component {
203209
return this.transformedTopicTable[id];
204210
}
205211

212+
lookupTagGroup(id) {
213+
return this.transformedTagGroupTable[id];
214+
}
215+
206216
lookupGroup(id) {
207217
return this.transformedGroupTable[id];
208218
}
@@ -368,11 +378,13 @@ export default class QueryResult extends Component {
368378
@lookupBadge={{this.lookupBadge}}
369379
@lookupPost={{this.lookupPost}}
370380
@lookupTopic={{this.lookupTopic}}
381+
@lookupTagGroup={{this.lookupTagGroup}}
371382
@lookupGroup={{this.lookupGroup}}
372383
@lookupCategory={{this.lookupCategory}}
373384
@transformedPostTable={{this.transformedPostTable}}
374385
@transformedBadgeTable={{this.transformedBadgeTable}}
375386
@transformedUserTable={{this.transformedUserTable}}
387+
@transformedTagGroupTable={{this.transformedTagGroupTable}}
376388
@transformedGroupTable={{this.transformedGroupTable}}
377389
@transformedTopicTable={{this.transformedTopicTable}}
378390
@site={{this.site}}

assets/javascripts/discourse/components/query-row-content.gjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Component from "@glimmer/component";
22
import { cached } from "@glimmer/tracking";
3-
import { capitalize } from "@ember/string";
3+
import { classify } from "@ember/string";
44
import getURL from "discourse/lib/get-url";
55
import { escapeExpression } from "discourse/lib/utilities";
66
import TextViewComponent from "./result-types/text";
@@ -31,7 +31,7 @@ export default class QueryRowContent extends Component {
3131
}
3232

3333
const lookupFunc =
34-
this.args[`lookup${capitalize(componentDefinition.name)}`];
34+
this.args[`lookup${classify(componentDefinition.name)}`];
3535
if (lookupFunc) {
3636
ctx[componentDefinition.name] = lookupFunc.call(this.args, id);
3737
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const Group = <template>
2+
{{#if @ctx.tag_group}}
3+
<a
4+
href="{{@ctx.baseuri}}/tag_groups/{{@ctx.id}}"
5+
>{{@ctx.tag_group.name}}</a>
6+
{{else}}
7+
{{@ctx.id}}
8+
{{/if}}
9+
</template>;
10+
11+
export default Group;

lib/discourse_data_explorer/data_explorer.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ def self.extra_data_pluck_fields
118118
fields: %i[id title slug posts_count locale],
119119
serializer: BasicTopicSerializer,
120120
},
121+
tag_group: {
122+
class: TagGroup,
123+
fields: %i[id name],
124+
only: %i[id name],
125+
},
121126
group: {
122127
class: Group,
123128
ignore: true,
@@ -141,7 +146,7 @@ def self.extra_data_pluck_fields
141146
def self.column_regexes
142147
@column_regexes ||=
143148
extra_data_pluck_fields
144-
.map { |key, val| /(#{val[:class].to_s.downcase})_id$/ if val[:class] }
149+
.map { |key, val| /(#{val[:class].to_s.underscore})_id$/ if val[:class] }
145150
.compact
146151
end
147152

@@ -196,6 +201,7 @@ def self.add_extra_data(pg_result)
196201
ret[cls] = ActiveModel::ArraySerializer.new(
197202
all_objs,
198203
each_serializer: support_info[:serializer],
204+
only: support_info[:only],
199205
)
200206
end
201207
[ret, col_map]

spec/data_explorer_spec.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,23 @@
101101
records.map { |t| BasicTopicSerializer.new(t, root: false).as_json }
102102
}.not_to raise_error
103103
end
104+
105+
it "chooses the correct serializer for tag_group" do
106+
tag_group = Fabricate(:tag_group)
107+
tag1 = Fabricate(:tag)
108+
tag2 = Fabricate(:tag)
109+
tag_group.tags = [tag1, tag2]
110+
111+
query = Fabricate(:query, sql: "SELECT tag_id, tag_group_id FROM tag_group_memberships")
112+
113+
pg_result = described_class.run_query(query)[:pg_result]
114+
relations, colrender = DiscourseDataExplorer::DataExplorer.add_extra_data(pg_result)
115+
116+
expect(colrender).to eq({ 1 => :tag_group })
117+
expect(relations[:tag_group].as_json).to include(
118+
{ "id" => tag_group.id, "name" => tag_group.name },
119+
)
120+
end
104121
end
105122
end
106123
end

0 commit comments

Comments
 (0)