Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
143d865c14 |
No files matched your search
@@ -14,6 +14,7 @@ import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -60,6 +61,7 @@ import com.kingsrook.qbits.qacapture.QaCaptureQBitProducer;
|
||||
import com.kingsrook.qbits.quicksearch.QuickSearchQBitConfig;
|
||||
import com.kingsrook.qbits.quicksearch.QuickSearchQBitProducer;
|
||||
import com.kingsrook.qbits.quicksearch.SearchableFieldConfig;
|
||||
import com.kingsrook.qbits.quicksearch.SearchableTableConfig;
|
||||
import com.kingsrook.qbits.redis.RedisConnectionConfig;
|
||||
import com.kingsrook.qbits.redis.RedisQBitConfig;
|
||||
import com.kingsrook.qbits.redis.RedisQBitProducer;
|
||||
@@ -85,6 +87,8 @@ import com.kingsrook.qqq.backend.core.jobs.DurableJobsMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.model.audits.AuditsMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||
@@ -369,8 +373,12 @@ final class EnterpriseFeatures
|
||||
.withAllowPlaintextCredentials(true)
|
||||
.withSchedulerName(schedulerName)
|
||||
.withTableMetaDataCustomizer(tableCustomizer)
|
||||
.withSearchableTable("customer", List.of(new SearchableFieldConfig("name"), new SearchableFieldConfig("email")))
|
||||
.withSearchableTable("order", List.of(new SearchableFieldConfig("orderNo"), new SearchableFieldConfig("status")));
|
||||
// new tables are queued for their first build, which the basepull runs: keep it quick
|
||||
.withBasepullRepeatSeconds(60);
|
||||
for(SearchableTableConfig table : searchableTables(i))
|
||||
{
|
||||
searchConfig.withSearchableTable(table);
|
||||
}
|
||||
new QuickSearchQBitProducer().withConfig(searchConfig).produce(i).addSelfToInstance(i);
|
||||
});
|
||||
}
|
||||
@@ -485,6 +493,72 @@ final class EnterpriseFeatures
|
||||
|
||||
|
||||
|
||||
/** Text fields worth searching besides a table's record label fields. */
|
||||
private static final Set<String> SEARCHABLE_FIELD_NAMES = Set.of("name", "label", "title", "description", "email",
|
||||
"firstName", "lastName", "city", "state", "country", "code", "orderNo", "status");
|
||||
|
||||
/** The backends of the demo and sample data (QBit admin tables live on h2 too, and are left out). */
|
||||
private static final Set<String> SAMPLE_BACKENDS = Set.of("rdbms", "memory");
|
||||
private static final List<String> DEMO_TABLES = List.of("customer", "order", "address", "shipping_country",
|
||||
"shipping_stateProvince", "shipping_city");
|
||||
|
||||
/*******************************************************************************
|
||||
** Quick Search registrations for the demo tables and every visible sample-app
|
||||
** table with a record label: the label fields plus the obvious text fields,
|
||||
** STRING fields only (OpenSearch indexes them as searchable text; dates,
|
||||
** numbers and booleans stay out). Self-priming creates their index rows and
|
||||
** queues each for its first build.
|
||||
*******************************************************************************/
|
||||
static List<SearchableTableConfig> searchableTables(QInstance instance)
|
||||
{
|
||||
List<SearchableTableConfig> tables = new ArrayList<>();
|
||||
for(QTableMetaData table : instance.getTables().values())
|
||||
{
|
||||
boolean demo = DEMO_TABLES.contains(table.getName());
|
||||
boolean sample = SAMPLE_BACKENDS.contains(table.getBackendName()) && !table.getIsHidden()
|
||||
&& table.getRecordLabelFields() != null && !table.getRecordLabelFields().isEmpty();
|
||||
if(!demo && !sample)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Set<String> names = new LinkedHashSet<>();
|
||||
for(String labelField : Objects.requireNonNullElse(table.getRecordLabelFields(), List.<String>of()))
|
||||
{
|
||||
names.add(labelField);
|
||||
}
|
||||
names.addAll(SEARCHABLE_FIELD_NAMES);
|
||||
List<SearchableFieldConfig> fields = new ArrayList<>();
|
||||
for(String name : names)
|
||||
{
|
||||
QFieldMetaData field = table.getFields().get(name);
|
||||
if(field != null && field.getType() == QFieldType.STRING)
|
||||
{
|
||||
fields.add(new SearchableFieldConfig(name).withWeight(Objects.requireNonNullElse(table.getRecordLabelFields(), List.<String>of()).contains(name) ? 3 : 1));
|
||||
}
|
||||
}
|
||||
if(fields.isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
SearchableTableConfig config = new SearchableTableConfig(table.getName(), fields);
|
||||
if((table.getRecordLabelFields() == null || table.getRecordLabelFields().isEmpty()) && fields.stream().anyMatch(f -> "name".equals(f.getFieldName())))
|
||||
{
|
||||
///////////////////////////////////////////////////////////////
|
||||
// label hits by name where the table itself has no label //
|
||||
///////////////////////////////////////////////////////////////
|
||||
config.withRecordLabelFormat("%s", "name");
|
||||
}
|
||||
if(!table.getFields().containsKey("modifyDate"))
|
||||
{
|
||||
config.withBasepullTimestampField(null);
|
||||
}
|
||||
tables.add(config);
|
||||
}
|
||||
return (tables);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** The core profile has no apps and several qbits only add tables. Put the
|
||||
** demo tables in a "QQQ All" app and every visible table that no app reaches
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 https://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package com.kingsrook.qqq.all;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qbits.quicksearch.SearchableFieldConfig;
|
||||
import com.kingsrook.qbits.quicksearch.SearchableTableConfig;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/** Quick Search covers the demo and sample tables, with their text fields only. */
|
||||
class EnterpriseQuickSearchTablesTest
|
||||
{
|
||||
@TempDir Path dataDirectory;
|
||||
|
||||
@Test
|
||||
void demoAndSampleTablesWithTheirTextFields() throws Exception
|
||||
{
|
||||
QInstance instance = new QqqAllApplication(dataDirectory, "tcp://127.0.0.1:61616").defineQInstance();
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// a stand-in for a sample-app table: labelled, on the sample's //
|
||||
// backend, with fields OpenSearch must not index as text //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
instance.addBackend(new QBackendMetaData().withName("rdbms").withBackendType(MemoryBackendModule.class));
|
||||
instance.addTable(new QTableMetaData().withName("countryState").withBackendName("rdbms").withPrimaryKeyField("id")
|
||||
.withRecordLabelFormat("%s").withRecordLabelFields("name")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("name", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("description", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("code", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME)));
|
||||
|
||||
Map<String, List<String>> tables = EnterpriseFeatures.searchableTables(instance).stream()
|
||||
.collect(Collectors.toMap(SearchableTableConfig::getTableName,
|
||||
table -> table.getFields().stream().map(SearchableFieldConfig::getFieldName).toList()));
|
||||
|
||||
assertEquals(List.of("name", "email"), tables.get("customer").stream().sorted((a, b) -> a.equals("name") ? -1 : 1).toList());
|
||||
assertTrue(tables.get("shipping_stateProvince").contains("name"));
|
||||
assertEquals(List.of("name", "description"), tables.get("countryState"));
|
||||
assertFalse(tables.containsKey("webhook"), "QBit admin tables on h2 stay out");
|
||||
assertFalse(tables.containsKey("product"), "the filesystem product table is not a demo search table");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user