From 53416f516348785bd6ee9d0a153834af783cf346 Mon Sep 17 00:00:00 2001 From: James Maes Date: Mon, 12 Oct 2026 14:13:00 -0500 Subject: [PATCH] feat!: snake_case table, PVS and permission names (owner naming rule) Owner rule (2026-10-12): "table names should always be lowercase and use _, and qbits should always be prefixed with their name". For 1.1.0-RC.3, metadata only (the QBit ships no DDL): - tables: quick_search_index, quick_search_index_run, quick_search_failed_event, quick_search_diagnostic_event, quick_search_validation_run (were camelCase) - possible-value sources: quick_search_index, quick_search_searchable_table - permission bases: quick_search_admin, quick_search_debug; table permissions follow the table names - applyTablePrefix: a host prefix is snake_cased and joined with "_" (myApp -> my_app_quick_search_index); processes, widgets and apps keep applyPrefix - @Deprecated LEGACY_* constants keep the old names for upgrade scripts - docs/MIGRATION-1.1.md: upgrade steps, ALTER TABLE for camelCase databases, UPDATEs for audit_table, saved views and reports, permission grants; no reindex needed - QuickSearchTableNamesTest covers new names, legacy constants and prefixing Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 4 +- CHANGELOG.md | 3 + CLAUDE.md | 4 +- README.md | 30 +++---- docs/MIGRATION-1.1.md | 72 ++++++++++++++- .../quicksearch/QuickSearchQBitConfig.java | 52 +++++++++-- .../qbits/quicksearch/QuickSearchRuntime.java | 4 +- .../diagnostics/DiagnosticEventRecorder.java | 4 +- .../diagnostics/DiagnosticsSupport.java | 2 +- .../diagnostics/IndexValidator.java | 10 +-- .../QuickSearchDeveloperPanelProvider.java | 2 +- .../QuickSearchDiagnosticsWidgetRenderer.java | 4 +- .../QuickSearchRecordChangeListener.java | 20 ++--- .../QuickSearchAdminAppMetaDataProducer.java | 2 +- ...hDiagnosticEventTableMetaDataProducer.java | 2 +- ...earchDiagnosticsProcessMetaDataHelper.java | 4 +- ...earchFailedEventTableMetaDataProducer.java | 2 +- ...earchIndexPossibleValueSourceProducer.java | 2 +- ...ckSearchIndexRunTableMetaDataProducer.java | 2 +- ...QuickSearchIndexTableMetaDataProducer.java | 2 +- .../QuickSearchProcessMetaDataHelper.java | 2 +- ...hableTablePossibleValueSourceProducer.java | 8 +- .../QuickSearchTableMetaDataHelper.java | 26 +++--- ...rchValidationRunTableMetaDataProducer.java | 2 +- .../model/QuickSearchDiagnosticEvent.java | 6 +- .../model/QuickSearchFailedEvent.java | 6 +- .../quicksearch/model/QuickSearchIndex.java | 8 +- .../model/QuickSearchIndexRun.java | 8 +- .../model/QuickSearchValidationRun.java | 6 +- .../processes/AbstractIndexingStep.java | 14 +-- .../processes/BasepullIndexStep.java | 8 +- .../processes/FullReindexStep.java | 10 +-- .../AbstractDiagnosticToolStep.java | 2 +- .../diagnostics/ValidateIndexStep.java | 2 +- .../quicksearch/DiagnosticsMetaDataTest.java | 6 +- .../QuickSearchQBitProducerTest.java | 30 +++---- .../QuickSearchTableNamesTest.java | 87 +++++++++++++++++++ .../model/QuickSearchIndexRunTest.java | 2 +- .../model/QuickSearchIndexTest.java | 2 +- 39 files changed, 339 insertions(+), 123 deletions(-) create mode 100644 src/test/java/com/kingsrook/qbits/quicksearch/QuickSearchTableNamesTest.java diff --git a/AGENTS.md b/AGENTS.md index 3013e19..54b6d88 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,13 +31,13 @@ Integration tests use `@ExtendWith(RequiresDockerCondition.class)`: skipped with - `QuickSearchRuntime` - Instance-scoped live state (discovered tables, lazy client, publisher, enabled cache), held on the config and resolved via `QuickSearchRuntime.get()` from `QContext`. `QuickSearchQBitContext` is a deprecated static facade over it. - `opensearch/QuickSearchOpenSearchClient` - All OpenSearch operations; the configured index name is an alias over `{alias}-v2-{epoch}` physical indexes (mapping v2, `_meta.quickSearchMappingVersion`); versioned bulk writes (`external_gte`); alias swap; wraps every error in `QException`. - `opensearch/OpenSearchTransportFactory` - Builds the transport for `NONE`/`BASIC` (Apache HttpClient 5 with TLS, timeouts, customizer SPI) or `AWS_SIGV4` (`AwsSdk2Transport`); resolves `${env.X}` secrets. -- `listeners/QuickSearchRecordChangeListener` - Real-time path: builds events in the write's transaction, publishes after commit, records failures in `quickSearchFailedEvent`. +- `listeners/QuickSearchRecordChangeListener` - Real-time path: builds events in the write's transaction, publishes after commit, records failures in `quick_search_failed_event`. - `processes/AbstractIndexingStep` - Keyset paging by primary key with display values, run records, drift detection, run purge. `BasepullIndexStep` (replays failed events, start-anchored watermark with overlap), `ReconcileIndexStep` (in place, orphan sweep), `FullReindexStep` (all tables: new physical index plus alias swap; one table: reconcile algorithm). - `actions/QuickSearchAction` - Permission-aware search (table READ filter, `QueryAction` post-filter), bounds, `tableNames`, `limitPerTable`, `tableLabel`. - `actions/QuickSearchRecordSearchProvider` - QQQ core `RecordSearchProviderInterface` (`POST /qqq/v1/search`): claims indexed, enabled tables; one `_msearch` per call returning ordered record ids per table; bounded by `recordSearchTimeoutMillis`; failures make core fall back and start a 30 s backoff (`QuickSearchRuntime.markRecordSearchFailed`). Registered, with default table `searchFields`, when `serveCoreRecordSearch` is true. - `metadata/*` - Component producers and the table/process helpers. -**Tables Produced:** `quickSearchIndex`, `quickSearchIndexRun`, `quickSearchFailedEvent` (plus a PVS over `quickSearchIndex`). +**Tables Produced:** `quick_search_index`, `quick_search_index_run`, `quick_search_failed_event` (plus a PVS over `quick_search_index`). **Annotation Discovery:** `@QuickSearchable(tableName = "...")` on entity classes; `@QuickSearchField(weight, includeLabel)` on fields; hidden fields are excluded. diff --git a/CHANGELOG.md b/CHANGELOG.md index c25bdb2..b012924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ Requires QQQ 4.1.0-RC.4 or later (the developer panel contract, QRun-IO/qqq#1076 ### Added - Record developer panel: `QuickSearchDeveloperPanelProvider` (id `quickSearch`) adds a "Quick Search" panel to the developer view of every record of an indexed table (`/app/{table}/{id}/dev` in the Next UI), for users who may read Quick Search Index. It shows the table's index row (enabled, status, record count, last basepull and full reindex, searchable fields), the latest index run, the record's indexed document compared field by field with the database (Inspect Search Document's comparison; needs `debugPermissionRules`), the record's failed index events, the Inspect Search Document and Reindex in Search actions the user may run, and links to the admin app and the index row. An unreachable OpenSearch shows a warning in the panel. Registered by `QuickSearchDeveloperPanelsMetaDataProducer`. +### Changed +- **Snake_case names (owner naming rule, 2026-10-12), for 1.1.0-RC.3.** The tables are now `quick_search_index`, `quick_search_index_run`, `quick_search_failed_event`, `quick_search_diagnostic_event` and `quick_search_validation_run` (they were camelCase). The possible-value sources are `quick_search_index` and `quick_search_searchable_table`. The permission bases are `quick_search_admin` and `quick_search_debug`, and table permissions follow the table names. A table-name prefix is now converted to snake_case and joined with `_`. The old names remain as `@Deprecated` `LEGACY_*` constants. This is metadata only: the QBit ships no DDL. Upgrade steps, with SQL for camelCase databases and for stored references (audit table names, saved views, permission grants), are in `docs/MIGRATION-1.1.md` under "Snake_case names (1.1.0-RC.3)". + ## [1.1.0-RC.1] - 2026-10-11 First release candidate of 1.1, published to Maven Central from `release/1.1`. It contains every change listed under 1.1.0 and 1.0.0 below (1.0.0 has not been released as GA). Requires QQQ 4.1.0-RC.2 or later. Upgrade notes: `docs/MIGRATION-1.1.md`. diff --git a/CLAUDE.md b/CLAUDE.md index 8e39d26..6fd6eab 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -31,13 +31,13 @@ Integration tests use `@ExtendWith(RequiresDockerCondition.class)`: skipped with - `QuickSearchRuntime` - Instance-scoped live state (discovered tables, lazy client, publisher, enabled cache), held on the config and resolved via `QuickSearchRuntime.get()` from `QContext`. `QuickSearchQBitContext` is a deprecated static facade over it. - `opensearch/QuickSearchOpenSearchClient` - All OpenSearch operations; the configured index name is an alias over `{alias}-v2-{epoch}` physical indexes (mapping v2, `_meta.quickSearchMappingVersion`); versioned bulk writes (`external_gte`); alias swap; wraps every error in `QException`. - `opensearch/OpenSearchTransportFactory` - Builds the transport for `NONE`/`BASIC` (Apache HttpClient 5 with TLS, timeouts, customizer SPI) or `AWS_SIGV4` (`AwsSdk2Transport`); resolves `${env.X}` secrets. -- `listeners/QuickSearchRecordChangeListener` - Real-time path: builds events in the write's transaction, publishes after commit, records failures in `quickSearchFailedEvent`. +- `listeners/QuickSearchRecordChangeListener` - Real-time path: builds events in the write's transaction, publishes after commit, records failures in `quick_search_failed_event`. - `processes/AbstractIndexingStep` - Keyset paging by primary key with display values, run records, drift detection, run purge. `BasepullIndexStep` (replays failed events, start-anchored watermark with overlap), `ReconcileIndexStep` (in place, orphan sweep), `FullReindexStep` (all tables: new physical index plus alias swap; one table: reconcile algorithm). - `actions/QuickSearchAction` - Permission-aware search (table READ filter, `QueryAction` post-filter), bounds, `tableNames`, `limitPerTable`, `tableLabel`. - `actions/QuickSearchRecordSearchProvider` - QQQ core `RecordSearchProviderInterface` (`POST /qqq/v1/search`): claims indexed, enabled tables; one `_msearch` per call returning ordered record ids per table; bounded by `recordSearchTimeoutMillis`; failures make core fall back and start a 30 s backoff (`QuickSearchRuntime.markRecordSearchFailed`). Registered, with default table `searchFields`, when `serveCoreRecordSearch` is true. - `metadata/*` - Component producers and the table/process helpers. -**Tables Produced:** `quickSearchIndex`, `quickSearchIndexRun`, `quickSearchFailedEvent` (plus a PVS over `quickSearchIndex`). +**Tables Produced:** `quick_search_index`, `quick_search_index_run`, `quick_search_failed_event` (plus a PVS over `quick_search_index`). **Annotation Discovery:** `@QuickSearchable(tableName = "...")` on entity classes; `@QuickSearchField(weight, includeLabel)` on fields; hidden fields are excluded. diff --git a/README.md b/README.md index 6b97e28..9db739c 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ Requires QQQ 4.1 (the QBit uses 4.1's record-change listeners, after-commit call | Capability | How | |---|---| -| Real-time indexing | One `RecordChangeListenerInterface` registered on the instance; events are published after the write's transaction commits, so rolled-back writes never reach the index. Failures are recorded in `quickSearchFailedEvent` and replayed by the scheduled basepull. | +| Real-time indexing | One `RecordChangeListenerInterface` registered on the instance; events are published after the write's transaction commits, so rolled-back writes never reach the index. Failures are recorded in `quick_search_failed_event` and replayed by the scheduled basepull. | | Basepull catch-up | Scheduled process (`schedulerName` plus `basepullRepeatSeconds`) that re-indexes rows changed since the previous run's start, with a configurable overlap, paging by primary key. | | Reconcile | Scheduled or on-demand process that re-indexes everything in place, then removes documents whose source row is gone, including documents of tables no longer configured. No search blackout. | | Full rebuild | Indexes every table into a fresh physical index and atomically swaps the alias; the old index keeps serving until the new one is complete. Also upgrades an index created by an older release. | | Core search | `QuickSearchRecordSearchProvider` serves QQQ's `RecordSearchAction` (`POST /qqq/v1/search`, the Next UI global search box) from OpenSearch for the indexed tables, with a timeout and an automatic fallback to core's own search. | | Search | `QuickSearchAction`: AND semantics, edge-ngram typeahead with a plain search analyzer, per-field weights, highlights, `tableNames` and `limitPerTable`, bounded paging, `tableLabel` on results. Only tables the session may read are searched; hits are re-read through `QueryAction` so record security locks apply. | | Connections | HTTP or HTTPS, basic auth, AWS IAM SigV4, custom CA or trust store, mTLS, timeouts, pool size, a transport customizer SPI for anything else. Secrets by `${env.X}` reference. | -| Operations | `quickSearchIndex` (per-table status, counts, last run, last error), `quickSearchIndexRun` (history, purged after `runHistoryRetentionDays`), `quickSearchFailedEvent`, a `quickSearchAdmin` app, explicit permission rules, fail-fast or degraded startup. | +| Operations | `quick_search_index` (per-table status, counts, last run, last error), `quick_search_index_run` (history, purged after `runHistoryRetentionDays`), `quick_search_failed_event`, a `quickSearchAdmin` app, explicit permission rules, fail-fast or degraded startup. | ## Supported platforms @@ -129,7 +129,7 @@ Search runs as the current `QContext` session: tables the session cannot read ar QQQ core has its own record search (`RecordSearchAction`, served at `POST /qqq/v1/search` and used by the Next UI's global search box): a case-insensitive contains-query over each table's `searchFields`. With `serveCoreRecordSearch` (default `true`) the producer registers `QuickSearchRecordSearchProvider` on the instance, and core asks it to search every table Quick Search indexes. The API and the UI do not change. -- **What is served from OpenSearch.** Tables this QBit indexes and that are enabled in `quickSearchIndex`. Core offers a table only when it has `searchFields`, the session may read it, and it supports query, so the producer gives each indexed table that has no `searchFields` its visible string and integer searchable fields (never hidden or password fields). `searchFields` you set yourself are kept. A table must be in the `QInstance` before the QBit is produced to get them. +- **What is served from OpenSearch.** Tables this QBit indexes and that are enabled in `quick_search_index`. Core offers a table only when it has `searchFields`, the session may read it, and it supports query, so the producer gives each indexed table that has no `searchFields` its visible string and integer searchable fields (never hidden or password fields). `searchFields` you set yourself are kept. A table must be in the `QInstance` before the QBit is produced to get them. - **How.** One `_msearch` request with one search per table (Quick Search's query, AND semantics and field weights); each table returns up to 4 x `limitPerTable` record ids (at most 100) in relevance order. Core re-reads them by primary key through `QueryAction`, so table permissions, record security locks and record labels are core's, and records deleted since they were indexed drop out. - **Failure.** The OpenSearch request is cancelled after `recordSearchTimeoutMillis` (default 2500). Any failure (timeout, cluster down, index missing) makes core search those tables with its own contains-query instead, so search degrades but never fails. After a failure, Quick Search claims no tables for 30 seconds, so a down cluster does not add a timeout to every search. - **Opting out.** `withServeCoreRecordSearch(false)` leaves core search and `searchFields` untouched. If the host already registered another record-search provider, the QBit keeps it and logs a warning (an instance has one provider). @@ -162,12 +162,12 @@ config.withSchedulerName("quartz") ### Diagnostic tools -With `enableDiagnosticTools` (default `true`) the QBit adds tools to validate the search and debug it from the admin UI. They are table and record actions (never left-nav entries), gated by permissions, recorded in `quickSearchDiagnosticEvent`, limited to `diagnosticRunsPerMinute` runs per user and tool, and read-only except Reindex in Search. +With `enableDiagnosticTools` (default `true`) the QBit adds tools to validate the search and debug it from the admin UI. They are table and record actions (never left-nav entries), gated by permissions, recorded in `quick_search_diagnostic_event`, limited to `diagnosticRunsPerMinute` runs per user and tool, and read-only except Reindex in Search. | Tool | Where | What it does | |---|---|---| | Search Playground | Quick Search Index, Actions (select rows to pre-fill their tables) | Runs a term the way the global search does, as you: the path each table takes (OpenSearch provider, core database search, or not searched) and why; the provider's own request, timed; the global search results you would see; per indexed table, the production query with scores, highlights, matched fields, which hits you can read and which the global search shows, the query DSL and the raw response (hits you cannot read are redacted); the term's tokens; and `explain` for a hit (`table:id`). The form stays open, so you can change the term and run again. | -| Validate Search Index | Quick Search Index, Actions; also scheduled by `validationCronExpression` | Cluster and index health, the alias, leftover physical indexes from interrupted rebuilds, the live mapping (version, field types, analyzers, the `fieldValues` template) and analysis settings, then per table: database rows vs documents, a sample of records checked present and current in the index, a random sample of documents checked to still have a record, the index row's status and last run, and waiting failed events. Each finding is OK, INFO, WARN or FAIL with what to do. The report is saved as a `quickSearchValidationRun` row (HTML for the record view, JSON for tools). Database reads run as the system user so counts compare like with like; the report holds counts, ids and field names, never record values. One validation runs at a time per server. | +| Validate Search Index | Quick Search Index, Actions; also scheduled by `validationCronExpression` | Cluster and index health, the alias, leftover physical indexes from interrupted rebuilds, the live mapping (version, field types, analyzers, the `fieldValues` template) and analysis settings, then per table: database rows vs documents, a sample of records checked present and current in the index, a random sample of documents checked to still have a record, the index row's status and last run, and waiting failed events. Each finding is OK, INFO, WARN or FAIL with what to do. The report is saved as a `quick_search_validation_run` row (HTML for the record view, JSON for tools). Database reads run as the system user so counts compare like with like; the report holds counts, ids and field names, never record values. One validation runs at a time per server. | | Test Search Analyzer | Quick Search Index, Actions | `_analyze` on the live index: the tokens of a text as indexed (edge n-grams of 2 to 20 characters) and as a query, and, given a term, whether every term token is among the text's indexed tokens. | | Inspect Search Document | Every indexed table's records (Actions), and Quick Search Failed Event rows | The record's document in the index next to the document indexing would write from the database now, field by field (current, stale or missing), with versions and the raw document. Enter a term to see why the record does or does not match it: term length, table enabled, read permission, document present and current, each term token found or not (and why: one character, longer than 20, not in the text, or only in the database's newer values), `explain`, and the record's rank against the number of ids the global search takes. | | Reindex in Search | Every indexed table's records, and Quick Search Failed Event rows | Rebuild the selected records' documents from the database now (versioned writes, so a newer document is never overwritten); a record that no longer exists has its document removed; a record you cannot read is skipped. Asks to confirm. Needs the admin permission. | @@ -175,7 +175,7 @@ With `enableDiagnosticTools` (default `true`) the QBit adds tools to validate th Search failures are recorded too: when the provider's OpenSearch request fails or times out (and core falls back to its own search), or `QuickSearchAction`'s search fails, a `SEARCH_FAILED` event keeps the tables, duration, error class and message, and the server. The user's term is never stored, only its length. At most 120 events are written per server per minute. -Permissions: the read-only tools and the widget use `debugPermissionRules` (default `quickSearchDebug.hasAccess`); Reindex in Search uses `adminPermissionRules` (`quickSearchAdmin.hasAccess`); the two history tables use `tablePermissionRules` (grant `.read` only: rows are written by the QBit). Impersonation ("search as user X") is deliberately not offered: a fabricated session would not carry the real user's security key values, so its results would mislead. +Permissions: the read-only tools and the widget use `debugPermissionRules` (default `quick_search_debug.hasAccess`); Reindex in Search uses `adminPermissionRules` (`quick_search_admin.hasAccess`); the two history tables use `tablePermissionRules` (grant `.read` only: rows are written by the QBit). Impersonation ("search as user X") is deliberately not offered: a fabricated session would not carry the real user's security key values, so its results would mislead. ### Record developer panel @@ -220,13 +220,13 @@ The panel's status is Indexed, Stale, Not indexed, Disabled (the table is turned | `applyRecordSecurityLocks` | `true` | Re-read hits through `QueryAction` | | `serveCoreRecordSearch` | `true` | Register `QuickSearchRecordSearchProvider` so core `POST /qqq/v1/search` uses OpenSearch for indexed tables, and give those tables `searchFields` when they have none | | `recordSearchTimeoutMillis` | 2500 | Wall-clock limit on the OpenSearch request behind a core search; past it, core falls back to its own search | -| `enableDiagnosticTools` | `true` | Add the diagnostic tools, the `quickSearchDiagnosticEvent` and `quickSearchValidationRun` tables and the diagnostics widget | +| `enableDiagnosticTools` | `true` | Add the diagnostic tools, the `quick_search_diagnostic_event` and `quick_search_validation_run` tables and the diagnostics widget | | `enableRecordDiagnosticActions` | `true` | With the tools on, add Inspect Search Document and Reindex in Search to every indexed table | | `validationCronExpression`, `validationCronTimeZoneId` | none | Schedule Validate Search Index; same rules as the reconcile schedule (a cron-capable scheduler such as Quartz, a valid Quartz expression, a time zone ID) | | `validationSampleSize` | 50 | Records and documents sampled per table by validation (at most 1000) | | `diagnosticRunsPerMinute` | 30 | Per-user, per-tool limit on diagnostic runs | -| `debugPermissionRules` | `HAS_ACCESS_PERMISSION`, base name `quickSearchDebug` | Rules for the read-only diagnostic tools and the widget | -| `adminPermissionRules` | `HAS_ACCESS_PERMISSION`, base name `quickSearchAdmin` | Rules for the app, the maintenance processes and Reindex in Search | +| `debugPermissionRules` | `HAS_ACCESS_PERMISSION`, base name `quick_search_debug` | Rules for the read-only diagnostic tools and the widget | +| `adminPermissionRules` | `HAS_ACCESS_PERMISSION`, base name `quick_search_admin` | Rules for the app, the maintenance processes and Reindex in Search | | `tablePermissionRules` | `READ_WRITE_PERMISSIONS` | Rules for the operational tables | | `tableMetaDataCustomizer` | | Applied to every produced table (backend details, for example) | | `searchableEntityClasses`, `searchableTables` | at least one | What to index | @@ -236,11 +236,11 @@ The panel's status is Indexed, Stale, Not indexed, Disabled (the table is turned ## Operational tables -- `quickSearchIndex`: one row per table with `enabled` (honoured by indexing and search, cached for one minute), `basepullIntervalMinutes`, `lastBasepullTime`, `lastReconcileTime`, `lastFullReindexTime`, `lastRunStatus`, `lastErrorMessage`, `recordCount`, `documentCount`, `realTimeErrorCount`, `status` (`ACTIVE`, `NEEDS_REINDEX` when the configured fields changed since the row was created, or `REBUILDING` while a full reindex of all tables runs). Unique on `tableName`. -- `quickSearchIndexRun`: `runType` (`BASEPULL`, `RECONCILE`, `FULL_REINDEX`), `status`, counts, `errorMessage`. -- `quickSearchDiagnosticEvent` (with `enableDiagnosticTools`): `eventType` (`SEARCH_FAILED`, `TOOL_RUN`, `REINDEX`, `RATE_LIMITED`), `source`, `outcome`, `userName`, `tableNames`, `searchTerm` (tool runs only), `durationMillis`, `errorClass`, `errorMessage` (text), `detail` (text), `hostName`, `createDate`. Purged after `runHistoryRetentionDays`. -- `quickSearchValidationRun` (with `enableDiagnosticTools`): `status` (`PASS`, `WARN`, `FAIL`), `triggerType` (`MANUAL`, `SCHEDULED`), `userName`, `tableNames`, `sampleSize`, `tablesChecked`, `failCount`, `warnCount`, `summary`, `reportHtml` (HTML), `reportJson` (text), `startTime`, `endTime`, `createDate`. Purged after `runHistoryRetentionDays`. -- `quickSearchFailedEvent`: real-time events that could not be applied; `status` `PENDING` or `EXHAUSTED` after 10 attempts. Deletes made while a full reindex of all tables runs are also recorded here with status `AWAITING_REINDEX`: the reindex applies them to the new index after the alias swap (basepull does not replay them). While a table is `REBUILDING`, drift detection is suspended for it. Only one full reindex runs at a time: starting one while another is running fails. A full reindex shows it is running through its `FULL_REINDEX` run records, which stay `RUNNING` with `modifyDate` refreshed after every page. If it is killed mid-run (pod restart, OOM, deploy), recovery is automatic once its run records have shown no sign of life for `fullReindexStaleMinutes` (30 by default): the next basepull, or the next full reindex, marks those run records `FAILED`, returns the tables to `ACTIVE` with `lastBasepullTime` moved back to the run's start, and turns the `AWAITING_REINDEX` rows `PENDING` so basepull replays the deletes. No data is lost. A run that was only slow and is judged stopped notices before its alias swap and fails without swapping, or, after its swap, stops applying its captured deletes; basepull skips a replayed delete whose record exists again. +- `quick_search_index`: one row per table with `enabled` (honoured by indexing and search, cached for one minute), `basepullIntervalMinutes`, `lastBasepullTime`, `lastReconcileTime`, `lastFullReindexTime`, `lastRunStatus`, `lastErrorMessage`, `recordCount`, `documentCount`, `realTimeErrorCount`, `status` (`ACTIVE`, `NEEDS_REINDEX` when the configured fields changed since the row was created, or `REBUILDING` while a full reindex of all tables runs). Unique on `tableName`. +- `quick_search_index_run`: `runType` (`BASEPULL`, `RECONCILE`, `FULL_REINDEX`), `status`, counts, `errorMessage`. +- `quick_search_diagnostic_event` (with `enableDiagnosticTools`): `eventType` (`SEARCH_FAILED`, `TOOL_RUN`, `REINDEX`, `RATE_LIMITED`), `source`, `outcome`, `userName`, `tableNames`, `searchTerm` (tool runs only), `durationMillis`, `errorClass`, `errorMessage` (text), `detail` (text), `hostName`, `createDate`. Purged after `runHistoryRetentionDays`. +- `quick_search_validation_run` (with `enableDiagnosticTools`): `status` (`PASS`, `WARN`, `FAIL`), `triggerType` (`MANUAL`, `SCHEDULED`), `userName`, `tableNames`, `sampleSize`, `tablesChecked`, `failCount`, `warnCount`, `summary`, `reportHtml` (HTML), `reportJson` (text), `startTime`, `endTime`, `createDate`. Purged after `runHistoryRetentionDays`. +- `quick_search_failed_event`: real-time events that could not be applied; `status` `PENDING` or `EXHAUSTED` after 10 attempts. Deletes made while a full reindex of all tables runs are also recorded here with status `AWAITING_REINDEX`: the reindex applies them to the new index after the alias swap (basepull does not replay them). While a table is `REBUILDING`, drift detection is suspended for it. Only one full reindex runs at a time: starting one while another is running fails. A full reindex shows it is running through its `FULL_REINDEX` run records, which stay `RUNNING` with `modifyDate` refreshed after every page. If it is killed mid-run (pod restart, OOM, deploy), recovery is automatic once its run records have shown no sign of life for `fullReindexStaleMinutes` (30 by default): the next basepull, or the next full reindex, marks those run records `FAILED`, returns the tables to `ACTIVE` with `lastBasepullTime` moved back to the run's start, and turns the `AWAITING_REINDEX` rows `PENDING` so basepull replays the deletes. No data is lost. A run that was only slow and is judged stopped notices before its alias swap and fails without swapping, or, after its swap, stops applying its captured deletes; basepull skips a replayed delete whose record exists again. ## Extending @@ -262,7 +262,7 @@ See [docs/MIGRATION-1.1.md](docs/MIGRATION-1.1.md). In short: 1.1 needs the QQQ ## Upgrading from 0.x -See [docs/MIGRATION-1.0.md](docs/MIGRATION-1.0.md). In short: QQQ 4.1 is required, remove any manual `addQBit` for this QBit, set `schedulerName`, prefer `opensearchUrl` and `${env.}` secrets, grant `quickSearchAdmin.hasAccess` and the table permissions, add the new operational table columns and `quickSearchFailedEvent`, and run a full reindex once so the index gets the new mapping. +See [docs/MIGRATION-1.0.md](docs/MIGRATION-1.0.md). In short: QQQ 4.1 is required, remove any manual `addQBit` for this QBit, set `schedulerName`, prefer `opensearchUrl` and `${env.}` secrets, grant `quick_search_admin.hasAccess` and the table permissions, add the new operational table columns and `quick_search_failed_event`, and run a full reindex once so the index gets the new mapping. ## Adopting in another app diff --git a/docs/MIGRATION-1.1.md b/docs/MIGRATION-1.1.md index 4bb8a0e..dd54021 100644 --- a/docs/MIGRATION-1.1.md +++ b/docs/MIGRATION-1.1.md @@ -33,7 +33,75 @@ restores 1.0 behaviour: no provider, no `searchFields` changes. The QBit now adds admin tools to validate and debug search (see the README, "Diagnostic tools"). They are on by default. -- **Two new operational tables**, on `backendName` like the others: `quickSearchDiagnosticEvent` and `quickSearchValidationRun` (columns in the README, "Operational tables"). Create them in the host's schema, with the naming the host applies to the other operational tables (`tableMetaDataCustomizer` applies to them too). Until they exist, writing events and saving reports fails quietly (logged at warn) and the tools still run. -- **Permissions.** Grant `quickSearchDebug.hasAccess` to the people who may use the read-only tools and see the widget, `quickSearchAdmin.hasAccess` for Reindex in Search, and `.read` on the two new tables (the QBit writes them; users never do). +- **Two new operational tables**, on `backendName` like the others: `quick_search_diagnostic_event` and `quick_search_validation_run` (columns in the README, "Operational tables"). Create them in the host's schema, with the naming the host applies to the other operational tables (`tableMetaDataCustomizer` applies to them too). Until they exist, writing events and saving reports fails quietly (logged at warn) and the tools still run. +- **Permissions.** Grant `quick_search_debug.hasAccess` to the people who may use the read-only tools and see the widget, `quick_search_admin.hasAccess` for Reindex in Search, and `.read` on the two new tables (the QBit writes them; users never do). - **New processes** have a `tableName` (Quick Search Index, Quick Search Failed Event, and each indexed table), so they appear as table and record actions. They are not added to the admin app's children; a host that strips processes from its nav needs no change. - **Opting out.** `withEnableDiagnosticTools(false)` adds none of it; `withEnableRecordDiagnosticActions(false)` keeps the tools on Quick Search Index but adds nothing to the indexed tables. + +## Snake_case names (1.1.0-RC.3) + +Owner naming rule (2026-10-12): table names are lowercase snake_case, and a QBit's tables are prefixed with its full name. RC.3 renames the QQQ metadata names. The QBit ships no DDL, so nothing is dropped or rewritten; what you change depends on how your database tables are named today. + +| Kind | Before (RC.1, RC.2) | From RC.3 | +|---|---|---| +| Table | `quickSearchIndex` | `quick_search_index` | +| Table | `quickSearchIndexRun` | `quick_search_index_run` | +| Table | `quickSearchFailedEvent` | `quick_search_failed_event` | +| Table | `quickSearchDiagnosticEvent` | `quick_search_diagnostic_event` | +| Table | `quickSearchValidationRun` | `quick_search_validation_run` | +| Possible-value source | `quickSearchIndex`, `quickSearchSearchableTable` | `quick_search_index`, `quick_search_searchable_table` | +| Table permissions | `quickSearchIndex.read`, `quickSearchIndexRun.read`, ... | `quick_search_index.read`, `quick_search_index_run.read`, ... | +| Admin permission | `quickSearchAdmin.hasAccess` | `quick_search_admin.hasAccess` | +| Debug permission | `quickSearchDebug.hasAccess` | `quick_search_debug.hasAccess` | +| Record actions on failed events | `quickSearchInspect_quickSearchFailedEvent`, `quickSearchReindexRecords_quickSearchFailedEvent` | `quickSearchInspect_quick_search_failed_event`, `quickSearchReindexRecords_quick_search_failed_event` | + +Unchanged: Java class names, field names (`quickSearchIndexId`, `tableName`), process, widget and app names (`quickSearchFullReindex`, `quickSearchDiagnostics`, `quickSearchAdmin` app), the OpenSearch index, and the developer panel id. + +**With a table-name prefix** (`withTableNamePrefix` or the producer namespace), table and possible-value source names are now the prefix in snake_case joined with `_`: prefix `myApp_` or `myApp` gives `my_app_quick_search_index`, where RC.2 gave `myApp_quickSearchIndex`. Process, widget and app names keep the prefix as given. + +**The old names stay available** as `@Deprecated` constants for upgrade scripts: `QuickSearchIndex.LEGACY_TABLE_NAME` (and the same on the other four entities), `QuickSearchSearchableTablePossibleValueSourceProducer.LEGACY_NAME`, and `QuickSearchQBitConfig.LEGACY_ADMIN_PERMISSION_BASE_NAME` / `LEGACY_DEBUG_PERMISSION_BASE_NAME`. They will be removed in 2.0. + +### Database tables + +- **Your tables are already `quick_search_*`** (for example you set the RDBMS backend name with `inferBackendName` or a table customizer): no DDL. You can drop the customizer, since the QQQ name now equals the database name. +- **Your tables are camelCase** (`"quickSearchIndex"`): rename them, in a maintenance window, before starting RC.3. PostgreSQL example: + +```sql +ALTER TABLE "quickSearchIndex" RENAME TO quick_search_index; +ALTER TABLE "quickSearchIndexRun" RENAME TO quick_search_index_run; +ALTER TABLE "quickSearchFailedEvent" RENAME TO quick_search_failed_event; +ALTER TABLE "quickSearchDiagnosticEvent" RENAME TO quick_search_diagnostic_event; +ALTER TABLE "quickSearchValidationRun" RENAME TO quick_search_validation_run; +``` + + Rename the matching sequences, indexes and constraints the same way if your tooling depends on their names. Data is untouched. If you cannot rename yet, point each table at its old name with an `RDBMSTableBackendDetails` table name in a table customizer. + +### Stored references + +QQQ stores table, process and permission names in your own data. Update them in the same window (PostgreSQL examples; adjust schema and column names to your instance): + +```sql +-- audit history: audit_table.name holds the QQQ table name +UPDATE audit_table SET name = 'quick_search_index' WHERE name = 'quickSearchIndex'; +UPDATE audit_table SET name = 'quick_search_index_run' WHERE name = 'quickSearchIndexRun'; +UPDATE audit_table SET name = 'quick_search_failed_event' WHERE name = 'quickSearchFailedEvent'; +UPDATE audit_table SET name = 'quick_search_diagnostic_event' WHERE name = 'quickSearchDiagnosticEvent'; +UPDATE audit_table SET name = 'quick_search_validation_run' WHERE name = 'quickSearchValidationRun'; + +-- saved views and saved reports +UPDATE saved_view SET table_name = 'quick_search_index' WHERE table_name = 'quickSearchIndex'; +UPDATE saved_report SET table_name = 'quick_search_index' WHERE table_name = 'quickSearchIndex'; +-- ... and the same for the other four tables +``` + +- **Permission grants.** Wherever your roles live (QQQ role tables, an identity provider's group attributes, code), replace `quickSearchAdmin.hasAccess` with `quick_search_admin.hasAccess`, `quickSearchDebug.hasAccess` with `quick_search_debug.hasAccess`, and `quickSearchIndex.read` / `.edit` (and the other tables' permissions) with the `quick_search_*` names. Users without the new grants lose the admin app and tools until they are granted. +- **Bookmarks and links** to `/app/quickSearchIndex/...` move to `/app/quick_search_index/...`. +- **Index rows and failed events** store *your* table names (`quick_search_index.table_name`, `quick_search_failed_event.table_name`), not the QBit's, so they need no change for this rename. The OpenSearch documents are keyed by your tables too, so **no reindex is needed**. If you rename your own tables at the same time, update those two columns and run a full reindex. + +### Checklist + +1. Back up the database. +2. Rename the tables (only if they are camelCase) and update the stored references above. +3. Update permission grants. +4. Upgrade to RC.3 and start; `startupMode` `FAIL_FAST` reports any table the backend cannot find. +5. Open Admin › Quick Search and run Validate Search Index. diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/QuickSearchQBitConfig.java b/src/main/java/com/kingsrook/qbits/quicksearch/QuickSearchQBitConfig.java index 94c792b..36b0489 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/QuickSearchQBitConfig.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/QuickSearchQBitConfig.java @@ -68,10 +68,16 @@ import org.quartz.CronExpression; *******************************************************************************/ public class QuickSearchQBitConfig implements QBitConfig { - public static final String DEFAULT_ADMIN_PERMISSION_BASE_NAME = "quickSearchAdmin"; + public static final String DEFAULT_ADMIN_PERMISSION_BASE_NAME = "quick_search_admin"; public static final String DEFAULT_BASEPULL_TIMESTAMP_FIELD = "modifyDate"; public static final int DEFAULT_RECORD_SEARCH_TIMEOUT_MILLIS = 2500; - public static final String DEFAULT_DEBUG_PERMISSION_BASE_NAME = "quickSearchDebug"; + public static final String DEFAULT_DEBUG_PERMISSION_BASE_NAME = "quick_search_debug"; + /** Admin permission base name before 1.1.0-RC.3 (camelCase). */ + @Deprecated(since = "1.1.0-RC.3") + public static final String LEGACY_ADMIN_PERMISSION_BASE_NAME = "quickSearchAdmin"; + /** Debug permission base name before 1.1.0-RC.3 (camelCase). */ + @Deprecated(since = "1.1.0-RC.3") + public static final String LEGACY_DEBUG_PERMISSION_BASE_NAME = "quickSearchDebug"; public static final int DEFAULT_VALIDATION_SAMPLE_SIZE = 50; public static final int MAX_VALIDATION_SAMPLE_SIZE = 1000; public static final int DEFAULT_DIAGNOSTIC_RUNS_PER_MINUTE = 30; @@ -687,7 +693,35 @@ public class QuickSearchQBitConfig implements QBitConfig /******************************************************************************* - ** Apply the table-name prefix, if any. + ** Apply the table-name prefix to a table or possible-value source name. + ** Table names are lowercase snake_case (owner naming rule, 2026-10-12), so a + ** prefix is converted to snake_case and joined with "_": prefix "acme" and + ** quick_search_index give acme_quick_search_index. + *******************************************************************************/ + public String applyTablePrefix(String name) + { + if(StringUtils.hasContent(tableNamePrefix)) + { + String prefix = toSnakeCase(tableNamePrefix); + return (prefix.endsWith("_") ? prefix : prefix + "_") + name; + } + return name; + } + + + + /******************************************************************************* + ** Convert a camelCase name to lowercase snake_case. + *******************************************************************************/ + static String toSnakeCase(String name) + { + return name.replaceAll("([a-z0-9])([A-Z])", "$1_$2").replace('-', '_').toLowerCase(); + } + + + + /******************************************************************************* + ** Apply the name prefix, if any, to a process, widget or app name. *******************************************************************************/ public String applyPrefix(String name) { @@ -701,21 +735,21 @@ public class QuickSearchQBitConfig implements QBitConfig /******************************************************************************* - ** Name of the produced quickSearchIndex table. + ** Name of the produced quick_search_index table. *******************************************************************************/ public String getQuickSearchIndexTableName() { - return applyPrefix(QuickSearchIndex.TABLE_NAME); + return applyTablePrefix(QuickSearchIndex.TABLE_NAME); } /******************************************************************************* - ** Name of the produced quickSearchIndexRun table. + ** Name of the produced quick_search_index_run table. *******************************************************************************/ public String getQuickSearchIndexRunTableName() { - return applyPrefix(QuickSearchIndexRun.TABLE_NAME); + return applyTablePrefix(QuickSearchIndexRun.TABLE_NAME); } @@ -1818,7 +1852,7 @@ public class QuickSearchQBitConfig implements QBitConfig /******************************************************************************* - ** Getter for runHistoryRetentionDays: delete quickSearchIndexRun rows older than this many days; null keeps them forever + ** Getter for runHistoryRetentionDays: delete quick_search_index_run rows older than this many days; null keeps them forever *******************************************************************************/ public Integer getRunHistoryRetentionDays() { @@ -2458,7 +2492,7 @@ public class QuickSearchQBitConfig implements QBitConfig /******************************************************************************* - ** Getter for debugPermissionRules: permission rules for the read-only diagnostic tools and the diagnostics widget (default: quickSearchDebug.hasAccess) + ** Getter for debugPermissionRules: permission rules for the read-only diagnostic tools and the diagnostics widget (default: quick_search_debug.hasAccess) *******************************************************************************/ public QPermissionRules getDebugPermissionRules() { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/QuickSearchRuntime.java b/src/main/java/com/kingsrook/qbits/quicksearch/QuickSearchRuntime.java index 5162794..5b283c0 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/QuickSearchRuntime.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/QuickSearchRuntime.java @@ -284,7 +284,7 @@ public class QuickSearchRuntime /******************************************************************************* ** Whether a table is enabled for indexing and search, per its - ** quickSearchIndex row. A table with no row yet is enabled. Results are + ** quick_search_index row. A table with no row yet is enabled. Results are ** cached for one minute; a failed lookup is treated as enabled so indexing ** does not stop because the operational table is unreachable. *******************************************************************************/ @@ -493,7 +493,7 @@ public class QuickSearchRuntime /******************************************************************************* - ** Read the enabled flag from the quickSearchIndex row. + ** Read the enabled flag from the quick_search_index row. *******************************************************************************/ private boolean readEnabledFlag(String tableName) { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/DiagnosticEventRecorder.java b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/DiagnosticEventRecorder.java index a6453ad..e72ace3 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/DiagnosticEventRecorder.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/DiagnosticEventRecorder.java @@ -36,7 +36,7 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; /******************************************************************************* - ** Writes quickSearchDiagnosticEvent rows: failed searches, diagnostic tool + ** Writes quick_search_diagnostic_event rows: failed searches, diagnostic tool ** runs (the audit trail) and refused runs. ** Best effort and off the caller's thread: events are queued (at most ** QUEUE_CAPACITY) and inserted by one daemon thread as the system user, so @@ -87,7 +87,7 @@ public class DiagnosticEventRecorder implements AutoCloseable public void record(QuickSearchDiagnosticEvent event) { QInstance qInstance = QContext.getQInstance(); - String tableName = config.applyPrefix(QuickSearchDiagnosticEvent.TABLE_NAME); + String tableName = config.applyTablePrefix(QuickSearchDiagnosticEvent.TABLE_NAME); if(event == null || qInstance == null || !Boolean.TRUE.equals(config.getEnableDiagnosticTools()) || qInstance.getTable(tableName) == null) { return; diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/DiagnosticsSupport.java b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/DiagnosticsSupport.java index cfff441..f74f124 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/DiagnosticsSupport.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/DiagnosticsSupport.java @@ -31,7 +31,7 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; /******************************************************************************* ** Shared pieces of the diagnostic tools: tool names, the current user, the ** per-user rate limit, and recording tool runs and search failures as - ** quickSearchDiagnosticEvent rows (the audit trail). + ** quick_search_diagnostic_event rows (the audit trail). *******************************************************************************/ public final class DiagnosticsSupport { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/IndexValidator.java b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/IndexValidator.java index e40d303..ea7c3e3 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/IndexValidator.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/IndexValidator.java @@ -72,11 +72,11 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; ** - per table: database rows vs indexed documents, a sample of records ** (the lowest and highest primary keys) checked present and current in ** the index, a random sample of documents checked to still have a record, - ** the quickSearchIndex row's status and last run, failed events waiting. + ** the quick_search_index row's status and last run, failed events waiting. ** Database reads run as the system user, so counts compare like with like ** (the index holds every row whatever the record locks). The report holds ** counts, ids and field names, never record values. Read-only, except that - ** persist() saves the report as a quickSearchValidationRun row. + ** persist() saves the report as a quick_search_validation_run row. *******************************************************************************/ public class IndexValidator { @@ -622,7 +622,7 @@ public class IndexValidator { try { - String failedTable = runtime.getConfig().applyPrefix(QuickSearchFailedEvent.TABLE_NAME); + String failedTable = runtime.getConfig().applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME); if(QContext.getQInstance().getTable(failedTable) == null) { return; @@ -646,13 +646,13 @@ public class IndexValidator /******************************************************************************* - ** Save a report as a quickSearchValidationRun row (as the system user); + ** Save a report as a quick_search_validation_run row (as the system user); ** returns its id, or null when the table is not configured or the insert ** fails (logged). *******************************************************************************/ public Integer persist(QuickSearchRuntime runtime, Report report, String triggerType, String userName) { - String tableName = runtime.getConfig().applyPrefix(QuickSearchValidationRun.TABLE_NAME); + String tableName = runtime.getConfig().applyTablePrefix(QuickSearchValidationRun.TABLE_NAME); if(QContext.getQInstance() == null || QContext.getQInstance().getTable(tableName) == null) { return (null); diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/QuickSearchDeveloperPanelProvider.java b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/QuickSearchDeveloperPanelProvider.java index 2be3b0e..c401869 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/QuickSearchDeveloperPanelProvider.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/QuickSearchDeveloperPanelProvider.java @@ -227,7 +227,7 @@ public class QuickSearchDeveloperPanelProvider implements DeveloperPanelProvider ///////////////////////////////// // failed index events, if any // ///////////////////////////////// - String failedTable = config.applyPrefix(QuickSearchFailedEvent.TABLE_NAME); + String failedTable = config.applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME); if(recordId != null && mayRead(failedTable)) { DeveloperPanelBlock failedBlock = failedEventsBlock(failedTable, tableName, recordId); diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/QuickSearchDiagnosticsWidgetRenderer.java b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/QuickSearchDiagnosticsWidgetRenderer.java index 8ba72f9..8603f52 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/QuickSearchDiagnosticsWidgetRenderer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/diagnostics/QuickSearchDiagnosticsWidgetRenderer.java @@ -116,7 +116,7 @@ public class QuickSearchDiagnosticsWidgetRenderer extends AbstractWidgetRenderer *******************************************************************************/ private static void renderRecentFailures(DiagnosticsHtml html, QuickSearchQBitConfig config) { - String tableName = config.applyPrefix(QuickSearchDiagnosticEvent.TABLE_NAME); + String tableName = config.applyTablePrefix(QuickSearchDiagnosticEvent.TABLE_NAME); html.subheading("Recent search failures (all servers)"); if(QContext.getQInstance().getTable(tableName) == null) { @@ -161,7 +161,7 @@ public class QuickSearchDiagnosticsWidgetRenderer extends AbstractWidgetRenderer *******************************************************************************/ private static void renderLastValidation(DiagnosticsHtml html, QuickSearchQBitConfig config) { - String tableName = config.applyPrefix(QuickSearchValidationRun.TABLE_NAME); + String tableName = config.applyTablePrefix(QuickSearchValidationRun.TABLE_NAME); html.subheading("Latest index validation"); if(QContext.getQInstance().getTable(tableName) == null) { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/listeners/QuickSearchRecordChangeListener.java b/src/main/java/com/kingsrook/qbits/quicksearch/listeners/QuickSearchRecordChangeListener.java index 865c95e..e7d1372 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/listeners/QuickSearchRecordChangeListener.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/listeners/QuickSearchRecordChangeListener.java @@ -66,13 +66,13 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; ** This listener never fails the host's write. When the re-read of inserted or ** updated records or publishing fails (including a LinkageError from a missing ** optional library while the client is built), each affected (table, record, - ** action) is written to quickSearchFailedEvent for the scheduled basepull to + ** action) is written to quick_search_failed_event for the scheduled basepull to ** replay. A failed re-read is recorded after the commit too, so a rolled-back ** write leaves no row. ** ** While a full reindex rebuilds into a new physical index, the alias still ** points at the old one, so a published delete never reaches the new index. - ** Such deletes are also written to quickSearchFailedEvent with status + ** Such deletes are also written to quick_search_failed_event with status ** AWAITING_REINDEX; the reindex applies them after the alias swap. *******************************************************************************/ public class QuickSearchRecordChangeListener implements RecordChangeListenerInterface @@ -246,7 +246,7 @@ public class QuickSearchRecordChangeListener implements RecordChangeListenerInte /******************************************************************************* - ** Write one quickSearchFailedEvent row per event. Never throws. + ** Write one quick_search_failed_event row per event. Never throws. *******************************************************************************/ static void recordFailures(QuickSearchRuntime runtime, List events, Throwable cause) { @@ -261,9 +261,9 @@ public class QuickSearchRecordChangeListener implements RecordChangeListenerInte try { - if(!hasTable(runtime.getConfig().applyPrefix(QuickSearchFailedEvent.TABLE_NAME))) + if(!hasTable(runtime.getConfig().applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME))) { - LOG.error("quickSearchFailedEvent table is not in the QInstance; failed events are lost", logPair("eventCount", events.size())); + LOG.error("quick_search_failed_event table is not in the QInstance; failed events are lost", logPair("eventCount", events.size())); return; } @@ -292,7 +292,7 @@ public class QuickSearchRecordChangeListener implements RecordChangeListenerInte String tableName = deleteEvents.get(0).getTableName(); try { - return (hasTable(runtime.getConfig().applyPrefix(QuickSearchFailedEvent.TABLE_NAME)) && isRebuilding(runtime, tableName)); + return (hasTable(runtime.getConfig().applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME)) && isRebuilding(runtime, tableName)); } catch(Exception e) { @@ -347,7 +347,7 @@ public class QuickSearchRecordChangeListener implements RecordChangeListenerInte } UpdateInput updateInput = new UpdateInput(); - updateInput.setTableName(runtime.getConfig().applyPrefix(QuickSearchFailedEvent.TABLE_NAME)); + updateInput.setTableName(runtime.getConfig().applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME)); updateInput.setRecords(updates); new UpdateAction().execute(updateInput); } @@ -355,7 +355,7 @@ public class QuickSearchRecordChangeListener implements RecordChangeListenerInte /******************************************************************************* - ** Whether the table's quickSearchIndex row is REBUILDING. + ** Whether the table's quick_search_index row is REBUILDING. *******************************************************************************/ private static boolean isRebuilding(QuickSearchRuntime runtime, String tableName) throws QException { @@ -375,7 +375,7 @@ public class QuickSearchRecordChangeListener implements RecordChangeListenerInte /******************************************************************************* - ** Insert one quickSearchFailedEvent row per event; returns the inserted rows. + ** Insert one quick_search_failed_event row per event; returns the inserted rows. *******************************************************************************/ static List insertFailedEventRows(QuickSearchRuntime runtime, List events, String message, String status) throws QException { @@ -392,7 +392,7 @@ public class QuickSearchRecordChangeListener implements RecordChangeListenerInte } InsertInput insertInput = new InsertInput(); - insertInput.setTableName(runtime.getConfig().applyPrefix(QuickSearchFailedEvent.TABLE_NAME)); + insertInput.setTableName(runtime.getConfig().applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME)); insertInput.setRecords(rows); return (CollectionUtils.nonNullList(new InsertAction().execute(insertInput).getRecords())); } diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchAdminAppMetaDataProducer.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchAdminAppMetaDataProducer.java index a3dcb9b..cccc5f8 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchAdminAppMetaDataProducer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchAdminAppMetaDataProducer.java @@ -76,7 +76,7 @@ public class QuickSearchAdminAppMetaDataProducer extends QBitComponentMetaDataPr for(String tableName : new String[] { QuickSearchIndex.TABLE_NAME, QuickSearchIndexRun.TABLE_NAME, QuickSearchFailedEvent.TABLE_NAME, QuickSearchValidationRun.TABLE_NAME, QuickSearchDiagnosticEvent.TABLE_NAME }) { - QTableMetaData table = produced.get(QTableMetaData.class, config.applyPrefix(tableName)); + QTableMetaData table = produced.get(QTableMetaData.class, config.applyTablePrefix(tableName)); if(table != null) { app.withChild(table); diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchDiagnosticEventTableMetaDataProducer.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchDiagnosticEventTableMetaDataProducer.java index dc37d2a..03f27a8 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchDiagnosticEventTableMetaDataProducer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchDiagnosticEventTableMetaDataProducer.java @@ -25,7 +25,7 @@ import com.kingsrook.qbits.quicksearch.QuickSearchQBitConfig; /******************************************************************************* - ** Produces the quickSearchDiagnosticEvent table when enableDiagnosticTools is true. + ** Produces the quick_search_diagnostic_event table when enableDiagnosticTools is true. *******************************************************************************/ public class QuickSearchDiagnosticEventTableMetaDataProducer extends QBitComponentMetaDataProducer { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchDiagnosticsProcessMetaDataHelper.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchDiagnosticsProcessMetaDataHelper.java index ef69dc2..34cb1f8 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchDiagnosticsProcessMetaDataHelper.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchDiagnosticsProcessMetaDataHelper.java @@ -217,8 +217,8 @@ public class QuickSearchDiagnosticsProcessMetaDataHelper processes.add(buildPlaygroundProcess(config)); processes.add(buildValidateProcess(config)); processes.add(buildAnalyzeProcess(config)); - processes.add(buildInspectProcess(config, config.applyPrefix(QuickSearchFailedEvent.TABLE_NAME))); - processes.add(buildReindexRecordsProcess(config, config.applyPrefix(QuickSearchFailedEvent.TABLE_NAME))); + processes.add(buildInspectProcess(config, config.applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME))); + processes.add(buildReindexRecordsProcess(config, config.applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME))); return (processes); } diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchFailedEventTableMetaDataProducer.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchFailedEventTableMetaDataProducer.java index 5353607..2d958a5 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchFailedEventTableMetaDataProducer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchFailedEventTableMetaDataProducer.java @@ -25,7 +25,7 @@ import com.kingsrook.qbits.quicksearch.QuickSearchQBitConfig; /******************************************************************************* - ** Produces the quickSearchFailedEvent table. + ** Produces the quick_search_failed_event table. *******************************************************************************/ public class QuickSearchFailedEventTableMetaDataProducer extends QBitComponentMetaDataProducer { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexPossibleValueSourceProducer.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexPossibleValueSourceProducer.java index f7f7ceb..ebfa85d 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexPossibleValueSourceProducer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexPossibleValueSourceProducer.java @@ -25,7 +25,7 @@ import com.kingsrook.qbits.quicksearch.QuickSearchQBitConfig; /******************************************************************************* - ** Produces the possible value source over the quickSearchIndex table. + ** Produces the possible value source over the quick_search_index table. *******************************************************************************/ public class QuickSearchIndexPossibleValueSourceProducer extends QBitComponentMetaDataProducer { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexRunTableMetaDataProducer.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexRunTableMetaDataProducer.java index b6366fd..b01c8da 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexRunTableMetaDataProducer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexRunTableMetaDataProducer.java @@ -25,7 +25,7 @@ import com.kingsrook.qbits.quicksearch.QuickSearchQBitConfig; /******************************************************************************* - ** Produces the quickSearchIndexRun table. + ** Produces the quick_search_index_run table. *******************************************************************************/ public class QuickSearchIndexRunTableMetaDataProducer extends QBitComponentMetaDataProducer { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexTableMetaDataProducer.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexTableMetaDataProducer.java index b74ebf8..9ed9107 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexTableMetaDataProducer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchIndexTableMetaDataProducer.java @@ -25,7 +25,7 @@ import com.kingsrook.qbits.quicksearch.QuickSearchQBitConfig; /******************************************************************************* - ** Produces the quickSearchIndex table. + ** Produces the quick_search_index table. *******************************************************************************/ public class QuickSearchIndexTableMetaDataProducer extends QBitComponentMetaDataProducer { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchProcessMetaDataHelper.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchProcessMetaDataHelper.java index b086b04..e20db7e 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchProcessMetaDataHelper.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchProcessMetaDataHelper.java @@ -113,7 +113,7 @@ public class QuickSearchProcessMetaDataHelper .withLabel("Choose table") .withFormField(new QFieldMetaData("tableName", QFieldType.STRING) .withLabel("Table (optional)") - .withPossibleValueSourceName(config.applyPrefix(QuickSearchSearchableTablePossibleValueSourceProducer.NAME)) + .withPossibleValueSourceName(config.applyTablePrefix(QuickSearchSearchableTablePossibleValueSourceProducer.NAME)) .withIsRequired(false)) .withViewField(new QFieldMetaData("help", QFieldType.STRING).withLabel(" ").withDefaultValue(help))); } diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchSearchableTablePossibleValueSourceProducer.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchSearchableTablePossibleValueSourceProducer.java index 3107766..1d34c0a 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchSearchableTablePossibleValueSourceProducer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchSearchableTablePossibleValueSourceProducer.java @@ -40,7 +40,11 @@ import com.kingsrook.qbits.quicksearch.annotations.QuickSearchable; *******************************************************************************/ public class QuickSearchSearchableTablePossibleValueSourceProducer extends QBitComponentMetaDataProducer { - public static final String NAME = "quickSearchSearchableTable"; + public static final String NAME = "quick_search_searchable_table"; + + /** Possible-value source name before 1.1.0-RC.3 (camelCase). */ + @Deprecated(since = "1.1.0-RC.3") + public static final String LEGACY_NAME = "quickSearchSearchableTable"; @@ -78,7 +82,7 @@ public class QuickSearchSearchableTablePossibleValueSourceProducer extends QBitC } return (new QPossibleValueSource() - .withName(config.applyPrefix(NAME)) + .withName(config.applyTablePrefix(NAME)) .withType(QPossibleValueSourceType.ENUM) .withEnumValues(values)); } diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchTableMetaDataHelper.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchTableMetaDataHelper.java index 10e0d4e..4438590 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchTableMetaDataHelper.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchTableMetaDataHelper.java @@ -43,12 +43,12 @@ public class QuickSearchTableMetaDataHelper { /******************************************************************************* - ** quickSearchIndex: one row per indexed table. + ** quick_search_index: one row per indexed table. *******************************************************************************/ public static QTableMetaData buildIndexTable(QuickSearchQBitConfig config) { return (new QTableMetaData() - .withName(config.applyPrefix(QuickSearchIndex.TABLE_NAME)) + .withName(config.applyTablePrefix(QuickSearchIndex.TABLE_NAME)) .withLabel("Quick Search Index") .withIcon(new QIcon("manage_search")) .withBackendName(config.getBackendName()) @@ -78,12 +78,12 @@ public class QuickSearchTableMetaDataHelper /******************************************************************************* - ** quickSearchIndexRun: history of basepull, reindex and reconcile runs. + ** quick_search_index_run: history of basepull, reindex and reconcile runs. *******************************************************************************/ public static QTableMetaData buildIndexRunTable(QuickSearchQBitConfig config) { return (new QTableMetaData() - .withName(config.applyPrefix(QuickSearchIndexRun.TABLE_NAME)) + .withName(config.applyTablePrefix(QuickSearchIndexRun.TABLE_NAME)) .withLabel("Quick Search Index Run") .withIcon(new QIcon("history")) .withBackendName(config.getBackendName()) @@ -91,7 +91,7 @@ public class QuickSearchTableMetaDataHelper .withPermissionRules(config.getTablePermissionRules() == null ? null : config.getTablePermissionRules().clone()) .withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false)) .withField(new QFieldMetaData("quickSearchIndexId", QFieldType.INTEGER).withIsEditable(false) - .withPossibleValueSourceName(config.applyPrefix(QuickSearchIndex.TABLE_NAME))) + .withPossibleValueSourceName(config.applyTablePrefix(QuickSearchIndex.TABLE_NAME))) .withField(new QFieldMetaData("runType", QFieldType.STRING).withIsEditable(false)) .withField(new QFieldMetaData("status", QFieldType.STRING).withIsEditable(false)) .withField(new QFieldMetaData("startTime", QFieldType.DATE_TIME).withIsEditable(false)) @@ -107,13 +107,13 @@ public class QuickSearchTableMetaDataHelper /******************************************************************************* - ** quickSearchFailedEvent: real-time index or delete events that could not + ** quick_search_failed_event: real-time index or delete events that could not ** reach OpenSearch, replayed by the scheduled basepull. *******************************************************************************/ public static QTableMetaData buildFailedEventTable(QuickSearchQBitConfig config) { return (new QTableMetaData() - .withName(config.applyPrefix(QuickSearchFailedEvent.TABLE_NAME)) + .withName(config.applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME)) .withLabel("Quick Search Failed Event") .withIcon(new QIcon("error_outline")) .withBackendName(config.getBackendName()) @@ -133,7 +133,7 @@ public class QuickSearchTableMetaDataHelper /******************************************************************************* - ** quickSearchDiagnosticEvent: failed searches, diagnostic tool runs (the + ** quick_search_diagnostic_event: failed searches, diagnostic tool runs (the ** audit trail) and refused runs. Written by the QBit only: insert, update ** and delete are disabled for users and the API (core actions, which the ** QBit uses, do not check capabilities). @@ -141,7 +141,7 @@ public class QuickSearchTableMetaDataHelper public static QTableMetaData buildDiagnosticEventTable(QuickSearchQBitConfig config) { return (new QTableMetaData() - .withName(config.applyPrefix(QuickSearchDiagnosticEvent.TABLE_NAME)) + .withName(config.applyTablePrefix(QuickSearchDiagnosticEvent.TABLE_NAME)) .withLabel("Quick Search Diagnostic Event") .withoutCapabilities(Capability.TABLE_INSERT, Capability.TABLE_UPDATE, Capability.TABLE_DELETE) .withIcon(new QIcon("bug_report")) @@ -171,7 +171,7 @@ public class QuickSearchTableMetaDataHelper /******************************************************************************* - ** quickSearchValidationRun: index validation reports (history). The + ** quick_search_validation_run: index validation reports (history). The ** report is an HTML field, shown in full on the record view; only the ** QBit writes rows (insert, update and delete are disabled for users and ** the API), so the HTML is always the QBit's escaped output. @@ -179,7 +179,7 @@ public class QuickSearchTableMetaDataHelper public static QTableMetaData buildValidationRunTable(QuickSearchQBitConfig config) { return (new QTableMetaData() - .withName(config.applyPrefix(QuickSearchValidationRun.TABLE_NAME)) + .withName(config.applyTablePrefix(QuickSearchValidationRun.TABLE_NAME)) .withLabel("Quick Search Validation Run") .withoutCapabilities(Capability.TABLE_INSERT, Capability.TABLE_UPDATE, Capability.TABLE_DELETE) .withIcon(new QIcon("fact_check")) @@ -212,12 +212,12 @@ public class QuickSearchTableMetaDataHelper /******************************************************************************* - ** Possible value source over quickSearchIndex, so run rows show the table + ** Possible value source over quick_search_index, so run rows show the table ** name instead of an id. *******************************************************************************/ public static QPossibleValueSource buildIndexPossibleValueSource(QuickSearchQBitConfig config) { - return (QPossibleValueSource.newForTable(config.applyPrefix(QuickSearchIndex.TABLE_NAME))); + return (QPossibleValueSource.newForTable(config.applyTablePrefix(QuickSearchIndex.TABLE_NAME))); } } diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchValidationRunTableMetaDataProducer.java b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchValidationRunTableMetaDataProducer.java index a5d6844..3f4de43 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchValidationRunTableMetaDataProducer.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/metadata/QuickSearchValidationRunTableMetaDataProducer.java @@ -25,7 +25,7 @@ import com.kingsrook.qbits.quicksearch.QuickSearchQBitConfig; /******************************************************************************* - ** Produces the quickSearchValidationRun table when enableDiagnosticTools is true. + ** Produces the quick_search_validation_run table when enableDiagnosticTools is true. *******************************************************************************/ public class QuickSearchValidationRunTableMetaDataProducer extends QBitComponentMetaDataProducer { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchDiagnosticEvent.java b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchDiagnosticEvent.java index 103ed56..f6389e9 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchDiagnosticEvent.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchDiagnosticEvent.java @@ -32,7 +32,11 @@ import com.kingsrook.qqq.backend.core.exceptions.QException; *******************************************************************************/ public class QuickSearchDiagnosticEvent extends QRecordEntity { - public static final String TABLE_NAME = "quickSearchDiagnosticEvent"; + public static final String TABLE_NAME = "quick_search_diagnostic_event"; + + /** Table name before 1.1.0-RC.3 (camelCase). Kept only for upgrade scripts; see docs/MIGRATION-1.1.md. */ + @Deprecated(since = "1.1.0-RC.3") + public static final String LEGACY_TABLE_NAME = "quickSearchDiagnosticEvent"; public static final String TYPE_SEARCH_FAILED = "SEARCH_FAILED"; public static final String TYPE_TOOL_RUN = "TOOL_RUN"; diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchFailedEvent.java b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchFailedEvent.java index 6c37272..7989c65 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchFailedEvent.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchFailedEvent.java @@ -29,7 +29,11 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; *******************************************************************************/ public class QuickSearchFailedEvent extends QRecordEntity { - public static final String TABLE_NAME = "quickSearchFailedEvent"; + public static final String TABLE_NAME = "quick_search_failed_event"; + + /** Table name before 1.1.0-RC.3 (camelCase). Kept only for upgrade scripts; see docs/MIGRATION-1.1.md. */ + @Deprecated(since = "1.1.0-RC.3") + public static final String LEGACY_TABLE_NAME = "quickSearchFailedEvent"; public static final String STATUS_PENDING = "PENDING"; public static final String STATUS_EXHAUSTED = "EXHAUSTED"; diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndex.java b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndex.java index c0940de..696c12f 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndex.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndex.java @@ -23,7 +23,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; /******************************************************************************* - ** Entity bean for the quickSearchIndex table. + ** Entity bean for the quick_search_index table. ** ** Tracks configuration for each table that participates in the quick search ** index, including basepull scheduling, searchable field definitions, and @@ -31,7 +31,11 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; *******************************************************************************/ public class QuickSearchIndex extends QRecordEntity { - public static final String TABLE_NAME = "quickSearchIndex"; + public static final String TABLE_NAME = "quick_search_index"; + + /** Table name before 1.1.0-RC.3 (camelCase). Kept only for upgrade scripts; see docs/MIGRATION-1.1.md. */ + @Deprecated(since = "1.1.0-RC.3") + public static final String LEGACY_TABLE_NAME = "quickSearchIndex"; @QField() private Integer id; diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexRun.java b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexRun.java index 3925326..0708b5d 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexRun.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexRun.java @@ -23,7 +23,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; /******************************************************************************* - ** Entity bean for the quickSearchIndexRun table. + ** Entity bean for the quick_search_index_run table. ** ** Records a single execution of the indexing process for a given ** QuickSearchIndex, capturing run type, timing, record counts, and any errors @@ -31,7 +31,11 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; *******************************************************************************/ public class QuickSearchIndexRun extends QRecordEntity { - public static final String TABLE_NAME = "quickSearchIndexRun"; + public static final String TABLE_NAME = "quick_search_index_run"; + + /** Table name before 1.1.0-RC.3 (camelCase). Kept only for upgrade scripts; see docs/MIGRATION-1.1.md. */ + @Deprecated(since = "1.1.0-RC.3") + public static final String LEGACY_TABLE_NAME = "quickSearchIndexRun"; @QField() private Integer id; diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchValidationRun.java b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchValidationRun.java index d5d0a65..fccf3d3 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchValidationRun.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/model/QuickSearchValidationRun.java @@ -31,7 +31,11 @@ import com.kingsrook.qqq.backend.core.exceptions.QException; *******************************************************************************/ public class QuickSearchValidationRun extends QRecordEntity { - public static final String TABLE_NAME = "quickSearchValidationRun"; + public static final String TABLE_NAME = "quick_search_validation_run"; + + /** Table name before 1.1.0-RC.3 (camelCase). Kept only for upgrade scripts; see docs/MIGRATION-1.1.md. */ + @Deprecated(since = "1.1.0-RC.3") + public static final String LEGACY_TABLE_NAME = "quickSearchValidationRun"; public static final String STATUS_PASS = "PASS"; public static final String STATUS_WARN = "WARN"; diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/processes/AbstractIndexingStep.java b/src/main/java/com/kingsrook/qbits/quicksearch/processes/AbstractIndexingStep.java index bfa7109..6c277e2 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/processes/AbstractIndexingStep.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/processes/AbstractIndexingStep.java @@ -138,7 +138,7 @@ public abstract class AbstractIndexingStep implements BackendStep /******************************************************************************* - ** Make sure a quickSearchIndex row exists for the table. The table's unique + ** Make sure a quick_search_index row exists for the table. The table's unique ** key on tableName makes a concurrent first insert fail, which is handled by ** re-querying. *******************************************************************************/ @@ -183,7 +183,7 @@ public abstract class AbstractIndexingStep implements BackendStep /******************************************************************************* - ** The quickSearchIndex row for a table, or null. + ** The quick_search_index row for a table, or null. *******************************************************************************/ protected QRecord queryIndexRow(String tableName) throws QException { @@ -197,7 +197,7 @@ public abstract class AbstractIndexingStep implements BackendStep /******************************************************************************* - ** The id of the quickSearchIndex row for a table. + ** The id of the quick_search_index row for a table. *******************************************************************************/ protected Integer queryIndexId(String tableName) throws QException { @@ -329,7 +329,7 @@ public abstract class AbstractIndexingStep implements BackendStep InsertOutput insertOutput = new InsertAction().execute(insertInput); if(insertOutput.getRecords().isEmpty()) { - throw new QException("Failed to create quickSearchIndexRun record: no record returned from insert"); + throw new QException("Failed to create quick_search_index_run record: no record returned from insert"); } QRecord inserted = insertOutput.getRecords().get(0); @@ -440,7 +440,7 @@ public abstract class AbstractIndexingStep implements BackendStep /******************************************************************************* - ** Update fields on a quickSearchIndex row. + ** Update fields on a quick_search_index row. *******************************************************************************/ protected void updateIndexRow(Integer indexId, Map values) throws QException { @@ -577,8 +577,8 @@ public abstract class AbstractIndexingStep implements BackendStep Instant cutoff = Instant.now().minus(retentionDays, ChronoUnit.DAYS); purgeOlderThan(getConfigOrNull().getQuickSearchIndexRunTableName(), "startTime", cutoff, retentionDays); - purgeOlderThan(getConfigOrNull().applyPrefix(QuickSearchDiagnosticEvent.TABLE_NAME), "createDate", cutoff, retentionDays); - purgeOlderThan(getConfigOrNull().applyPrefix(QuickSearchValidationRun.TABLE_NAME), "createDate", cutoff, retentionDays); + purgeOlderThan(getConfigOrNull().applyTablePrefix(QuickSearchDiagnosticEvent.TABLE_NAME), "createDate", cutoff, retentionDays); + purgeOlderThan(getConfigOrNull().applyTablePrefix(QuickSearchValidationRun.TABLE_NAME), "createDate", cutoff, retentionDays); } diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/processes/BasepullIndexStep.java b/src/main/java/com/kingsrook/qbits/quicksearch/processes/BasepullIndexStep.java index 91a03ec..8fc2b4c 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/processes/BasepullIndexStep.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/processes/BasepullIndexStep.java @@ -61,7 +61,7 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; ** are replayed in the same run) and replays failed real-time events, and ** afterwards purges old run history. ** - ** The watermark stored on the quickSearchIndex row is the run's start time, + ** The watermark stored on the quick_search_index row is the run's start time, ** captured before the first query, so rows modified during the run are read ** again next time (re-indexing is idempotent). A table without a timestamp ** field is left to the reconcile process. @@ -118,7 +118,7 @@ public class BasepullIndexStep extends AbstractIndexingStep if(CollectionUtils.nullSafeIsEmpty(indexRecords)) { - LOG.info("No enabled quickSearchIndex rows found; nothing to basepull"); + LOG.info("No enabled quick_search_index rows found; nothing to basepull"); purgeOldRuns(); return; } @@ -196,7 +196,7 @@ public class BasepullIndexStep extends AbstractIndexingStep if(tableConfig == null) { - String message = "Table is no longer configured for Quick Search; disable or remove its quickSearchIndex row"; + String message = "Table is no longer configured for Quick Search; disable or remove its quick_search_index row"; completeRunRecord(run, RUN_FAILED, 0, 0, 1, message); throw (new QException(tableName + ": " + message)); } @@ -277,7 +277,7 @@ public class BasepullIndexStep extends AbstractIndexingStep void replayFailedEvents(RunBackendStepOutput output) throws QException { QuickSearchQBitConfig config = getConfig(); - String failedEventTable = config.applyPrefix(QuickSearchFailedEvent.TABLE_NAME); + String failedEventTable = config.applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME); QueryInput queryInput = new QueryInput(); queryInput.setTableName(failedEventTable); diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/processes/FullReindexStep.java b/src/main/java/com/kingsrook/qbits/quicksearch/processes/FullReindexStep.java index 59b3336..3fc951f 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/processes/FullReindexStep.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/processes/FullReindexStep.java @@ -69,7 +69,7 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; ** While the new index is built, real-time writes still go through the alias ** to the old one. Updates are caught by the next basepull (lastBasepullTime ** is set to each table's start). Deletes are caught here: each table's - ** quickSearchIndex row is REBUILDING for the whole rebuild, which makes the + ** quick_search_index row is REBUILDING for the whole rebuild, which makes the ** record change listener (on any node) also record each delete as an ** AWAITING_REINDEX failed event. Once the rebuild's own writes are done and ** the alias is swapped, those deletes are applied through the alias. @@ -479,7 +479,7 @@ public class FullReindexStep extends AbstractIndexingStep private void handCapturedDeletesToBasepull(Serializable lastCapturedId) throws QException { QuickSearchQBitConfig config = getConfig(); - String failedEventTable = config.applyPrefix(QuickSearchFailedEvent.TABLE_NAME); + String failedEventTable = config.applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME); Serializable afterId = null; Integer handedOver = 0; @@ -646,7 +646,7 @@ public class FullReindexStep extends AbstractIndexingStep /******************************************************************************* - ** Every quickSearchIndex row that is REBUILDING. + ** Every quick_search_index row that is REBUILDING. *******************************************************************************/ private List queryRebuildingIndexRows() throws QException { @@ -665,7 +665,7 @@ public class FullReindexStep extends AbstractIndexingStep private Serializable queryLastCapturedDeleteId() throws QException { QueryInput queryInput = new QueryInput(); - queryInput.setTableName(getConfig().applyPrefix(QuickSearchFailedEvent.TABLE_NAME)); + queryInput.setTableName(getConfig().applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME)); queryInput.setFilter(new QQueryFilter(new QFilterCriteria("status", QCriteriaOperator.EQUALS, QuickSearchFailedEvent.STATUS_AWAITING_REINDEX)) .withOrderBy(new QFilterOrderBy("id", false)) .withLimit(1)); @@ -757,7 +757,7 @@ public class FullReindexStep extends AbstractIndexingStep try { QuickSearchQBitConfig config = getConfig(); - String failedEventTable = config.applyPrefix(QuickSearchFailedEvent.TABLE_NAME); + String failedEventTable = config.applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME); Serializable lastCapturedId = queryLastCapturedDeleteId(); Serializable afterId = null; diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/processes/diagnostics/AbstractDiagnosticToolStep.java b/src/main/java/com/kingsrook/qbits/quicksearch/processes/diagnostics/AbstractDiagnosticToolStep.java index ab0b311..af16672 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/processes/diagnostics/AbstractDiagnosticToolStep.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/processes/diagnostics/AbstractDiagnosticToolStep.java @@ -145,7 +145,7 @@ public abstract class AbstractDiagnosticToolStep implements BackendStep throw (new QUserFacingException("Select at most " + max + " records (" + records.size() + "+ selected).")); } - boolean failedEvents = tableName.equals(runtime.getConfig().applyPrefix(QuickSearchFailedEvent.TABLE_NAME)); + boolean failedEvents = tableName.equals(runtime.getConfig().applyTablePrefix(QuickSearchFailedEvent.TABLE_NAME)); Set targets = new LinkedHashSet<>(); for(QRecord record : records) { diff --git a/src/main/java/com/kingsrook/qbits/quicksearch/processes/diagnostics/ValidateIndexStep.java b/src/main/java/com/kingsrook/qbits/quicksearch/processes/diagnostics/ValidateIndexStep.java index 0b08e1e..d658fd5 100644 --- a/src/main/java/com/kingsrook/qbits/quicksearch/processes/diagnostics/ValidateIndexStep.java +++ b/src/main/java/com/kingsrook/qbits/quicksearch/processes/diagnostics/ValidateIndexStep.java @@ -103,7 +103,7 @@ public class ValidateIndexStep extends AbstractDiagnosticToolStep String link = runId == null ? "

The report was not saved (the validation run table is not configured or the insert failed; see the log).

" - : "

Saved as validation run #" + runId + ".

"; + : "

Saved as validation run #" + runId + ".

"; setHtml(output, STEP_RESULT, IndexValidator.render(report) + link); output.addValue(FIELD_RUN_ID, runId); output.addValue("status", report.status()); diff --git a/src/test/java/com/kingsrook/qbits/quicksearch/DiagnosticsMetaDataTest.java b/src/test/java/com/kingsrook/qbits/quicksearch/DiagnosticsMetaDataTest.java index d150b01..da9c171 100644 --- a/src/test/java/com/kingsrook/qbits/quicksearch/DiagnosticsMetaDataTest.java +++ b/src/test/java/com/kingsrook/qbits/quicksearch/DiagnosticsMetaDataTest.java @@ -293,10 +293,10 @@ class DiagnosticsMetaDataTest QuickSearchQBitConfig config = config().withTableNamePrefix("myApp_"); new QuickSearchQBitProducer().withConfig(config).produce(qInstance); - assertThat(qInstance.getTable("myApp_" + QuickSearchDiagnosticEvent.TABLE_NAME)).isNotNull(); - assertThat(qInstance.getTable("myApp_" + QuickSearchValidationRun.TABLE_NAME)).isNotNull(); + assertThat(qInstance.getTable("my_app_" + QuickSearchDiagnosticEvent.TABLE_NAME)).isNotNull(); + assertThat(qInstance.getTable("my_app_" + QuickSearchValidationRun.TABLE_NAME)).isNotNull(); QProcessMetaData playground = qInstance.getProcess("myApp_" + QuickSearchDiagnosticsProcessMetaDataHelper.PLAYGROUND_PROCESS_NAME); - assertThat(playground.getTableName()).isEqualTo("myApp_" + QuickSearchIndex.TABLE_NAME); + assertThat(playground.getTableName()).isEqualTo("my_app_" + QuickSearchIndex.TABLE_NAME); assertThat(qInstance.getProcess("myApp_quickSearchInspect_" + SOURCE)).isNotNull(); } diff --git a/src/test/java/com/kingsrook/qbits/quicksearch/QuickSearchQBitProducerTest.java b/src/test/java/com/kingsrook/qbits/quicksearch/QuickSearchQBitProducerTest.java index 5536d48..252a0d5 100644 --- a/src/test/java/com/kingsrook/qbits/quicksearch/QuickSearchQBitProducerTest.java +++ b/src/test/java/com/kingsrook/qbits/quicksearch/QuickSearchQBitProducerTest.java @@ -200,13 +200,13 @@ class QuickSearchQBitProducerTest producer.produce(qInstance); - assertThat(qInstance.getTable("quickSearchIndex")).isNotNull(); - assertThat(qInstance.getTable("quickSearchIndex").getBackendName()).isEqualTo(BACKEND_NAME); - assertThat(qInstance.getTable("quickSearchIndex").getPrimaryKeyField()).isEqualTo("id"); + assertThat(qInstance.getTable("quick_search_index")).isNotNull(); + assertThat(qInstance.getTable("quick_search_index").getBackendName()).isEqualTo(BACKEND_NAME); + assertThat(qInstance.getTable("quick_search_index").getPrimaryKeyField()).isEqualTo("id"); - assertThat(qInstance.getTable("quickSearchIndexRun")).isNotNull(); - assertThat(qInstance.getTable("quickSearchIndexRun").getBackendName()).isEqualTo(BACKEND_NAME); - assertThat(qInstance.getTable("quickSearchIndexRun").getPrimaryKeyField()).isEqualTo("id"); + assertThat(qInstance.getTable("quick_search_index_run")).isNotNull(); + assertThat(qInstance.getTable("quick_search_index_run").getBackendName()).isEqualTo(BACKEND_NAME); + assertThat(qInstance.getTable("quick_search_index_run").getPrimaryKeyField()).isEqualTo("id"); } @@ -228,8 +228,8 @@ class QuickSearchQBitProducerTest producer.produce(qInstance); - assertThat(qInstance.getTable("myApp_quickSearchIndex")).isNotNull(); - assertThat(qInstance.getTable("myApp_quickSearchIndexRun")).isNotNull(); + assertThat(qInstance.getTable("my_app_quick_search_index")).isNotNull(); + assertThat(qInstance.getTable("my_app_quick_search_index_run")).isNotNull(); assertThat(qInstance.getProcess("myApp_" + QuickSearchQBitProducer.BASEPULL_PROCESS_NAME)).isNotNull(); assertThat(qInstance.getProcess("myApp_" + QuickSearchQBitProducer.FULL_REINDEX_PROCESS_NAME)).isNotNull(); assertThat(qInstance.getProcess("myApp_" + QuickSearchQBitProducer.RECONCILE_PROCESS_NAME)).isNotNull(); @@ -612,7 +612,7 @@ class QuickSearchQBitProducerTest producer.produce(qInstance); - QTableMetaData indexTable = qInstance.getTable("quickSearchIndex"); + QTableMetaData indexTable = qInstance.getTable("quick_search_index"); assertThat(indexTable.getFields()).containsKey("id"); assertThat(indexTable.getFields()).containsKey("tableName"); assertThat(indexTable.getFields()).containsKey("enabled"); @@ -626,7 +626,7 @@ class QuickSearchQBitProducerTest assertThat(indexTable.getFields()).containsKey("createDate"); assertThat(indexTable.getFields()).containsKey("modifyDate"); - QTableMetaData indexRunTable = qInstance.getTable("quickSearchIndexRun"); + QTableMetaData indexRunTable = qInstance.getTable("quick_search_index_run"); assertThat(indexRunTable.getFields()).containsKey("id"); assertThat(indexRunTable.getFields()).containsKey("quickSearchIndexId"); assertThat(indexRunTable.getFields()).containsKey("runType"); @@ -697,9 +697,9 @@ class QuickSearchQBitProducerTest assertThat(config.getRuntime()).isNotNull(); assertThat(QuickSearchRuntime.get()).isSameAs(config.getRuntime()); - assertThat(qInstance.getTable("quickSearchIndex").getSourceQBitName()).isEqualTo(qBit.getName()); + assertThat(qInstance.getTable("quick_search_index").getSourceQBitName()).isEqualTo(qBit.getName()); assertThat(qInstance.getProcess(QuickSearchQBitProducer.BASEPULL_PROCESS_NAME).getSourceQBitName()).isEqualTo(qBit.getName()); - assertThat(qInstance.getTable("quickSearchFailedEvent")).isNotNull(); + assertThat(qInstance.getTable("quick_search_failed_event")).isNotNull(); } @@ -712,10 +712,10 @@ class QuickSearchQBitProducerTest new QuickSearchQBitProducer().withConfig(buildValidConfig()).produce(qInstance); assertThat(qInstance.getProcess(QuickSearchQBitProducer.FULL_REINDEX_PROCESS_NAME).getPermissionRules().getLevel()).isEqualTo(PermissionLevel.HAS_ACCESS_PERMISSION); - assertThat(qInstance.getProcess(QuickSearchQBitProducer.FULL_REINDEX_PROCESS_NAME).getPermissionRules().getPermissionBaseName()).isEqualTo("quickSearchAdmin"); + assertThat(qInstance.getProcess(QuickSearchQBitProducer.FULL_REINDEX_PROCESS_NAME).getPermissionRules().getPermissionBaseName()).isEqualTo("quick_search_admin"); assertThat(qInstance.getApp(QuickSearchQBitProducer.APP_NAME).getPermissionRules().getLevel()).isEqualTo(PermissionLevel.HAS_ACCESS_PERMISSION); - assertThat(qInstance.getTable("quickSearchIndex").getPermissionRules().getLevel()).isEqualTo(PermissionLevel.READ_WRITE_PERMISSIONS); - assertThat(qInstance.getTable("quickSearchIndex").getUniqueKeys()).anyMatch(uk -> uk.getFieldNames().equals(List.of("tableName"))); + assertThat(qInstance.getTable("quick_search_index").getPermissionRules().getLevel()).isEqualTo(PermissionLevel.READ_WRITE_PERMISSIONS); + assertThat(qInstance.getTable("quick_search_index").getUniqueKeys()).anyMatch(uk -> uk.getFieldNames().equals(List.of("tableName"))); } diff --git a/src/test/java/com/kingsrook/qbits/quicksearch/QuickSearchTableNamesTest.java b/src/test/java/com/kingsrook/qbits/quicksearch/QuickSearchTableNamesTest.java new file mode 100644 index 0000000..b4803b0 --- /dev/null +++ b/src/test/java/com/kingsrook/qbits/quicksearch/QuickSearchTableNamesTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2026 Kingsrook, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.kingsrook.qbits.quicksearch; + + +import com.kingsrook.qbits.quicksearch.metadata.QuickSearchSearchableTablePossibleValueSourceProducer; +import com.kingsrook.qbits.quicksearch.model.QuickSearchDiagnosticEvent; +import com.kingsrook.qbits.quicksearch.model.QuickSearchFailedEvent; +import com.kingsrook.qbits.quicksearch.model.QuickSearchIndex; +import com.kingsrook.qbits.quicksearch.model.QuickSearchIndexRun; +import com.kingsrook.qbits.quicksearch.model.QuickSearchValidationRun; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + + +/******************************************************************************* + ** Table, possible-value source and permission names follow the owner naming + ** rule (lowercase snake_case, prefixed quick_search_), and the deprecated + ** LEGACY_* constants keep the pre-1.1.0-RC.3 names for upgrade scripts. + *******************************************************************************/ +@SuppressWarnings("deprecation") +class QuickSearchTableNamesTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testTableNames_areSnakeCaseWithQuickSearchPrefix() + { + assertThat(QuickSearchIndex.TABLE_NAME).isEqualTo("quick_search_index"); + assertThat(QuickSearchIndexRun.TABLE_NAME).isEqualTo("quick_search_index_run"); + assertThat(QuickSearchFailedEvent.TABLE_NAME).isEqualTo("quick_search_failed_event"); + assertThat(QuickSearchDiagnosticEvent.TABLE_NAME).isEqualTo("quick_search_diagnostic_event"); + assertThat(QuickSearchValidationRun.TABLE_NAME).isEqualTo("quick_search_validation_run"); + assertThat(QuickSearchSearchableTablePossibleValueSourceProducer.NAME).isEqualTo("quick_search_searchable_table"); + assertThat(QuickSearchQBitConfig.DEFAULT_ADMIN_PERMISSION_BASE_NAME).isEqualTo("quick_search_admin"); + assertThat(QuickSearchQBitConfig.DEFAULT_DEBUG_PERMISSION_BASE_NAME).isEqualTo("quick_search_debug"); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testLegacyConstants_keepOldNames() + { + assertThat(QuickSearchIndex.LEGACY_TABLE_NAME).isEqualTo("quickSearchIndex"); + assertThat(QuickSearchIndexRun.LEGACY_TABLE_NAME).isEqualTo("quickSearchIndexRun"); + assertThat(QuickSearchFailedEvent.LEGACY_TABLE_NAME).isEqualTo("quickSearchFailedEvent"); + assertThat(QuickSearchDiagnosticEvent.LEGACY_TABLE_NAME).isEqualTo("quickSearchDiagnosticEvent"); + assertThat(QuickSearchValidationRun.LEGACY_TABLE_NAME).isEqualTo("quickSearchValidationRun"); + assertThat(QuickSearchSearchableTablePossibleValueSourceProducer.LEGACY_NAME).isEqualTo("quickSearchSearchableTable"); + assertThat(QuickSearchQBitConfig.LEGACY_ADMIN_PERMISSION_BASE_NAME).isEqualTo("quickSearchAdmin"); + assertThat(QuickSearchQBitConfig.LEGACY_DEBUG_PERMISSION_BASE_NAME).isEqualTo("quickSearchDebug"); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testApplyTablePrefix_snakeCasesAndJoinsWithUnderscore() + { + assertThat(new QuickSearchQBitConfig().applyTablePrefix(QuickSearchIndex.TABLE_NAME)).isEqualTo("quick_search_index"); + assertThat(new QuickSearchQBitConfig().withTableNamePrefix("").applyTablePrefix(QuickSearchIndex.TABLE_NAME)).isEqualTo("quick_search_index"); + assertThat(new QuickSearchQBitConfig().withTableNamePrefix("acme").applyTablePrefix(QuickSearchIndex.TABLE_NAME)).isEqualTo("acme_quick_search_index"); + assertThat(new QuickSearchQBitConfig().withTableNamePrefix("acme_").applyTablePrefix(QuickSearchIndex.TABLE_NAME)).isEqualTo("acme_quick_search_index"); + assertThat(new QuickSearchQBitConfig().withTableNamePrefix("myApp_").applyTablePrefix(QuickSearchIndex.TABLE_NAME)).isEqualTo("my_app_quick_search_index"); + } + +} diff --git a/src/test/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexRunTest.java b/src/test/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexRunTest.java index 31facb8..3d9948f 100644 --- a/src/test/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexRunTest.java +++ b/src/test/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexRunTest.java @@ -34,7 +34,7 @@ class QuickSearchIndexRunTest @Test void testTableNameConstant() { - assertThat(QuickSearchIndexRun.TABLE_NAME).isEqualTo("quickSearchIndexRun"); + assertThat(QuickSearchIndexRun.TABLE_NAME).isEqualTo("quick_search_index_run"); } diff --git a/src/test/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexTest.java b/src/test/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexTest.java index 7469661..28fc7c8 100644 --- a/src/test/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexTest.java +++ b/src/test/java/com/kingsrook/qbits/quicksearch/model/QuickSearchIndexTest.java @@ -34,7 +34,7 @@ class QuickSearchIndexTest @Test void testTableNameConstant() { - assertThat(QuickSearchIndex.TABLE_NAME).isEqualTo("quickSearchIndex"); + assertThat(QuickSearchIndex.TABLE_NAME).isEqualTo("quick_search_index"); } -- 2.54.0