Update client side lucene searching to work with nested JSON fields and fix bug with flattening nested JSON schema

This commit is contained in:
Andrew Kingston 2021-12-06 12:04:22 +00:00
parent cd5d370e7b
commit d10d332b9f
5 changed files with 44 additions and 19 deletions

View File

@ -410,6 +410,7 @@ export const getSchemaForDatasource = (asset, datasource, isForm = false) => {
jsonSchema = jsonSchema[keysToSchema[i]].schema jsonSchema = jsonSchema[keysToSchema[i]].schema
} }
schema = convertJSONSchemaToTableSchema(jsonSchema, true) schema = convertJSONSchemaToTableSchema(jsonSchema, true)
console.log(schema)
} }
// Otherwise we assume we're targeting an internal table or a plus // Otherwise we assume we're targeting an internal table or a plus

View File

@ -1,11 +1,14 @@
export const convertJSONSchemaToTableSchema = jsonSchema => { export const convertJSONSchemaToTableSchema = (
jsonSchema,
squashObjects = false
) => {
if (!jsonSchema) { if (!jsonSchema) {
return null return null
} }
if (jsonSchema.schema) { if (jsonSchema.schema) {
jsonSchema = jsonSchema.schema jsonSchema = jsonSchema.schema
} }
const keys = extractJSONSchemaKeys(jsonSchema) const keys = extractJSONSchemaKeys(jsonSchema, squashObjects)
let schema = {} let schema = {}
keys.forEach(({ key, type }) => { keys.forEach(({ key, type }) => {
schema[key] = { type, name: key } schema[key] = { type, name: key }

View File

@ -21,7 +21,7 @@
export let panel = ClientBindingPanel export let panel = ClientBindingPanel
export let allowBindings = true export let allowBindings = true
const BannedTypes = ["link", "attachment", "formula"] const BannedTypes = ["link", "attachment", "formula", "json"]
$: fieldOptions = (schemaFields ?? []) $: fieldOptions = (schemaFields ?? [])
.filter(field => !BannedTypes.includes(field.type)) .filter(field => !BannedTypes.includes(field.type))

View File

@ -99,6 +99,7 @@ export const luceneQuery = (docs, query) => {
if (!query) { if (!query) {
return docs return docs
} }
// make query consistent first // make query consistent first
query = cleanupQuery(query) query = cleanupQuery(query)
@ -106,7 +107,9 @@ export const luceneQuery = (docs, query) => {
const match = (type, failFn) => doc => { const match = (type, failFn) => doc => {
const filters = Object.entries(query[type] || {}) const filters = Object.entries(query[type] || {})
for (let i = 0; i < filters.length; i++) { for (let i = 0; i < filters.length; i++) {
if (failFn(filters[i][0], filters[i][1], doc)) { const [key, testValue] = filters[i]
const docValue = deepGet(doc, key)
if (failFn(docValue, testValue)) {
return false return false
} }
} }
@ -114,38 +117,38 @@ export const luceneQuery = (docs, query) => {
} }
// Process a string match (fails if the value does not start with the string) // Process a string match (fails if the value does not start with the string)
const stringMatch = match("string", (key, value, doc) => { const stringMatch = match("string", (docValue, testValue) => {
return !doc[key] || !doc[key].startsWith(value) return !docValue || !docValue.startsWith(testValue)
}) })
// Process a fuzzy match (treat the same as starts with when running locally) // Process a fuzzy match (treat the same as starts with when running locally)
const fuzzyMatch = match("fuzzy", (key, value, doc) => { const fuzzyMatch = match("fuzzy", (docValue, testValue) => {
return !doc[key] || !doc[key].startsWith(value) return !docValue || !docValue.startsWith(testValue)
}) })
// Process a range match // Process a range match
const rangeMatch = match("range", (key, value, doc) => { const rangeMatch = match("range", (docValue, testValue) => {
return !doc[key] || doc[key] < value.low || doc[key] > value.high return !docValue || docValue < testValue.low || docValue > testValue.high
}) })
// Process an equal match (fails if the value is different) // Process an equal match (fails if the value is different)
const equalMatch = match("equal", (key, value, doc) => { const equalMatch = match("equal", (docValue, testValue) => {
return value != null && value !== "" && doc[key] !== value return testValue != null && testValue !== "" && docValue !== testValue
}) })
// Process a not-equal match (fails if the value is the same) // Process a not-equal match (fails if the value is the same)
const notEqualMatch = match("notEqual", (key, value, doc) => { const notEqualMatch = match("notEqual", (docValue, testValue) => {
return value != null && value !== "" && doc[key] === value return testValue != null && testValue !== "" && docValue === testValue
}) })
// Process an empty match (fails if the value is not empty) // Process an empty match (fails if the value is not empty)
const emptyMatch = match("empty", (key, value, doc) => { const emptyMatch = match("empty", docValue => {
return doc[key] != null && doc[key] !== "" return docValue != null && docValue !== ""
}) })
// Process a not-empty match (fails is the value is empty) // Process a not-empty match (fails is the value is empty)
const notEmptyMatch = match("notEmpty", (key, value, doc) => { const notEmptyMatch = match("notEmpty", docValue => {
return doc[key] == null || doc[key] === "" return docValue == null || docValue === ""
}) })
// Match a document against all criteria // Match a document against all criteria
@ -202,3 +205,21 @@ export const luceneLimit = (docs, limit) => {
} }
return docs.slice(0, numLimit) return docs.slice(0, numLimit)
} }
/**
* Gets a key within an object. The key supports dot syntax for retriving deep
* fields - e.g. "a.b.c".
* @param obj the object
* @param key the key
*/
const deepGet = (obj, key) => {
if (!obj || !key) {
return null
}
const split = key.split(".")
let value = obj
for (let i = 0; i < split.length; i++) {
value = value?.[split[i]]
}
return value
}

View File

@ -19,7 +19,7 @@
export let schemaFields export let schemaFields
export let filters = [] export let filters = []
const BannedTypes = ["link", "attachment", "formula"] const BannedTypes = ["link", "attachment", "formula", "json"]
$: fieldOptions = (schemaFields ?? []) $: fieldOptions = (schemaFields ?? [])
.filter(field => !BannedTypes.includes(field.type)) .filter(field => !BannedTypes.includes(field.type))