pgkiln 0.68.0 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/db/migrations/135_fulltext_search.sql +60 -0
- package/docs/apex-feature-parity.md +2 -2
- package/docs/guide/03-builder.md +7 -0
- package/docs/guide/04-pages-and-regions.md +46 -1
- package/docs/guide/12-development.md +10 -0
- package/examples/hr/README.md +1 -0
- package/examples/hr/hr_71_fulltext_search.sql +43 -0
- package/package.json +1 -1
- package/src/builder/advisor.ts +39 -3
- package/src/builder/components.ts +14 -1
- package/src/builder/fulltext.ts +160 -0
- package/src/builder/i18n/de.ts +20 -0
- package/src/builder/i18n/en.ts +21 -0
- package/src/builder/i18n/es.ts +20 -0
- package/src/builder/i18n/fr.ts +20 -0
- package/src/builder/i18n/it.ts +20 -0
- package/src/builder/i18n/ja.ts +20 -0
- package/src/builder/i18n/ko.ts +20 -0
- package/src/builder/i18n/nl.ts +20 -0
- package/src/builder/i18n/pt.ts +20 -0
- package/src/builder/i18n/zh-cn.ts +20 -0
- package/src/builder/i18n/zh-tw.ts +20 -0
- package/src/builder/object-actions.ts +1 -0
- package/src/builder/sql.ts +3 -0
- package/src/builder/table-editor.ts +1 -0
- package/src/i18n/ar.ts +1 -0
- package/src/i18n/cs.ts +1 -0
- package/src/i18n/da.ts +1 -0
- package/src/i18n/de.ts +1 -0
- package/src/i18n/el.ts +1 -0
- package/src/i18n/es.ts +1 -0
- package/src/i18n/fi.ts +1 -0
- package/src/i18n/fr.ts +1 -0
- package/src/i18n/he.ts +1 -0
- package/src/i18n/it.ts +1 -0
- package/src/i18n/ja.ts +1 -0
- package/src/i18n/ko.ts +1 -0
- package/src/i18n/nb.ts +1 -0
- package/src/i18n/pl.ts +1 -0
- package/src/i18n/pt.ts +1 -0
- package/src/i18n/ru.ts +1 -0
- package/src/i18n/sv.ts +1 -0
- package/src/i18n/tr.ts +1 -0
- package/src/i18n/uk.ts +1 -0
- package/src/i18n/zh.ts +1 -0
- package/src/i18n.ts +2 -0
- package/src/runtime/report.ts +26 -2
- package/src/runtime/search.ts +184 -21
package/src/builder/i18n/de.ts
CHANGED
|
@@ -1045,6 +1045,26 @@ export const de: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': 'Fehlgeschlagene Anweisung',
|
|
1046
1046
|
'te.title_table': 'Tabelle {table}',
|
|
1047
1047
|
'te.title_create': 'Tabelle erstellen',
|
|
1048
|
+
'fts.add': "Volltextsuche hinzufügen",
|
|
1049
|
+
'fts.title': "Volltextsuche für {table}",
|
|
1050
|
+
'fts.intro': "Fügt eine gespeicherte generierte tsvector-Spalte über die gewählten Textspalten hinzu, mit einem GIN-Index darauf. Eine Suchkonfiguration vom Suchtyp fulltext (Gemeinsame Komponenten › Suchkonfigurationen) oder die Suche eines Berichts findet dann Wortformen (\"running\" findet \"run\") schnell. Die Spalte aktualisiert sich selbst; das Hinzufügen schreibt die Tabelle neu.",
|
|
1051
|
+
'fts.columns': "Textspalten",
|
|
1052
|
+
'fts.include': "Einbeziehen",
|
|
1053
|
+
'fts.weight': "Gewichtung",
|
|
1054
|
+
'fts.weight_help': "A zählt in der Rangfolge am meisten, D am wenigsten: z. B. A für einen Titel, B für eine Beschreibung.",
|
|
1055
|
+
'fts.config': "Textsuchkonfiguration",
|
|
1056
|
+
'fts.config_help': "Die Sprache, deren Wortstämme verwendet werden (german: Läufer → läuf); simple: keine Stammformen. Mit derselben Konfiguration suchen.",
|
|
1057
|
+
'fts.column': "tsvector-Spalte",
|
|
1058
|
+
'fts.index': "Indexname",
|
|
1059
|
+
'fts.no_text': "Diese Tabelle hat keine Textspalten zum Durchsuchen.",
|
|
1060
|
+
'fts.pick': "Wählen Sie mindestens eine Textspalte.",
|
|
1061
|
+
'fts.bad_name': "\"{name}\" ist kein gültiger Name: Kleinbuchstaben, Ziffern und _.",
|
|
1062
|
+
'fts.exists': "{name} existiert bereits.",
|
|
1063
|
+
'fts.bad_config': "{name} ist keine Textsuchkonfiguration.",
|
|
1064
|
+
'fts.existing': "Vorhandene tsvector-Spalten:",
|
|
1065
|
+
'fts.gin_yes': "GIN-Index",
|
|
1066
|
+
'fts.gin_no': "kein GIN-Index",
|
|
1067
|
+
'fts.added': "Volltextsuche zu {table} hinzugefügt: Spalte {column} mit Index {index}.",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': 'Navigationseintrag',
|
|
1050
1070
|
'comp.nav_entry.plural': 'Navigationsmenü',
|
package/src/builder/i18n/en.ts
CHANGED
|
@@ -1048,6 +1048,27 @@ export const en = {
|
|
|
1048
1048
|
'te.failed_stmt': 'Failed statement',
|
|
1049
1049
|
'te.title_table': 'Table {table}',
|
|
1050
1050
|
'te.title_create': 'Create table',
|
|
1051
|
+
// (sprint 135, AP-2) Table Properties › Add full-text search
|
|
1052
|
+
'fts.add': "Add full-text search",
|
|
1053
|
+
'fts.title': "Full-text search on {table}",
|
|
1054
|
+
'fts.intro': "Adds a stored generated tsvector column over the text columns you choose, and a GIN index on it. A search configuration of search type fulltext (Shared Components › Search configurations) or a report search then finds stemmed words (\"running\" finds \"run\") fast. The column keeps itself up to date; adding it rewrites the table.",
|
|
1055
|
+
'fts.columns': "Text columns",
|
|
1056
|
+
'fts.include': "Include",
|
|
1057
|
+
'fts.weight': "Weight",
|
|
1058
|
+
'fts.weight_help': "A counts most in the ranking, D least: e.g. A for a title, B for a description.",
|
|
1059
|
+
'fts.config': "Text search configuration",
|
|
1060
|
+
'fts.config_help': "The language whose stemming is used (english: running → run); simple: no stemming. Search with the same configuration.",
|
|
1061
|
+
'fts.column': "tsvector column",
|
|
1062
|
+
'fts.index': "Index name",
|
|
1063
|
+
'fts.no_text': "This table has no text columns to search.",
|
|
1064
|
+
'fts.pick': "Choose at least one text column.",
|
|
1065
|
+
'fts.bad_name': "\"{name}\" is not a valid name: lowercase letters, digits and _.",
|
|
1066
|
+
'fts.exists': "{name} already exists.",
|
|
1067
|
+
'fts.bad_config': "{name} is not a text search configuration.",
|
|
1068
|
+
'fts.existing': "tsvector columns now:",
|
|
1069
|
+
'fts.gin_yes': "GIN index",
|
|
1070
|
+
'fts.gin_no': "no GIN index",
|
|
1071
|
+
'fts.added': "Added full-text search to {table}: column {column} with index {index}.",
|
|
1051
1072
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1052
1073
|
'comp.nav_entry': 'Navigation entry',
|
|
1053
1074
|
'comp.nav_entry.plural': 'Navigation menu',
|
package/src/builder/i18n/es.ts
CHANGED
|
@@ -1045,6 +1045,26 @@ export const es: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': 'Sentencia con error',
|
|
1046
1046
|
'te.title_table': 'Tabla {table}',
|
|
1047
1047
|
'te.title_create': 'Crear tabla',
|
|
1048
|
+
'fts.add': "Añadir búsqueda de texto completo",
|
|
1049
|
+
'fts.title': "Búsqueda de texto completo en {table}",
|
|
1050
|
+
'fts.intro': "Añade una columna tsvector generada y almacenada sobre las columnas de texto que elija, con un índice GIN. Una configuración de búsqueda de tipo fulltext (Componentes compartidos › Configuraciones de búsqueda) o la búsqueda de un informe encuentra entonces rápidamente las formas de las palabras (\"running\" encuentra \"run\"). La columna se mantiene al día; añadirla reescribe la tabla.",
|
|
1051
|
+
'fts.columns': "Columnas de texto",
|
|
1052
|
+
'fts.include': "Incluir",
|
|
1053
|
+
'fts.weight': "Peso",
|
|
1054
|
+
'fts.weight_help': "A cuenta más en la clasificación, D menos: p. ej. A para un título, B para una descripción.",
|
|
1055
|
+
'fts.config': "Configuración de búsqueda de texto",
|
|
1056
|
+
'fts.config_help': "El idioma cuya lematización se usa (spanish: corriendo → corr); simple: sin lematización. Busque con la misma configuración.",
|
|
1057
|
+
'fts.column': "Columna tsvector",
|
|
1058
|
+
'fts.index': "Nombre del índice",
|
|
1059
|
+
'fts.no_text': "Esta tabla no tiene columnas de texto en las que buscar.",
|
|
1060
|
+
'fts.pick': "Elija al menos una columna de texto.",
|
|
1061
|
+
'fts.bad_name': "\"{name}\" no es un nombre válido: minúsculas, dígitos y _.",
|
|
1062
|
+
'fts.exists': "{name} ya existe.",
|
|
1063
|
+
'fts.bad_config': "{name} no es una configuración de búsqueda de texto.",
|
|
1064
|
+
'fts.existing': "Columnas tsvector actuales:",
|
|
1065
|
+
'fts.gin_yes': "índice GIN",
|
|
1066
|
+
'fts.gin_no': "sin índice GIN",
|
|
1067
|
+
'fts.added': "Búsqueda de texto completo añadida a {table}: columna {column} con el índice {index}.",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': 'Entrada de navegación',
|
|
1050
1070
|
'comp.nav_entry.plural': 'Menú de navegación',
|
package/src/builder/i18n/fr.ts
CHANGED
|
@@ -1045,6 +1045,26 @@ export const fr: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': 'Instruction en échec',
|
|
1046
1046
|
'te.title_table': 'Table {table}',
|
|
1047
1047
|
'te.title_create': 'Créer une table',
|
|
1048
|
+
'fts.add': "Ajouter la recherche plein texte",
|
|
1049
|
+
'fts.title': "Recherche plein texte sur {table}",
|
|
1050
|
+
'fts.intro': "Ajoute une colonne tsvector générée et stockée sur les colonnes de texte choisies, avec un index GIN. Une configuration de recherche de type fulltext (Composants partagés › Configurations de recherche) ou la recherche d'un rapport trouve alors rapidement les formes des mots (\"running\" trouve \"run\"). La colonne se tient à jour ; l'ajouter réécrit la table.",
|
|
1051
|
+
'fts.columns': "Colonnes de texte",
|
|
1052
|
+
'fts.include': "Inclure",
|
|
1053
|
+
'fts.weight': "Poids",
|
|
1054
|
+
'fts.weight_help': "A compte le plus dans le classement, D le moins : par ex. A pour un titre, B pour une description.",
|
|
1055
|
+
'fts.config': "Configuration de recherche de texte",
|
|
1056
|
+
'fts.config_help': "La langue dont la racinisation est utilisée (french : courir → cour) ; simple : sans racinisation. Recherchez avec la même configuration.",
|
|
1057
|
+
'fts.column': "Colonne tsvector",
|
|
1058
|
+
'fts.index': "Nom de l'index",
|
|
1059
|
+
'fts.no_text': "Cette table n'a pas de colonnes de texte à rechercher.",
|
|
1060
|
+
'fts.pick': "Choisissez au moins une colonne de texte.",
|
|
1061
|
+
'fts.bad_name': "« {name} » n'est pas un nom valide : minuscules, chiffres et _.",
|
|
1062
|
+
'fts.exists': "{name} existe déjà.",
|
|
1063
|
+
'fts.bad_config': "{name} n'est pas une configuration de recherche de texte.",
|
|
1064
|
+
'fts.existing': "Colonnes tsvector actuelles :",
|
|
1065
|
+
'fts.gin_yes': "index GIN",
|
|
1066
|
+
'fts.gin_no': "pas d'index GIN",
|
|
1067
|
+
'fts.added': "Recherche plein texte ajoutée à {table} : colonne {column} avec l'index {index}.",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': 'Entrée de navigation',
|
|
1050
1070
|
'comp.nav_entry.plural': 'Menu de navigation',
|
package/src/builder/i18n/it.ts
CHANGED
|
@@ -1045,6 +1045,26 @@ export const it: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': 'Istruzione non riuscita',
|
|
1046
1046
|
'te.title_table': 'Tabella {table}',
|
|
1047
1047
|
'te.title_create': 'Crea tabella',
|
|
1048
|
+
'fts.add': "Aggiungi ricerca full-text",
|
|
1049
|
+
'fts.title': "Ricerca full-text su {table}",
|
|
1050
|
+
'fts.intro': "Aggiunge una colonna tsvector generata e memorizzata sulle colonne di testo scelte, con un indice GIN. Una configurazione di ricerca di tipo fulltext (Componenti condivisi › Configurazioni di ricerca) o la ricerca di un report trova allora rapidamente le forme delle parole (\"running\" trova \"run\"). La colonna si aggiorna da sola; aggiungerla riscrive la tabella.",
|
|
1051
|
+
'fts.columns': "Colonne di testo",
|
|
1052
|
+
'fts.include': "Includi",
|
|
1053
|
+
'fts.weight': "Peso",
|
|
1054
|
+
'fts.weight_help': "A conta di più nella classifica, D di meno: ad es. A per un titolo, B per una descrizione.",
|
|
1055
|
+
'fts.config': "Configurazione di ricerca testuale",
|
|
1056
|
+
'fts.config_help': "La lingua di cui si usa lo stemming (italian: correndo → corr); simple: nessuno stemming. Cercate con la stessa configurazione.",
|
|
1057
|
+
'fts.column': "Colonna tsvector",
|
|
1058
|
+
'fts.index': "Nome dell'indice",
|
|
1059
|
+
'fts.no_text': "Questa tabella non ha colonne di testo in cui cercare.",
|
|
1060
|
+
'fts.pick': "Scegliete almeno una colonna di testo.",
|
|
1061
|
+
'fts.bad_name': "\"{name}\" non è un nome valido: lettere minuscole, cifre e _.",
|
|
1062
|
+
'fts.exists': "{name} esiste già.",
|
|
1063
|
+
'fts.bad_config': "{name} non è una configurazione di ricerca testuale.",
|
|
1064
|
+
'fts.existing': "Colonne tsvector attuali:",
|
|
1065
|
+
'fts.gin_yes': "indice GIN",
|
|
1066
|
+
'fts.gin_no': "nessun indice GIN",
|
|
1067
|
+
'fts.added': "Ricerca full-text aggiunta a {table}: colonna {column} con l'indice {index}.",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': 'Voce di navigazione',
|
|
1050
1070
|
'comp.nav_entry.plural': 'Menu di navigazione',
|
package/src/builder/i18n/ja.ts
CHANGED
|
@@ -1045,6 +1045,26 @@ export const ja: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': '失敗した文',
|
|
1046
1046
|
'te.title_table': '表 {table}',
|
|
1047
1047
|
'te.title_create': '表の作成',
|
|
1048
|
+
'fts.add': "全文検索の追加",
|
|
1049
|
+
'fts.title': "{table} の全文検索",
|
|
1050
|
+
'fts.intro': "選択したテキスト列にまたがる格納生成 tsvector 列と、その GIN 索引を追加します。これにより、検索タイプ fulltext の検索構成(共有コンポーネント › 検索構成)やレポートの検索で、語形変化(\"running\" で \"run\")をすばやく見つけられます。列は自動的に更新されます。追加すると表が書き換えられます。",
|
|
1051
|
+
'fts.columns': "テキスト列",
|
|
1052
|
+
'fts.include': "含める",
|
|
1053
|
+
'fts.weight': "重み",
|
|
1054
|
+
'fts.weight_help': "ランキングでは A が最も重く、D が最も軽くなります。例:タイトルは A、説明は B。",
|
|
1055
|
+
'fts.config': "テキスト検索構成",
|
|
1056
|
+
'fts.config_help': "語幹処理に使う言語(english:running → run)。simple:語幹処理なし。検索にも同じ構成を使ってください。",
|
|
1057
|
+
'fts.column': "tsvector 列",
|
|
1058
|
+
'fts.index': "索引名",
|
|
1059
|
+
'fts.no_text': "この表には検索できるテキスト列がありません。",
|
|
1060
|
+
'fts.pick': "テキスト列を 1 つ以上選択してください。",
|
|
1061
|
+
'fts.bad_name': "\"{name}\" は有効な名前ではありません:小文字、数字、_ のみ。",
|
|
1062
|
+
'fts.exists': "{name} はすでに存在します。",
|
|
1063
|
+
'fts.bad_config': "{name} はテキスト検索構成ではありません。",
|
|
1064
|
+
'fts.existing': "現在の tsvector 列:",
|
|
1065
|
+
'fts.gin_yes': "GIN 索引",
|
|
1066
|
+
'fts.gin_no': "GIN 索引なし",
|
|
1067
|
+
'fts.added': "{table} に全文検索を追加しました:列 {column}、索引 {index}。",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': 'ナビゲーション・エントリ',
|
|
1050
1070
|
'comp.nav_entry.plural': 'ナビゲーション・メニュー',
|
package/src/builder/i18n/ko.ts
CHANGED
|
@@ -1045,6 +1045,26 @@ export const ko: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': '실패한 문장',
|
|
1046
1046
|
'te.title_table': '테이블 {table}',
|
|
1047
1047
|
'te.title_create': '테이블 생성',
|
|
1048
|
+
'fts.add': "전체 텍스트 검색 추가",
|
|
1049
|
+
'fts.title': "{table}의 전체 텍스트 검색",
|
|
1050
|
+
'fts.intro': "선택한 텍스트 열에 대한 저장된 생성 tsvector 열과 그 위의 GIN 인덱스를 추가합니다. 그러면 검색 유형이 fulltext인 검색 구성(공유 구성 요소 › 검색 구성)이나 보고서 검색이 어형 변화(\"running\"으로 \"run\")를 빠르게 찾습니다. 열은 자동으로 최신 상태를 유지하며, 추가할 때 테이블이 다시 작성됩니다.",
|
|
1051
|
+
'fts.columns': "텍스트 열",
|
|
1052
|
+
'fts.include': "포함",
|
|
1053
|
+
'fts.weight': "가중치",
|
|
1054
|
+
'fts.weight_help': "순위에서 A가 가장 중요하고 D가 가장 덜 중요합니다. 예: 제목은 A, 설명은 B.",
|
|
1055
|
+
'fts.config': "텍스트 검색 구성",
|
|
1056
|
+
'fts.config_help': "어간 처리에 사용할 언어(english: running → run). simple: 어간 처리 없음. 검색할 때도 같은 구성을 사용하십시오.",
|
|
1057
|
+
'fts.column': "tsvector 열",
|
|
1058
|
+
'fts.index': "인덱스 이름",
|
|
1059
|
+
'fts.no_text': "이 테이블에는 검색할 텍스트 열이 없습니다.",
|
|
1060
|
+
'fts.pick': "텍스트 열을 하나 이상 선택하십시오.",
|
|
1061
|
+
'fts.bad_name': "\"{name}\"은(는) 올바른 이름이 아닙니다: 소문자, 숫자, _만 사용할 수 있습니다.",
|
|
1062
|
+
'fts.exists': "{name}이(가) 이미 있습니다.",
|
|
1063
|
+
'fts.bad_config': "{name}은(는) 텍스트 검색 구성이 아닙니다.",
|
|
1064
|
+
'fts.existing': "현재 tsvector 열:",
|
|
1065
|
+
'fts.gin_yes': "GIN 인덱스",
|
|
1066
|
+
'fts.gin_no': "GIN 인덱스 없음",
|
|
1067
|
+
'fts.added': "{table}에 전체 텍스트 검색을 추가했습니다: 열 {column}, 인덱스 {index}.",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': '탐색 항목',
|
|
1050
1070
|
'comp.nav_entry.plural': '탐색 메뉴',
|
package/src/builder/i18n/nl.ts
CHANGED
|
@@ -1045,6 +1045,26 @@ export const nl: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': 'Mislukt statement',
|
|
1046
1046
|
'te.title_table': 'Tabel {table}',
|
|
1047
1047
|
'te.title_create': 'Tabel maken',
|
|
1048
|
+
'fts.add': "Volledige-tekstzoeken toevoegen",
|
|
1049
|
+
'fts.title': "Volledige-tekstzoeken op {table}",
|
|
1050
|
+
'fts.intro': "Voegt een opgeslagen gegenereerde tsvector-kolom toe over de tekstkolommen die u kiest, met een GIN-index erop. Een zoekconfiguratie van zoektype fulltext (Gedeelde componenten › Zoekconfiguraties) of het zoeken in een rapport vindt dan snel woorden in al hun vormen (\"running\" vindt \"run\"). De kolom houdt zichzelf bij; toevoegen herschrijft de tabel.",
|
|
1051
|
+
'fts.columns': "Tekstkolommen",
|
|
1052
|
+
'fts.include': "Meenemen",
|
|
1053
|
+
'fts.weight': "Gewicht",
|
|
1054
|
+
'fts.weight_help': "A telt het zwaarst in de rangorde, D het minst: bijvoorbeeld A voor een titel, B voor een omschrijving.",
|
|
1055
|
+
'fts.config': "Tekstzoekconfiguratie",
|
|
1056
|
+
'fts.config_help': "De taal waarvan de woordstammen worden gebruikt (dutch: lopen → loop); simple: geen stammen. Zoek met dezelfde configuratie.",
|
|
1057
|
+
'fts.column': "tsvector-kolom",
|
|
1058
|
+
'fts.index': "Indexnaam",
|
|
1059
|
+
'fts.no_text': "Deze tabel heeft geen tekstkolommen om in te zoeken.",
|
|
1060
|
+
'fts.pick': "Kies ten minste één tekstkolom.",
|
|
1061
|
+
'fts.bad_name': "\"{name}\" is geen geldige naam: kleine letters, cijfers en _.",
|
|
1062
|
+
'fts.exists': "{name} bestaat al.",
|
|
1063
|
+
'fts.bad_config': "{name} is geen tekstzoekconfiguratie.",
|
|
1064
|
+
'fts.existing': "tsvector-kolommen nu:",
|
|
1065
|
+
'fts.gin_yes': "GIN-index",
|
|
1066
|
+
'fts.gin_no': "geen GIN-index",
|
|
1067
|
+
'fts.added': "Volledige-tekstzoeken toegevoegd aan {table}: kolom {column} met index {index}.",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': 'Navigatie-item',
|
|
1050
1070
|
'comp.nav_entry.plural': 'Navigatiemenu',
|
package/src/builder/i18n/pt.ts
CHANGED
|
@@ -1045,6 +1045,26 @@ export const pt: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': 'Instrução com falha',
|
|
1046
1046
|
'te.title_table': 'Tabela {table}',
|
|
1047
1047
|
'te.title_create': 'Criar tabela',
|
|
1048
|
+
'fts.add': "Adicionar pesquisa de texto integral",
|
|
1049
|
+
'fts.title': "Pesquisa de texto integral em {table}",
|
|
1050
|
+
'fts.intro': "Adiciona uma coluna tsvector gerada e armazenada sobre as colunas de texto escolhidas, com um índice GIN. Uma configuração de pesquisa do tipo fulltext (Componentes partilhados › Configurações de pesquisa) ou a pesquisa de um relatório encontra então rapidamente as formas das palavras (\"running\" encontra \"run\"). A coluna mantém-se atualizada; adicioná-la reescreve a tabela.",
|
|
1051
|
+
'fts.columns': "Colunas de texto",
|
|
1052
|
+
'fts.include': "Incluir",
|
|
1053
|
+
'fts.weight': "Peso",
|
|
1054
|
+
'fts.weight_help': "A conta mais na classificação, D menos: p. ex. A para um título, B para uma descrição.",
|
|
1055
|
+
'fts.config': "Configuração de pesquisa de texto",
|
|
1056
|
+
'fts.config_help': "A língua cuja radicalização é usada (portuguese: correndo → corr); simple: sem radicalização. Pesquise com a mesma configuração.",
|
|
1057
|
+
'fts.column': "Coluna tsvector",
|
|
1058
|
+
'fts.index': "Nome do índice",
|
|
1059
|
+
'fts.no_text': "Esta tabela não tem colunas de texto para pesquisar.",
|
|
1060
|
+
'fts.pick': "Escolha pelo menos uma coluna de texto.",
|
|
1061
|
+
'fts.bad_name': "\"{name}\" não é um nome válido: minúsculas, dígitos e _.",
|
|
1062
|
+
'fts.exists': "{name} já existe.",
|
|
1063
|
+
'fts.bad_config': "{name} não é uma configuração de pesquisa de texto.",
|
|
1064
|
+
'fts.existing': "Colunas tsvector atuais:",
|
|
1065
|
+
'fts.gin_yes': "índice GIN",
|
|
1066
|
+
'fts.gin_no': "sem índice GIN",
|
|
1067
|
+
'fts.added': "Pesquisa de texto integral adicionada a {table}: coluna {column} com o índice {index}.",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': 'Entrada de navegação',
|
|
1050
1070
|
'comp.nav_entry.plural': 'Menu de navegação',
|
|
@@ -1045,6 +1045,26 @@ export const zhCN: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': '失败的语句',
|
|
1046
1046
|
'te.title_table': '表 {table}',
|
|
1047
1047
|
'te.title_create': '创建表',
|
|
1048
|
+
'fts.add': "添加全文搜索",
|
|
1049
|
+
'fts.title': "{table} 的全文搜索",
|
|
1050
|
+
'fts.intro': "在所选的文本列上添加一个存储的生成 tsvector 列,并在其上创建 GIN 索引。之后,搜索类型为 fulltext 的搜索配置(共享组件 › 搜索配置)或报表搜索即可快速找到词形变化(\"running\" 可找到 \"run\")。该列会自动保持最新;添加时会重写该表。",
|
|
1051
|
+
'fts.columns': "文本列",
|
|
1052
|
+
'fts.include': "包含",
|
|
1053
|
+
'fts.weight': "权重",
|
|
1054
|
+
'fts.weight_help': "A 在排序中最重要,D 最不重要:例如标题用 A,描述用 B。",
|
|
1055
|
+
'fts.config': "文本搜索配置",
|
|
1056
|
+
'fts.config_help': "使用其词干规则的语言(english:running → run);simple:不提取词干。搜索时请使用相同的配置。",
|
|
1057
|
+
'fts.column': "tsvector 列",
|
|
1058
|
+
'fts.index': "索引名称",
|
|
1059
|
+
'fts.no_text': "此表没有可搜索的文本列。",
|
|
1060
|
+
'fts.pick': "请至少选择一个文本列。",
|
|
1061
|
+
'fts.bad_name': "\"{name}\" 不是有效名称:只能使用小写字母、数字和 _。",
|
|
1062
|
+
'fts.exists': "{name} 已存在。",
|
|
1063
|
+
'fts.bad_config': "{name} 不是文本搜索配置。",
|
|
1064
|
+
'fts.existing': "现有 tsvector 列:",
|
|
1065
|
+
'fts.gin_yes': "GIN 索引",
|
|
1066
|
+
'fts.gin_no': "无 GIN 索引",
|
|
1067
|
+
'fts.added': "已为 {table} 添加全文搜索:列 {column},索引 {index}。",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': '导航条目',
|
|
1050
1070
|
'comp.nav_entry.plural': '导航菜单',
|
|
@@ -1045,6 +1045,26 @@ export const zhTW: BuilderMessages = {
|
|
|
1045
1045
|
'te.failed_stmt': '失敗的敘述句',
|
|
1046
1046
|
'te.title_table': '表格 {table}',
|
|
1047
1047
|
'te.title_create': '建立表格',
|
|
1048
|
+
'fts.add': "新增全文檢索",
|
|
1049
|
+
'fts.title': "{table} 的全文檢索",
|
|
1050
|
+
'fts.intro': "在所選的文字欄位上新增一個儲存的產生 tsvector 欄位,並在其上建立 GIN 索引。之後,搜尋類型為 fulltext 的搜尋設定(共用元件 › 搜尋設定)或報表搜尋即可快速找到詞形變化(\"running\" 可找到 \"run\")。該欄位會自動保持最新;新增時會重寫該表格。",
|
|
1051
|
+
'fts.columns': "文字欄位",
|
|
1052
|
+
'fts.include': "包含",
|
|
1053
|
+
'fts.weight': "權重",
|
|
1054
|
+
'fts.weight_help': "A 在排序中最重要,D 最不重要:例如標題用 A,描述用 B。",
|
|
1055
|
+
'fts.config': "文字搜尋設定",
|
|
1056
|
+
'fts.config_help': "使用其詞幹規則的語言(english:running → run);simple:不擷取詞幹。搜尋時請使用相同的設定。",
|
|
1057
|
+
'fts.column': "tsvector 欄位",
|
|
1058
|
+
'fts.index': "索引名稱",
|
|
1059
|
+
'fts.no_text': "此表格沒有可搜尋的文字欄位。",
|
|
1060
|
+
'fts.pick': "請至少選擇一個文字欄位。",
|
|
1061
|
+
'fts.bad_name': "\"{name}\" 不是有效名稱:只能使用小寫字母、數字和 _。",
|
|
1062
|
+
'fts.exists': "{name} 已存在。",
|
|
1063
|
+
'fts.bad_config': "{name} 不是文字搜尋設定。",
|
|
1064
|
+
'fts.existing': "現有 tsvector 欄位:",
|
|
1065
|
+
'fts.gin_yes': "GIN 索引",
|
|
1066
|
+
'fts.gin_no': "無 GIN 索引",
|
|
1067
|
+
'fts.added': "已為 {table} 新增全文檢索:欄位 {column},索引 {index}。",
|
|
1048
1068
|
// ------------------------------------------------------------ Shared Components (sprint 124)
|
|
1049
1069
|
'comp.nav_entry': '導覽項目',
|
|
1050
1070
|
'comp.nav_entry.plural': '導覽選單',
|
|
@@ -32,6 +32,7 @@ export function objectMenu(schema: string, o: MenuObj): Raw {
|
|
|
32
32
|
${table ? item(`${BASE}/sql/objects/table?${new URLSearchParams({ schema, template: o.ref })}`, 'copy', 'Use as template') : ''}
|
|
33
33
|
${table ? item(`${BASE}/sql/objects/security?${new URLSearchParams({ o: o.ref })}`, 'shield', 'Security…') : ''}
|
|
34
34
|
${table ? item(`${BASE}/sql/load`, 'upload', 'Load data') : ''}
|
|
35
|
+
${table ? item(`${BASE}/sql/objects/fulltext?${new URLSearchParams({ o: o.ref })}`, 'search', 'Add full-text search…') : ''}
|
|
35
36
|
${table ? html`${item(q('index'), 'list', 'Add index')}${item(q('trigger'), 'bolt', 'Add trigger')}${item(q('policy'), 'shield', 'Add policy')}` : ''}
|
|
36
37
|
${RELATIONS.has(o.type) ? item(`${BASE}/sql/rest/object?${new URLSearchParams({ schema, name: o.name })}`, 'globe', 'REST › Enable / Disable') : ''}
|
|
37
38
|
${item(q('ddl'), 'code', 'Quick DDL to the worksheet')}
|
package/src/builder/sql.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { sqlUtilityRoutes } from './sql-utilities.ts';
|
|
|
19
19
|
import { createTemplate, objectBrowserRoutes } from './object-browser.ts';
|
|
20
20
|
import { objectActionRoutes } from './object-actions.ts';
|
|
21
21
|
import { tableEditorRoutes } from './table-editor.ts';
|
|
22
|
+
import { fulltextRoutes } from './fulltext.ts';
|
|
22
23
|
import { dataSecurityRoutes } from './data-security.ts';
|
|
23
24
|
import { dataModelerRoutes } from './data-modeler.ts';
|
|
24
25
|
import { autoRestBuilderRoutes } from './autorest.ts';
|
|
@@ -134,6 +135,8 @@ export async function sqlRoutes(app: FastifyInstance) {
|
|
|
134
135
|
await app.register(objectActionRoutes);
|
|
135
136
|
// (sprint 95) Table Properties: create, edit or copy a table in a form
|
|
136
137
|
await app.register(tableEditorRoutes);
|
|
138
|
+
// (sprint 135, AP-2) Table Properties › Add full-text search
|
|
139
|
+
await app.register(fulltextRoutes);
|
|
137
140
|
await app.register(dataSecurityRoutes);
|
|
138
141
|
// (sprint 98) the Data Modeler: relational diagrams, their DDL and data dictionary
|
|
139
142
|
await app.register(dataModelerRoutes);
|
|
@@ -142,6 +142,7 @@ function form(s: Session, def: TableDef, opts: { editing: TableDef | null; schem
|
|
|
142
142
|
<button class="btn" name="mode" value="preview">${icon('eye')} ${tx('te.preview')}</button>
|
|
143
143
|
<button class="btn btn-hot" name="mode" value="apply">${icon('check')} ${tx('te.apply')}</button>
|
|
144
144
|
<button class="btn" name="mode" value="worksheet">${icon('code')} ${tx('te.open_ws')}</button>
|
|
145
|
+
${editing ? html`<a class="btn" href="${BASE}/sql/objects/fulltext?${new URLSearchParams({ o: opts.ref })}">${icon('search')} ${tx('fts.add')}…</a>` : ''}
|
|
145
146
|
<a class="btn" href="${editing ? `${BASE}/sql/objects?${new URLSearchParams({ schema: def.schema, k: 'table', o: opts.ref })}` : `${BASE}/sql/objects?${new URLSearchParams({ schema: def.schema })}`}">${tx('common.cancel')}</a>
|
|
146
147
|
</div></form>`;
|
|
147
148
|
}
|
package/src/i18n/ar.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const ar: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "جارٍ تحميل المزيد…",
|
|
425
425
|
'da.wait': "يرجى الانتظار…",
|
|
426
426
|
'lov.no_rows': "لم يُعثر على شيء.",
|
|
427
|
+
'search.did_you_mean': "هل تقصد:",
|
|
427
428
|
'error.lov_value': "{label}: اختر قيمة من القائمة.",
|
|
428
429
|
'item.yes': "نعم",
|
|
429
430
|
'item.no': "لا",
|
package/src/i18n/cs.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const cs: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Načítání dalších…",
|
|
425
425
|
'da.wait': "Čekejte prosím…",
|
|
426
426
|
'lov.no_rows': "Nic nenalezeno.",
|
|
427
|
+
'search.did_you_mean': "Měli jste na mysli:",
|
|
427
428
|
'error.lov_value': "{label}: vyberte hodnotu ze seznamu.",
|
|
428
429
|
'item.yes': "Ano",
|
|
429
430
|
'item.no': "Ne",
|
package/src/i18n/da.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const da: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Indlæser flere…",
|
|
425
425
|
'da.wait': "Vent venligst…",
|
|
426
426
|
'lov.no_rows': "Intet fundet.",
|
|
427
|
+
'search.did_you_mean': "Mente du:",
|
|
427
428
|
'error.lov_value': "{label}: vælg en værdi på listen.",
|
|
428
429
|
'item.yes': "Ja",
|
|
429
430
|
'item.no': "Nej",
|
package/src/i18n/de.ts
CHANGED
|
@@ -421,6 +421,7 @@ export const de: Record<MessageKey, string> = {
|
|
|
421
421
|
'lov.loading': 'Weitere werden geladen…',
|
|
422
422
|
'da.wait': 'Bitte warten…',
|
|
423
423
|
'lov.no_rows': 'Nichts gefunden.',
|
|
424
|
+
'search.did_you_mean': "Meinten Sie:",
|
|
424
425
|
'error.lov_value': '{label}: Wählen Sie einen Wert aus der Liste.',
|
|
425
426
|
'item.yes': 'Ja',
|
|
426
427
|
'item.no': 'Nein',
|
package/src/i18n/el.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const el: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Φόρτωση περισσότερων…",
|
|
425
425
|
'da.wait': "Παρακαλώ περιμένετε…",
|
|
426
426
|
'lov.no_rows': "Δεν βρέθηκε τίποτα.",
|
|
427
|
+
'search.did_you_mean': "Μήπως εννοούσατε:",
|
|
427
428
|
'error.lov_value': "{label}: επιλέξτε τιμή από τη λίστα.",
|
|
428
429
|
'item.yes': "Ναι",
|
|
429
430
|
'item.no': "Όχι",
|
package/src/i18n/es.ts
CHANGED
|
@@ -421,6 +421,7 @@ export const es: Record<MessageKey, string> = {
|
|
|
421
421
|
'lov.loading': 'Cargando más…',
|
|
422
422
|
'da.wait': 'Espere, por favor…',
|
|
423
423
|
'lov.no_rows': 'No se ha encontrado nada.',
|
|
424
|
+
'search.did_you_mean': "Quizás quiso decir:",
|
|
424
425
|
'error.lov_value': '{label}: elija un valor de la lista.',
|
|
425
426
|
'item.yes': 'Sí',
|
|
426
427
|
'item.no': 'No',
|
package/src/i18n/fi.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const fi: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Ladataan lisää…",
|
|
425
425
|
'da.wait': "Odota hetki…",
|
|
426
426
|
'lov.no_rows': "Mitään ei löytynyt.",
|
|
427
|
+
'search.did_you_mean': "Tarkoititko:",
|
|
427
428
|
'error.lov_value': "{label}: valitse arvo luettelosta.",
|
|
428
429
|
'item.yes': "Kyllä",
|
|
429
430
|
'item.no': "Ei",
|
package/src/i18n/fr.ts
CHANGED
|
@@ -421,6 +421,7 @@ export const fr: Record<MessageKey, string> = {
|
|
|
421
421
|
'lov.loading': 'Chargement de la suite…',
|
|
422
422
|
'da.wait': 'Veuillez patienter…',
|
|
423
423
|
'lov.no_rows': 'Aucun résultat.',
|
|
424
|
+
'search.did_you_mean': "Vouliez-vous dire :",
|
|
424
425
|
'error.lov_value': '{label} : choisissez une valeur dans la liste.',
|
|
425
426
|
'item.yes': 'Oui',
|
|
426
427
|
'item.no': 'Non',
|
package/src/i18n/he.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const he: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "טוען עוד…",
|
|
425
425
|
'da.wait': "נא להמתין…",
|
|
426
426
|
'lov.no_rows': "לא נמצא דבר.",
|
|
427
|
+
'search.did_you_mean': "האם התכוונת ל:",
|
|
427
428
|
'error.lov_value': "{label}: בחרו ערך מהרשימה.",
|
|
428
429
|
'item.yes': "כן",
|
|
429
430
|
'item.no': "לא",
|
package/src/i18n/it.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const it: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Caricamento di altri…",
|
|
425
425
|
'da.wait': "Attendere prego…",
|
|
426
426
|
'lov.no_rows': "Nessun risultato.",
|
|
427
|
+
'search.did_you_mean': "Forse cercavi:",
|
|
427
428
|
'error.lov_value': "{label}: scegli un valore dall'elenco.",
|
|
428
429
|
'item.yes': "Sì",
|
|
429
430
|
'item.no': "No",
|
package/src/i18n/ja.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const ja: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "さらに読み込み中…",
|
|
425
425
|
'da.wait': "お待ちください…",
|
|
426
426
|
'lov.no_rows': "見つかりません。",
|
|
427
|
+
'search.did_you_mean': "もしかして:",
|
|
427
428
|
'error.lov_value': "{label}: 一覧から値を選んでください。",
|
|
428
429
|
'item.yes': "はい",
|
|
429
430
|
'item.no': "いいえ",
|
package/src/i18n/ko.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const ko: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "더 불러오는 중…",
|
|
425
425
|
'da.wait': "잠시 기다려 주세요…",
|
|
426
426
|
'lov.no_rows': "찾은 항목이 없습니다.",
|
|
427
|
+
'search.did_you_mean': "이것을 찾으셨나요:",
|
|
427
428
|
'error.lov_value': "{label}: 목록에서 값을 선택하세요.",
|
|
428
429
|
'item.yes': "예",
|
|
429
430
|
'item.no': "아니요",
|
package/src/i18n/nb.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const nb: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Laster inn flere…",
|
|
425
425
|
'da.wait': "Vent litt…",
|
|
426
426
|
'lov.no_rows': "Fant ingenting.",
|
|
427
|
+
'search.did_you_mean': "Mente du:",
|
|
427
428
|
'error.lov_value': "{label}: velg en verdi fra listen.",
|
|
428
429
|
'item.yes': "Ja",
|
|
429
430
|
'item.no': "Nei",
|
package/src/i18n/pl.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const pl: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Wczytywanie kolejnych…",
|
|
425
425
|
'da.wait': "Proszę czekać…",
|
|
426
426
|
'lov.no_rows': "Nic nie znaleziono.",
|
|
427
|
+
'search.did_you_mean': "Czy chodziło o:",
|
|
427
428
|
'error.lov_value': "{label}: wybierz wartość z listy.",
|
|
428
429
|
'item.yes': "Tak",
|
|
429
430
|
'item.no': "Nie",
|
package/src/i18n/pt.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const pt: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "A carregar mais…",
|
|
425
425
|
'da.wait': "Aguarde, por favor…",
|
|
426
426
|
'lov.no_rows': "Nada encontrado.",
|
|
427
|
+
'search.did_you_mean': "Queria dizer:",
|
|
427
428
|
'error.lov_value': "{label}: escolha um valor da lista.",
|
|
428
429
|
'item.yes': "Sim",
|
|
429
430
|
'item.no': "Não",
|
package/src/i18n/ru.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const ru: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Загрузка…",
|
|
425
425
|
'da.wait': "Подождите…",
|
|
426
426
|
'lov.no_rows': "Ничего не найдено.",
|
|
427
|
+
'search.did_you_mean': "Возможно, вы имели в виду:",
|
|
427
428
|
'error.lov_value': "{label}: выберите значение из списка.",
|
|
428
429
|
'item.yes': "Да",
|
|
429
430
|
'item.no': "Нет",
|
package/src/i18n/sv.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const sv: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Läser in fler…",
|
|
425
425
|
'da.wait': "Vänta…",
|
|
426
426
|
'lov.no_rows': "Inget hittades.",
|
|
427
|
+
'search.did_you_mean': "Menade du:",
|
|
427
428
|
'error.lov_value': "{label}: välj ett värde i listan.",
|
|
428
429
|
'item.yes': "Ja",
|
|
429
430
|
'item.no': "Nej",
|
package/src/i18n/tr.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const tr: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Daha fazlası yükleniyor…",
|
|
425
425
|
'da.wait': "Lütfen bekleyin…",
|
|
426
426
|
'lov.no_rows': "Hiçbir şey bulunamadı.",
|
|
427
|
+
'search.did_you_mean': "Bunu mu demek istediniz:",
|
|
427
428
|
'error.lov_value': "{label}: listeden bir değer seçin.",
|
|
428
429
|
'item.yes': "Evet",
|
|
429
430
|
'item.no': "Hayır",
|
package/src/i18n/uk.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const uk: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "Завантаження…",
|
|
425
425
|
'da.wait': "Зачекайте…",
|
|
426
426
|
'lov.no_rows': "Нічого не знайдено.",
|
|
427
|
+
'search.did_you_mean': "Можливо, ви мали на увазі:",
|
|
427
428
|
'error.lov_value': "{label}: виберіть значення зі списку.",
|
|
428
429
|
'item.yes': "Так",
|
|
429
430
|
'item.no': "Ні",
|
package/src/i18n/zh.ts
CHANGED
|
@@ -424,6 +424,7 @@ export const zh: Record<MessageKey, string> = {
|
|
|
424
424
|
'lov.loading': "正在加载更多…",
|
|
425
425
|
'da.wait': "请稍候…",
|
|
426
426
|
'lov.no_rows': "未找到任何内容。",
|
|
427
|
+
'search.did_you_mean': "您是不是要找:",
|
|
427
428
|
'error.lov_value': "{label}:请从列表中选择一个值。",
|
|
428
429
|
'item.yes': "是",
|
|
429
430
|
'item.no': "否",
|
package/src/i18n.ts
CHANGED
|
@@ -451,6 +451,7 @@ const en = {
|
|
|
451
451
|
'lov.loading': 'Loading more…',
|
|
452
452
|
'da.wait': 'Please wait…',
|
|
453
453
|
'lov.no_rows': 'Nothing found.',
|
|
454
|
+
'search.did_you_mean': 'Did you mean:',
|
|
454
455
|
'error.lov_value': '{label}: choose a value from the list.',
|
|
455
456
|
'item.yes': 'Yes',
|
|
456
457
|
'item.no': 'No',
|
|
@@ -1318,6 +1319,7 @@ const nl: Record<MessageKey, string> = {
|
|
|
1318
1319
|
'lov.loading': 'Meer laden…',
|
|
1319
1320
|
'da.wait': 'Even geduld…',
|
|
1320
1321
|
'lov.no_rows': 'Niets gevonden.',
|
|
1322
|
+
'search.did_you_mean': 'Bedoelde u:',
|
|
1321
1323
|
'error.lov_value': '{label}: kies een waarde uit de lijst.',
|
|
1322
1324
|
'item.yes': 'Ja',
|
|
1323
1325
|
'item.no': 'Nee',
|
package/src/runtime/report.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { REPORT_CHART_KINDS } from './charts.ts';
|
|
|
17
17
|
import { ComputeError, computeNameOk, computeSql, type Computation } from './compute.ts';
|
|
18
18
|
import { GRID_VIEWS, renderView, VIEWS, type View } from './report-views.ts';
|
|
19
19
|
import { columnTemplates } from './template-components.ts';
|
|
20
|
+
import { textSearchConfig } from './search.ts';
|
|
20
21
|
import { facetFilterSql, facetFilters, hidesColumns, reportFacetDefs, searchSql, userColumnNames } from './facet-state.ts';
|
|
21
22
|
import { resolveRestRegion } from './rest-sources.ts';
|
|
22
23
|
import { checksumValid, signText } from '../security.ts';
|
|
@@ -409,6 +410,18 @@ export async function withComputations(ctx: PageContext, r: Region, src: string,
|
|
|
409
410
|
return { src: exprs.length ? `select "__s".*, ${exprs.join(', ')} from (\n${src}\n) "__s"` : src, errors };
|
|
410
411
|
}
|
|
411
412
|
|
|
413
|
+
/**
|
|
414
|
+
* (135) The tsvector column a report's search also uses: the one its attributes name (`fulltext`, which may be a
|
|
415
|
+
* hidden column: the developer chose it), else the only tsvector column the user may see; null when there is none.
|
|
416
|
+
*/
|
|
417
|
+
export function fulltextColumn(r: Pick<Region, 'config'>, fields: { name: string; dataTypeID: number }[], userCols: Map<string, number>) {
|
|
418
|
+
const TSVECTOR = 3614;
|
|
419
|
+
const named = typeof r.config.fulltext === 'string' ? r.config.fulltext : null;
|
|
420
|
+
if (named) return fields.find((f) => f.name === named && f.dataTypeID === TSVECTOR)?.name ?? null;
|
|
421
|
+
const shown = fields.filter((f) => f.dataTypeID === TSVECTOR && userCols.has(f.name));
|
|
422
|
+
return shown.length === 1 ? shown[0].name : null;
|
|
423
|
+
}
|
|
424
|
+
|
|
412
425
|
/**
|
|
413
426
|
* The report's query with the user's search, filters and facets applied:
|
|
414
427
|
* the source, the WHERE clause, and the result's column names (only looked
|
|
@@ -422,14 +435,25 @@ export async function filtered(ctx: PageContext, r: Region, st: ReportState) {
|
|
|
422
435
|
const p = new SqlParams();
|
|
423
436
|
const hides = hidesColumns(r);
|
|
424
437
|
const facets = facetFilters(ctx.params, r.id, reportFacetDefs(ctx.page.regions, r.id, ctx.vis?.regions), undefined, appDateReader(ctx));
|
|
425
|
-
const needCols = st.filters.length || facets.length || st.breakCol || st.aggregates.length || st.highlights.length || st.view !== 'report' || st.area || st.near || keysetColumns(r) || (hides && (st.search || st.sort)) ||
|
|
438
|
+
const needCols = st.filters.length || facets.length || st.breakCol || st.aggregates.length || st.highlights.length || st.view !== 'report' || st.area || st.near || keysetColumns(r) || (hides && (st.search || st.sort)) || st.search;
|
|
426
439
|
// column name → type oid
|
|
427
440
|
const fields = needCols ? await fieldsOf(ctx, src) : [];
|
|
428
441
|
const cols = new Map<string, number>(fields.map((f) => [f.name, f.dataTypeID]));
|
|
429
442
|
// the columns the user may choose (filters, highlights, control break, aggregates, views, sorting): not the hidden ones
|
|
430
443
|
const userCols = new Map<string, number>(userColumnNames(r, [...cols.keys()]).map((n) => [n, cols.get(n)!]));
|
|
431
444
|
// (sprint 76) the search in one column the user may see, or in all
|
|
432
|
-
if (st.search)
|
|
445
|
+
if (st.search) {
|
|
446
|
+
const oneCol = !!st.searchCol && userCols.has(st.searchCol);
|
|
447
|
+
let cond = searchSql(st.search, p, oneCol ? [st.searchCol!] : hides ? [...userCols.keys()] : undefined);
|
|
448
|
+
// (135) a tsvector column in the source: the search also finds rows by full-text search (stemmed words,
|
|
449
|
+
// "phrases", or, -word), with a text search configuration from pg_ts_config as a query parameter
|
|
450
|
+
const fts = oneCol ? null : fulltextColumn(r, fields, userCols);
|
|
451
|
+
if (fts) {
|
|
452
|
+
const cfg = await textSearchConfig(ctx.client!, typeof r.config.fulltext_config === 'string' ? r.config.fulltext_config : null, ctx.app.language);
|
|
453
|
+
cond = `(${cond} or ${q(fts)} @@ websearch_to_tsquery(${p.add(cfg, 'regconfig')}, ${p.add(st.search, 'text')}))`;
|
|
454
|
+
}
|
|
455
|
+
where.push(cond);
|
|
456
|
+
}
|
|
433
457
|
for (const f of st.filters) if (userCols.has(f.column)) where.push(OPERATORS[f.op].sql(q(f.column), f.value));
|
|
434
458
|
for (const f of facets) {
|
|
435
459
|
const cond = facetFilterSql(f, cols, p);
|