diff --git a/admin/src/components/SchemaMapper/index.js b/admin/src/components/SchemaMapper/index.js index ee348e3..ed05266 100644 --- a/admin/src/components/SchemaMapper/index.js +++ b/admin/src/components/SchemaMapper/index.js @@ -1,97 +1,20 @@ -import React from "react" -import { - Box, - Checkbox, - Flex, - Switch, - Table, - Thead, - Tbody, - Tr, - Th, - Td, - Tooltip, - Typography, - Status -} from "@strapi/design-system" -import WarningIcon from "../WarningIcon" -import { getSelectedPropsFromObj, getSelectedAttributesFromSchema } from "../../../../utils/schema" - -const isCollection = (value) => Array.isArray(value) && value.length > 0 && typeof value[0] === "object" - -const handleObjectField = (acc, fieldKey, fieldValue, relations) => { - if (relations.includes(fieldKey)) { - Object.keys(fieldValue).forEach((key) => acc.push(`${fieldKey}.${key}`)) - } -} - -const handleCollectionField = (acc, fieldKey, fieldValue, relations) => { - if (relations.includes(fieldKey)) { - acc.push(fieldKey) - } -} +import React from 'react' +import { Box, Checkbox, Flex, Switch, Table, Thead, Tbody, Tr, Th, Td, Typography } from '@strapi/design-system' +import { getSelectedPropsFromObj, getSelectedAttributesFromSchema } from '../../../../utils' const generateSelectableAttributesFromSchema = ({ schema, relations }) => { - const handlers = { - object: handleObjectField, - collection: handleCollectionField - } - return Object.entries(schema).reduce((acc, [fieldKey, fieldValue]) => { - const fieldType = fieldValue === "collection" ? "collection" : typeof fieldValue - - if (fieldType in handlers) { - handlers[fieldType](acc, fieldKey, fieldValue, relations) - } else if (!isCollection(fieldValue)) { + if (typeof fieldValue === 'object') { + if (relations.includes(fieldKey)) { + Object.keys(fieldValue).forEach((key) => acc.push(`${fieldKey}.${key}`)) + } + } else { acc.push(fieldKey) } - return acc }, []) } -const AttributeRow = ({ contentTypeSchema, field, isChecked, onCheck, isSearchableSelected, onSearchableSwitch, needsTransformation }) => ( - - - onCheck(field)} /> - - onCheck(field)} - style={{ cursor: "pointer", display: "flex", alignItems: "center" }} - > - {field} - {contentTypeSchema[field] === "collection" && needsTransformation && ( - <> - - -
- - Action required -
-
-
- - )} - - - - onSearchableSwitch(field)} /> - - - -) - const SchemaMapper = ({ collection, contentTypeSchema, onSchemaChange }) => { const [selectedAttributes, setSelectedAttributes] = React.useState( getSelectedAttributesFromSchema({ @@ -154,12 +77,10 @@ const SchemaMapper = ({ collection, contentTypeSchema, onSchemaChange }) => { } } - const collectionDocumentsTransformers = collection?.documentsTransformers || {} - return ( - Attributes Mapping * + Attributes Mapping* @@ -167,7 +88,13 @@ const SchemaMapper = ({ collection, contentTypeSchema, onSchemaChange }) => { - + {/*TODO: style this*/} + {collection.hasSettings && ( + + The schema is handled by the Orama Cloud plugin settings. + + )} + {!collection.hasSettings && (
- - {schemaAttributes.map( - (field) => ( - - ) - )} + {schemaAttributes.map((field) => ( + + + + + + ))} -
@@ -177,15 +104,15 @@ const SchemaMapper = ({ collection, contentTypeSchema, onSchemaChange }) => { onChange={() => selectAllAttributes()} /> + Attribute
Searchable @@ -194,22 +121,23 @@ const SchemaMapper = ({ collection, contentTypeSchema, onSchemaChange }) => {
+ handleCheck(field)} /> + handleCheck(field)} style={{ cursor: 'pointer' }}> + {field} + + + handleSearchable(field)} /> + +
+ )}
) diff --git a/server/content-types/collection/index.js b/server/content-types/collection/index.js index a9c84db..71781e4 100644 --- a/server/content-types/collection/index.js +++ b/server/content-types/collection/index.js @@ -1,7 +1,7 @@ // @ts-nocheck 'use strict' -const schema = require('./schema') +const schema = require('./schema.json') const lifecycles = require('./lifecycles') module.exports = { diff --git a/server/services/collections.js b/server/services/collections.js index 7d15e1d..f9b7263 100644 --- a/server/services/collections.js +++ b/server/services/collections.js @@ -12,26 +12,25 @@ module.exports = ({ strapi }) => { async find() { const collections = await strapi.entityService.findMany(ENTITY_NAME) - const result = collectionSettings ? collections.map(collection => { + return collectionSettings ? collections.reduce((acc, collection) => { const settings = collectionSettings[collection.indexId] - const hasTransformers = !!settings?.documentsTransformer - - if (hasTransformers) { - const documentsTransformers = Object.keys(settings.documentsTransformer).reduce((acc, key) => { - acc[key] = true - return acc - }, {}) - - return { - ...collection, - documentsTransformers, + const hasValidSettings = settings?.schema && settings?.transformer + + if (settings) { + if (hasValidSettings) { + acc.push({ + ...collection, + hasSettings: true, + }) + } else { + strapi.log.warn(`Collection with indexId ${collection.indexId} has settings but no schema or transformer`) } + } else { + acc.push(collection) } - return collection - }) : collections - - return result + return acc + }, []) : collections }, /** diff --git a/server/services/orama-manager.js b/server/services/orama-manager.js index 6183f65..d5aafd4 100644 --- a/server/services/orama-manager.js +++ b/server/services/orama-manager.js @@ -1,7 +1,7 @@ 'use strict' const { CloudManager } = require('@oramacloud/client') -const { getSchemaFromEntryStructure, getSelectedPropsFromObj } = require('../../utils/schema') +const { getSelectedPropsFromObj } = require('../../utils') class OramaManager { constructor({ strapi }) { @@ -26,6 +26,8 @@ class OramaManager { * @param {Object} collection - Collection object * */ validate(collection) { + const collectionSettings = this.collectionSettings?.[collection.indexId] + if (!collection) { this.strapi.log.error(`Collection not found`) return false @@ -50,6 +52,13 @@ class OramaManager { return false } + if ((collectionSettings.schema && !collectionSettings.transformer) || (!collectionSettings.schema && collectionSettings.transformer)) { + this.strapi.log.error( + `ERROR: Both schema and transformer are required in the collection settings` + ) + return false + } + return true } @@ -61,19 +70,13 @@ class OramaManager { * @param {Array} entries - Array of entries * */ documentsTransformer(indexId, entries) { - const transformerFnMap = this.collectionSettings?.[indexId]?.documentsTransformer + const transformer = this.collectionSettings?.[indexId]?.transformer - if (!transformerFnMap) { + if (!transformer) { return entries } - return entries.map((entry) => { - return Object.entries(entry) - .map(([key, value]) => ({ - [key]: transformerFnMap[key]?.(value) ?? value - })) - .reduce((acc, curr) => ({ ...acc, ...curr }), {}) - }) + return entries.map(transformer) } /* @@ -148,19 +151,6 @@ class OramaManager { }) if (entries.length > 0) { - if (offset === 0) { - const transformedEntries = this.documentsTransformer(collection.indexId, entries) - const filteredEntry = getSelectedPropsFromObj({ - props: collection.searchableAttributes, - obj: transformedEntries[0] - }) - - await this.oramaUpdateSchema({ - indexId: collection.indexId, - schema: getSchemaFromEntryStructure(filteredEntry) - }) - } - await this.oramaInsert({ indexId: collection.indexId, entries @@ -190,16 +180,16 @@ class OramaManager { * */ async oramaInsert({ indexId, entries }) { const index = this.oramaCloudManager.index(indexId) - const formattedData = this.documentsTransformer(indexId, entries) + const transformedData = this.documentsTransformer(indexId, entries) - if (!formattedData) { + if (!transformedData) { this.strapi.log.error(`ERROR: documentsTransformer needs a return value`) return false } - const result = await index.insert(formattedData) + const result = await index.insert(transformedData) - this.strapi.log.info(`INSERT: documents with id ${formattedData.map(({ id }) => id)} into index ${indexId}`) + this.strapi.log.info(`INSERT: documents with id ${transformedData.map(({ id }) => id)} into index ${indexId}`) return result } @@ -212,16 +202,16 @@ class OramaManager { * */ async oramaUpdate({ indexId, entries }) { const index = this.oramaCloudManager.index(indexId) - const formattedData = this.documentsTransformer(entries) || entries + const transformedData = this.documentsTransformer(indexId, entries) - if (!formattedData) { + if (!transformedData) { this.strapi.log.error(`ERROR: documentsTransformer needs a return value`) return false } - const result = await index.update(formattedData) + const result = await index.update(transformedData) - this.strapi.log.info(`UPDATE: document with id ${formattedData.map(({ id }) => id)} into index ${indexId}`) + this.strapi.log.info(`UPDATE: document with id ${transformedData.map(({ id }) => id)} into index ${indexId}`) return result } @@ -269,13 +259,27 @@ class OramaManager { return } + const customSchema = this.collectionSettings?.[collection.indexId]?.schema + + const oramaSchema = customSchema ?? getSelectedPropsFromObj({ + props: collection.searchableAttributes, + obj: collection.schema + }) + await this.updatingStarted(collection) await this.resetIndex(collection) + await this.oramaUpdateSchema({ + indexId: collection.indexId, + schema: oramaSchema + }) + const { documents_count } = await this.bulkInsert(collection) - await this.oramaDeployIndex(collection) + if (documents_count > 0) { + await this.oramaDeployIndex(collection) + } await this.updatingCompleted(collection, documents_count) } diff --git a/utils/schema.js b/utils/index.js similarity index 95% rename from utils/schema.js rename to utils/index.js index 6704ba4..349eee7 100644 --- a/utils/schema.js +++ b/utils/index.js @@ -1,3 +1,4 @@ +const { collection } = require("../server/content-types") const getSelectedPropsFromObj = ({ props, obj }) => { return props.reduce((acc, field) => { if (field.includes('.')) { diff --git a/utils/schema.test.js b/utils/index.test.js similarity index 97% rename from utils/schema.test.js rename to utils/index.test.js index 1d36d91..6b19eb7 100644 --- a/utils/schema.test.js +++ b/utils/index.test.js @@ -1,4 +1,4 @@ -const { getSelectedPropsFromObj, getSelectedAttributesFromSchema, getSchemaFromEntryStructure } = require('./schema') +const { getSelectedPropsFromObj, getSelectedAttributesFromSchema, getSchemaFromEntryStructure } = require('./index') describe('Schema Utils', () => { describe('getSelectedPropsFromObj', () => {