Commit e6597f3a authored by Emmanuel Raviart's avatar Emmanuel Raviart
Browse files

Index CodeBook language & questions. Repair language of ADISP DDIs.

parent 33bbaf18
Pipeline #208791 failed with stage
in 2 minutes and 37 seconds
......@@ -52,30 +52,36 @@ npm run configure
### Fetching Nesstar Servers
```bash
npx tsc
# ADISP
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.js --url http://nesstar.progedo-adisp.fr/ ../public_data/adisp-ddi/
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.ts --url http://nesstar.progedo-adisp.fr/ ../public_data/adisp-ddi/
# CDSP Sciences Po
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.js --url http://nesstar.sciences-po.fr/ ../public_data/cdsp-ddi/
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.ts --url http://nesstar.sciences-po.fr/ ../public_data/cdsp-ddi/
# INED
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.js --url http://nesstar.ined.fr/ ../public_data/ined-ddi/
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.ts --url http://nesstar.ined.fr/ ../public_data/ined-ddi/
# INED - Generations and Gender Survey
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.js --url http://ggpsurvey.ined.fr/ ../public_data/ined-gpgsurvey-ddi/
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.ts --url http://ggpsurvey.ined.fr/ ../public_data/ined-gpgsurvey-ddi/
# UK Data Service
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.js --url http://nesstar.ukdataservice.ac.uk/ ../public_data/ukdataservice-ddi/
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.ts --url http://nesstar.ukdataservice.ac.uk/ ../public_data/ukdataservice-ddi/
# Norwegian Centre for Research Data
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.js --url http://nsddata.nsd.uib.no ../public_data/nsddata-ddi/
npx babel-node --extensions ".ts" src/scripts/retrieve_nesstar_ddis.ts --url http://nsddata.nsd.uib.no ../public_data/nsddata-ddi/
```
### Repairing DDI files
```bash
# ADISP
npx babel-node --extensions ".ts" src/scripts/repair_adisp_ddis.ts --source=../public_data/adisp-ddi/ ../public_data/adisp-ddi-repaired
```
### Indexing DDI files
```bash
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --path=adisp --title=\"Archives de données issues de la statistique publique \(ADISP\)\" ../public_data/adisp-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --path=cdsp --title=\"SciencesPo Centre de données socio-politiques \(CDSP\)\" ../public_data/cdsp-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --path=ined --title=\"Institut national d\'études démographiques \(INED\)\" ../public_data/ined-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --path=ined/gpgsurvey --title=\"Enquête Générations et Genre du projet international Generations and Gender Programme \(GGP\)\" ../public_data/ined-gpgsurvey-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --path=ukdataservice --title=\"UK Data Service\" ../public_data/ukdataservice-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --path=nsddata --title=\"Norwegian Centre for Research Data \(NSD\)\" ../public_data/nsddata-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --language=fr --path=adisp --title=\"Archives de données issues de la statistique publique \(ADISP\)\" ../public_data/adisp-ddi-repaired/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --language=fr --path=cdsp --title=\"SciencesPo Centre de données socio-politiques \(CDSP\)\" ../public_data/cdsp-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --language=fr --path=ined --title=\"Institut national d\'études démographiques \(INED\)\" ../public_data/ined-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --language=fr --path=ined/gpgsurvey --title=\"Enquête Générations et Genre du projet international Generations and Gender Programme \(GGP\)\" ../public_data/ined-gpgsurvey-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --language=en --path=ukdataservice --title=\"UK Data Service\" ../public_data/ukdataservice-ddi/
npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --language=no --path=nsddata --title=\"Norwegian Centre for Research Data \(NSD\)\" ../public_data/nsddata-ddi/
```
## Development
......@@ -85,7 +91,9 @@ npx babel-node --extensions ".ts" -- src/scripts/index_code_books.ts --path=nsdd
In `data-catalogue` directory:
```bash
npx babel-node --extensions ".ts" --max-old-space-size=10240 src/scripts/raw_types_from_ddi_files.ts ../public_data/adisp-ddi/ ../public_data/adisp-ddi/ ../public_data/ined-ddi/ --target=src/raw_types/code_books.ts
npx babel-node --extensions ".ts" --max-old-space-size=10240 src/scripts/raw_types_from_ddi_files.ts ../public_data/adisp-ddi/ ../public_data/adisp-ddi/ ../public_data/ined-ddi/
npx babel-node --extensions ".ts" --max-old-space-size=10240 -- src/scripts/raw_types_from_ddi_files.ts ../public_data/adisp-ddi/ ../public_data/adisp-ddi/ ../public_data/ined-ddi/ --version=1.2.2
npx babel-node --extensions ".ts" -- src/scripts/raw_types_from_ddi_files.ts ../public_data/adisp-ddi/ ../public_data/adisp-ddi/ ../public_data/ined-ddi/ --version=1.3
npx babel-node --extensions ".ts" --max-old-space-size=8192 src/scripts/raw_types_from_ddi_files.ts ../public_data/xml-ddi-adisp/ --target=src/raw_types/enquetes_adisp_fournies.ts
npx babel-node --extensions ".ts" --max-old-space-size=8192 src/scripts/raw_types_from_ddi_files.ts ../public_data/adisp-ddi/ --target=src/raw_types/enquetes_adisp.ts
npx babel-node --extensions ".ts" src/scripts/raw_types_from_ddi_files.ts ../public_data/cdsp-ddi/ --target=src/raw_types/enquetes_cdsp.ts
......
......@@ -2476,13 +2476,13 @@
}
},
"node_modules/call-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
"integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.1.tgz",
"integrity": "sha512-tvAvUwNcRikl3RVF20X9lsYmmepsovzTWeJiXjO0PkJp15uy/6xKFZOQtuiSULwYW+6ToZBprphCgWXC2dSgcQ==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.0"
"get-intrinsic": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
......@@ -6708,9 +6708,9 @@
}
},
"node_modules/postcss": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.3.tgz",
"integrity": "sha512-tdmNCCmxJEsLZNj810qlj8QbvnUNKFL9A5doV+uHrGGK/YNKWEslrytnHDWr9M/GgGjfUFwXCRbxd/b6IoRBXQ==",
"version": "8.2.4",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.4.tgz",
"integrity": "sha512-kRFftRoExRVXZlwUuay9iC824qmXPcQQVzAjbCCgjpXnkdMCJYBu2gTwAaFBzv8ewND6O8xFb3aELmEkh9zTzg==",
"dev": true,
"dependencies": {
"colorette": "^1.2.1",
......@@ -12829,13 +12829,13 @@
"dev": true
},
"call-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
"integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.1.tgz",
"integrity": "sha512-tvAvUwNcRikl3RVF20X9lsYmmepsovzTWeJiXjO0PkJp15uy/6xKFZOQtuiSULwYW+6ToZBprphCgWXC2dSgcQ==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.0"
"get-intrinsic": "^1.0.2"
}
},
"caller-callsite": {
......@@ -16148,9 +16148,9 @@
"dev": true
},
"postcss": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.3.tgz",
"integrity": "sha512-tdmNCCmxJEsLZNj810qlj8QbvnUNKFL9A5doV+uHrGGK/YNKWEslrytnHDWr9M/GgGjfUFwXCRbxd/b6IoRBXQ==",
"version": "8.2.4",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.4.tgz",
"integrity": "sha512-kRFftRoExRVXZlwUuay9iC824qmXPcQQVzAjbCCgjpXnkdMCJYBu2gTwAaFBzv8ewND6O8xFb3aELmEkh9zTzg==",
"dev": true,
"requires": {
"colorette": "^1.2.1",
......
......@@ -18,7 +18,7 @@ import {
cleanAudit,
} from "@auditors/core"
import { allFollows, NodeType } from "../data"
import { allFollows, Field, NodeType } from "../data"
export function auditNodeQuery(audit: Audit, data: any): [any, any] {
if (data == null) {
......@@ -44,6 +44,14 @@ export function auditNodeQuery(audit: Audit, data: any): [any, any] {
auditStringToBoolean,
auditSetNullish(false),
)
audit.attribute(
data,
"field",
true,
errors,
remainingKeys,
auditQueryOptionsArray(Object.values(Field)),
)
audit.attribute(
data,
"follow",
......
<script lang="ts">
import type { Node } from "../data"
import type { NodeCodeBook } from "../data"
import { localize } from "../stores"
export let node: Node
export let node: NodeCodeBook
$: _ = $localize
......@@ -11,24 +11,24 @@
$: keywords = codeBook?.stdyDscr?.stdyInfo.subject?.keyword
</script>
<h1 class="heading">{_(node.type)}{_('colon')} <i>{node.title}</i></h1>
<h1 class="heading">{_(node.type)}{_("colon")} <i>{node.title}</i></h1>
{#if codeBook != null}
<div class="mx-auto">
<!-- <h2 class="font-bold text-2xl">
{codeBook.stdyDscr.citation.titlStmt.titl}
</h2> -->
<p>{_('Version')}{_('colon')} {codeBook['@version']}</p>
<p>{_("Version")}{_("colon")} {codeBook["@version"]}</p>
<p>{codeBook.stdyDscr.stdyInfo.abstract}</p>
{#if keywords}
<p>
{_('Keywords')}{_('colon')}
{_("Keywords")}{_("colon")}
{#each keywords as keyword, index}
{#if index > 0}, {/if}{keyword}
{#if index > 0}, {/if}{keyword}
{/each}
</p>
{/if}
<p>{_('Version')}{_('colon')} {codeBook['@version']}</p>
<p>{_("Version")}{_("colon")} {codeBook["@version"]}</p>
<pre>{JSON.stringify(codeBook, null, 2)}</pre>
</div>
{/if}
......@@ -2,10 +2,11 @@
import { stores } from "@sapper/app"
import Pagination from "./Pagination.svelte"
import SearchForm from "./SearchForm.svelte"
import type { Node } from "../data"
import type { NodeGroup } from "../data"
import { NodeType } from "../data"
import { localize } from "../stores"
export let node: Node
export let node: NodeGroup
const { page } = stores()
......@@ -20,7 +21,7 @@
$: term = query.q
</script>
<h1 class="heading">{_(node.type)}{_('colon')} <i>{node.title}</i></h1>
<h1 class="heading">{_(node.type)}{_("colon")} <i>{node.title}</i></h1>
<div class="mx-auto">
<SearchForm placeholder="niveau de vie…" searchPath={$page.path} {term} />
......@@ -28,8 +29,13 @@
<ul>
{#each children as child}
<li>
<a class="button ~info !low" href={child.path}>{child.title}
({_(child.type)})</a>
<a class="button ~info !low" href={child.path}>
{#if child.type === NodeType.CodeBook}
{child.title} ({_(child.type)} {_("version")} {child.version})
{:else}
{child.title}
{/if}
</a>
</li>
{/each}
</ul>
......@@ -39,5 +45,6 @@
currentPageCount={children.length}
limit={20}
queryParams={query}
url={$page.path} />
url={$page.path}
/>
</div>
import assert from "assert"
import dedent from "dedent-js"
import { Node, NodeType } from "./data"
import { Language, NodeType } from "./data"
import { db, versionNumber } from "./database"
import { indexNode } from "./indexers"
import { indexGroup } from "./indexers"
export async function configure(): Promise<void> {
await configureDatabase()
const rootNode: Node = {
title: "Root",
await indexGroup({
path: "",
language: Language.En,
title: "Root",
type: NodeType.Group,
}
await indexNode(rootNode)
})
}
async function configureDatabase(): Promise<void> {
......@@ -49,6 +49,40 @@ async function configureDatabase(): Promise<void> {
// Types
// Enum: field
try {
await db.none(
dedent`
CREATE TYPE field AS ENUM (
'Question',
'Title'
)
`,
)
} catch (e) {
// 42710: type "field" already exists
if (e.code !== "42710") {
throw e
}
}
// Enum: language
try {
await db.none(
dedent`
CREATE TYPE language AS ENUM (
'en',
'fr'
)
`,
)
} catch (e) {
// 42710: type "language" already exists
if (e.code !== "42710") {
throw e
}
}
// Enum: node_type
try {
await db.none(
......@@ -60,29 +94,19 @@ async function configureDatabase(): Promise<void> {
`,
)
} catch (e) {
// 42710: type "chart_node_type" already exists
// 42710: type "node_type" already exists
if (e.code !== "42710") {
throw e
}
}
// Table: users
await db.none(
dedent`
CREATE TABLE IF NOT EXISTS users (
username text NOT NULL PRIMARY KEY,
email text NOT NULL
)
`,
)
// Tables
// Table: nodes
await db.none(
dedent`
CREATE TABLE IF NOT EXISTS nodes (
file_path text,
language language NOT NULL,
path text NOT NULL PRIMARY KEY,
title text NOT NULL,
type node_type NOT NULL
......@@ -90,13 +114,25 @@ async function configureDatabase(): Promise<void> {
`,
)
// Table: code_books
await db.none(
dedent`
CREATE TABLE IF NOT EXISTS code_books (
file_path text NOT NULL,
path text NOT NULL PRIMARY KEY REFERENCES nodes(path) ON DELETE CASCADE,
version text NOT NULL
)
`,
)
// Table: nodes_autocomplete
await db.none(
dedent`
CREATE TABLE IF NOT EXISTS nodes_autocomplete (
autocomplete text NOT NULL,
field field NOT NULL,
path text NOT NULL REFERENCES nodes(path) ON DELETE CASCADE,
PRIMARY KEY (path, autocomplete)
PRIMARY KEY (path, field, autocomplete)
)
`,
)
......@@ -113,6 +149,16 @@ async function configureDatabase(): Promise<void> {
`,
)
// Table: users
await db.none(
dedent`
CREATE TABLE IF NOT EXISTS users (
username text NOT NULL PRIMARY KEY,
email text NOT NULL
)
`,
)
// Apply patches that must be executed after every table is created.
// Add indexes once every table and column exists.
......@@ -127,9 +173,14 @@ async function configureDatabase(): Promise<void> {
// Add comments once every table and column exists.
for (const command of [
"COMMENT ON TABLE nodes IS 'nodes (of the tree of nodes'",
"COMMENT ON COLUMN nodes.file_path IS 'relative path of the file containing the" +
" data of the node'",
"COMMENT ON TABLE code_books IS 'additional informations for nodes of type CodeBook'",
"COMMENT ON COLUMN code_books.file_path IS 'relative path of the file containing the" +
" XML data of the CodeBook'",
"COMMENT ON COLUMN code_books.path IS 'path of node'",
"COMMENT ON COLUMN code_books.version IS 'version of CodeBook used'",
"COMMENT ON TABLE nodes IS 'nodes (of the tree of nodes)'",
"COMMENT ON COLUMN nodes.language IS 'language used for node'",
'COMMENT ON COLUMN nodes.path IS \'"/"-separated concatenation of' +
" the segments of the node and its ancestors'",
"COMMENT ON COLUMN nodes.title IS 'name of node'",
......@@ -137,6 +188,7 @@ async function configureDatabase(): Promise<void> {
"COMMENT ON TABLE nodes_autocomplete IS 'autocompletions texts for nodes'",
"COMMENT ON COLUMN nodes_autocomplete.autocomplete IS 'autocompletion text of node'",
"COMMENT ON COLUMN nodes_autocomplete.field IS 'field(s) used for autocompletion'",
"COMMENT ON COLUMN nodes_autocomplete.path IS 'path of node'",
"COMMENT ON TABLE version IS 'version of database'",
......
import type { CodeBook } from "./raw_types/code_books"
export enum CodeBookVersion {
Version_1_2_2 = "1.2.2",
Version_1_3 = "1.3",
}
export enum Field {
Question = "Question",
Title = "Title",
}
export enum Follow {
Node_children = "Node.children",
Node_codeBook = "Node.codeBook",
NodeCodeBook_codeBook = "NodeCodeBook.codeBook",
NodeGroup_children = "NodeGroup.children",
}
export const allFollows = Object.values(Follow)
......@@ -13,24 +23,42 @@ export interface JsonData {
path?: string
}
export interface Node {
children?: Node[]
childrenAutocompletion?: NodeAutocompletion[]
childrenCount?: number
codeBook?: CodeBook
file_path?: string
nextChildrenUrl?: string
path: string
title: string
type: NodeType
export enum Language {
En = "en",
Fr = "fr",
}
export type Node = NodeCodeBook | NodeGroup
export interface NodeAutocompletion {
autocomplete?: string
distance?: number
field: Field
path: string
}
export interface NodeBase {
language: Language
path: string
title: string
type: NodeType
}
export interface NodeCodeBook extends NodeBase {
codeBook?: CodeBook
file_path?: string // Required on server but removed for clients.
type: NodeType.CodeBook
version: CodeBookVersion
}
export interface NodeGroup extends NodeBase {
children?: Node[]
childrenAutocompletion?: NodeAutocompletion[]
childrenCount?: number
nextChildrenUrl?: string
type: NodeType.Group
}
export enum NodeType {
CodeBook = "CodeBook",
Group = "Group",
......@@ -44,6 +72,10 @@ export interface RetrievalError {
url: string
}
export function assertNeverNode(node: never): never {
throw new Error("Unexpected node: " + node)
}
export function assertNeverNodeType(type: never): never {
throw new Error("Unexpected node type: " + type)
}
import { assertNeverNodeType, Follow, JsonData, Node, NodeType } from "./data"
import { assertNeverNode, Follow, JsonData, Node, NodeType } from "./data"
import type { CodeBook } from "./raw_types/code_books"
function codeBookFromPath(
......@@ -25,14 +25,14 @@ function nodeFromPath(
switch (node.type) {
case NodeType.CodeBook:
if (follow.has(Follow.Node_codeBook) && node.codeBook == null) {
if (follow.has(Follow.NodeCodeBook_codeBook) && node.codeBook == null) {
node.codeBook = codeBookFromPath(json, follow, node.path)
}
break
case NodeType.Group:
if (
follow.has(Follow.Node_codeBook) &&
follow.has(Follow.NodeCodeBook_codeBook) &&
node.childrenAutocompletion != null &&
node.children == null
) {
......@@ -43,7 +43,7 @@ function nodeFromPath(
break
default:
assertNeverNodeType(node.type)
assertNeverNode(node)
}
return node
......
......@@ -4,23 +4,29 @@ import fs from "fs-extra"
import path from "path"
import {
assertNeverNode,
assertNeverNodeType,
Field,
Follow,
JsonData,
Node,
NodeAutocompletion,
NodeBase,
NodeCodeBook,
NodeGroup,
NodeType,
} from "./data"
import config from "./config"
import { db } from "./database"
import type { CodeBook } from "./raw_types/code_books"
import type { Request } from "./requests_responses"
import { newNodeFullUrl } from "./urls"
import { newNodeFullUrl } from "./server_urls"
const { publicDataDir } = config
export interface GroupOptions {
deep?: boolean
fields?: Field[]
follow: Set<Follow>
limit?: number
offset?: number
......@@ -36,29 +42,28 @@ export class DataProducer implements JsonData {
path?: string
requestedChildrenOptionsByPath = new Map<string, RequestOptions>()
requestedCodeBookFilePathByPath = new Map<string, string>()
requestedNodeCodeBooksPartOptionsByPath = new Map<string, RequestOptions>()
requestedNodesOptionsByPath = new Map<string, RequestOptions>()
constructor(public req: Request) {}
addCodeBook(codeBook: CodeBook, path: string): void {
addCodeBookData(codeBook: CodeBook, path: string): void {
this.codeBookByPath[path] = codeBook
}
addNode(node: Node, options: RequestOptions): void {
this.nodeByPath[node.path] = node
addNodeBase(node: NodeBase, options: RequestOptions): void {
this.nodeByPath[node.path] = node as Node
switch (node.type) {
case NodeType.CodeBook:
if (options.follow.has(Follow.Node_codeBook)) {
this.requestedCodeBookFilePathByPath.set(node.path, node.file_path!)
}
this.requestedNodeCodeBooksPartOptionsByPath.set(node.path, options)
break
case NodeType.Group:
if (options.follow.has(Follow.Node_children)) {
// Remove Follow.Node_codeBook for children, code books are too big.
if (options.follow.has(Follow.NodeGroup_children)) {
// Remove Follow.NodeCodeBook_codeBook for children, because code books are too big.
this.requestedChildrenOptionsByPath.set(
node.path,
removeUnfollowedFromOptions(options, Follow.Node_codeBook),
removeUnfollowedFromOptions(options, Follow.NodeCodeBook_codeBook),
)
}
break
......@@ -68,6 +73,18 @@ export class DataProducer implements JsonData {
}
}
addNodeCodeBookPart(
nodeCodeBook: NodeCodeBook,
options: RequestOptions,
): void {
if (options.follow.has(Follow.NodeCodeBook_codeBook)) {
this.requestedCodeBookFilePathByPath.set(
nodeCodeBook.path,
nodeCodeBook.file_path!,
)
}
}
async getAll(): Promise<void> {
let empty = false
while (!empty) {
......@@ -85,6 +102,7 @@ export class DataProducer implements JsonData {
options,
] of requestedChildrenOptionsByPath.entries()) {
const deep = options.deep ?? false
const fields = options.fields ?? []
const follow = options.follow
const limit = options.limit ?? 10
const offset = options.offset ?? 0
......@@ -121,7 +139,11 @@ export class DataProducer implements JsonData {
"nodes.*",
"nodes_autocomplete.autocomplete",
"nodes_autocomplete.autocomplete <-> $<term> AS distance",
"nodes_autocomplete.field",
]
if (fields.length > 0) {
whereClauses.push("nodes_autocomplete.field IN ($<fields:list>)")
}
}
const joinsClause =
joinClauses.length > 0 ? joinClauses.join(" ") : ""
......@@ -136,6 +158,7 @@ export class DataProducer implements JsonData {
${whereClause}
`,
{
fields,
path,
term,
types,
......@@ -144,7 +167,7 @@ export class DataProducer implements JsonData {
).count
const childrenOptions = removeUnfollowedFromOptions(