UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 21.4 kB
{"version":3,"file":"construct-brick-table.mjs","names":[],"sources":["../../../../src/services/documents-bricks/helpers/construct-brick-table.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport type BrickBuilder from \"../../../libs/collection/builders/brick-builder/index.js\";\nimport type CollectionBuilder from \"../../../libs/collection/builders/collection-builder/index.js\";\nimport registeredFields from \"../../../libs/collection/custom-fields/registered-fields.js\";\nimport {\n\tgetFieldDatabaseConfig,\n\tisStorageMode,\n} from \"../../../libs/collection/custom-fields/storage/index.js\";\nimport {\n\ttreeTableMode,\n\ttreeTableSchemaColumns,\n} from \"../../../libs/collection/custom-fields/storage/tree-table.js\";\nimport buildTableName from \"../../../libs/collection/helpers/build-table-name.js\";\nimport prefixGeneratedColName from \"../../../libs/collection/helpers/prefix-generated-column-name.js\";\nimport type { TableType } from \"../../../libs/collection/schema/types.js\";\nimport type { BrickInputSchema } from \"../../../schemas/collection-bricks.js\";\nimport type { FieldInputSchema } from \"../../../schemas/collection-fields.js\";\nimport type {\n\tFieldDatabaseMode,\n\tInsert,\n\tInternalDocumentBrick,\n\tInternalDocumentField,\n\tLucidBricksTable,\n\tLucidBrickTableName,\n} from \"../../../types.js\";\nimport processFieldValues from \"./process-field-values.js\";\n\nexport type InsertBrickTables = {\n\ttable: LucidBrickTableName;\n\tdata: Array<Partial<Insert<LucidBricksTable>>>;\n\tpriority: number;\n};\n\ntype ConstructField = FieldInputSchema | InternalDocumentField;\n\nexport type ConstructBrickTableParams = {\n\ttype: Exclude<TableType, \"versions\" | \"document\">;\n\tbrick?: BrickInputSchema | InternalDocumentBrick;\n\ttargetFields: ConstructField[];\n\tfieldPath?: Array<string>;\n\tpriority?: number;\n\tparentId?: Map<string, number> | null;\n\tparentIdRef?: Map<string, number>;\n\tbrickIdByLocale?: Map<string, number>; // Track brick_id_refs by locale\n\tcollection: CollectionBuilder;\n\tdocumentId: number;\n\tversionId: number;\n\tlocalization: {\n\t\tlocales: string[];\n\t\tdefaultLocale: string;\n\t};\n\tbrickKeyTableNameMap: Map<string, LucidBrickTableName>;\n\torder: number;\n\topen: boolean;\n\ttableNameByteLimit: number | null;\n};\n\ntype ChildTableBuild = Pick<\n\tConstructBrickTableParams,\n\t| \"type\"\n\t| \"targetFields\"\n\t| \"fieldPath\"\n\t| \"priority\"\n\t| \"parentId\"\n\t| \"parentIdRef\"\n\t| \"brickIdByLocale\"\n\t| \"order\"\n\t| \"open\"\n>;\n\ntype TableModeContext = Pick<\n\tConstructBrickTableParams,\n\t\"type\" | \"fieldPath\" | \"parentId\" | \"parentIdRef\" | \"brickIdByLocale\"\n>;\n\ntype FieldModeHandlerContext = {\n\tfield: ConstructField;\n\tparams: ConstructBrickTableParams;\n\trowsByLocale: Map<string, Partial<Insert<LucidBricksTable>>>;\n\tbrickIdRefByLocale: Map<string, number>;\n\tparentTableMode: FieldDatabaseMode;\n};\n\ntype FieldModeHandler = {\n\twriteColumns?: (context: FieldModeHandlerContext) => void;\n\tbuildChildTables?: (context: FieldModeHandlerContext) => ChildTableBuild[];\n};\n\n/**\n * Resolves the builder that owns the current target fields.\n */\nconst getFieldOwner = (\n\tparams: ConstructBrickTableParams,\n): CollectionBuilder | BrickBuilder | null => {\n\tif (!params.brick?.key) return params.collection;\n\n\treturn (\n\t\tparams.collection.brickInstances.find(\n\t\t\t(item) => item.key === params.brick?.key,\n\t\t) ?? null\n\t);\n};\n\nconst createTempRelationId = (): number => {\n\treturn -Math.abs(\n\t\tNumber.parseInt(crypto.randomBytes(3).toString(\"hex\"), 16) % 2147483647,\n\t);\n};\n\nconst getTableMode = (\n\ttype: Exclude<TableType, \"versions\" | \"document\">,\n): FieldDatabaseMode => {\n\treturn getFieldDatabaseConfig(type)?.mode ?? \"column\";\n};\n\nconst getTablePriority = (params: {\n\tmode: FieldDatabaseMode;\n\tfieldPath?: string[];\n\tpriority?: number;\n}): number => {\n\tif (typeof params.priority === \"number\") return params.priority;\n\n\tswitch (params.mode) {\n\t\tcase \"tree-table\":\n\t\t\treturn treeTableMode.getInsertPriority(params.fieldPath);\n\t\tcase \"column\":\n\t\tcase \"ignore\":\n\t\tcase \"relation-table\":\n\t\t\treturn 0;\n\t}\n};\n\nconst applyTableModeColumns = (context: {\n\tmode: FieldDatabaseMode;\n\trow: Partial<Insert<LucidBricksTable>>;\n\tlocale: string;\n\tparams: TableModeContext;\n}): void => {\n\tswitch (context.mode) {\n\t\tcase \"tree-table\":\n\t\t\tcontext.row[treeTableSchemaColumns.parentId] =\n\t\t\t\tcontext.params.parentId?.get(context.locale) || null;\n\t\t\tcontext.row[treeTableSchemaColumns.parentIdRef] =\n\t\t\t\tcontext.params.parentIdRef?.get(context.locale);\n\n\t\t\tif (context.params.brickIdByLocale?.has(context.locale)) {\n\t\t\t\tcontext.row[treeTableSchemaColumns.rootId] =\n\t\t\t\t\tcontext.params.brickIdByLocale.get(context.locale);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"column\":\n\t\tcase \"ignore\":\n\t\tcase \"relation-table\":\n\t\t\tbreak;\n\t}\n};\n\nconst fieldModeHandlers: Record<FieldDatabaseMode, FieldModeHandler> = {\n\tcolumn: {\n\t\twriteColumns: (context) => {\n\t\t\tif (!context.field.key) return;\n\n\t\t\tconst valuesByLocale = processFieldValues(\n\t\t\t\tcontext.field,\n\t\t\t\tcontext.params.localization.locales,\n\t\t\t\tcontext.params.localization.defaultLocale,\n\t\t\t);\n\n\t\t\tfor (const locale of context.params.localization.locales) {\n\t\t\t\tconst row = context.rowsByLocale.get(locale);\n\t\t\t\tif (!row) continue;\n\n\t\t\t\trow[prefixGeneratedColName(context.field.key)] =\n\t\t\t\t\tvaluesByLocale.get(locale);\n\t\t\t}\n\t\t},\n\t},\n\tignore: {},\n\t\"tree-table\": {\n\t\tbuildChildTables: (context) => {\n\t\t\tconst databaseConfig =\n\t\t\t\tregisteredFields[context.field.type].config.database;\n\t\t\tif (!isStorageMode(databaseConfig, \"tree-table\")) return [];\n\t\t\tif (!context.field.key) return [];\n\t\t\tif (!context.field.groups || context.field.groups.length === 0) return [];\n\n\t\t\tconst fieldPath = context.params.fieldPath\n\t\t\t\t? [...context.params.fieldPath, context.field.key]\n\t\t\t\t: [context.field.key];\n\n\t\t\treturn context.field.groups.flatMap((group, groupIndex) => {\n\t\t\t\tif (!group.fields) return [];\n\n\t\t\t\tconst localeGroupRef = new Map<string, number>();\n\t\t\t\tfor (const locale of context.params.localization.locales) {\n\t\t\t\t\tlocaleGroupRef.set(locale, createTempRelationId());\n\t\t\t\t}\n\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: databaseConfig.tableType,\n\t\t\t\t\t\ttargetFields: group.fields,\n\t\t\t\t\t\tfieldPath: fieldPath,\n\t\t\t\t\t\tparentId:\n\t\t\t\t\t\t\tcontext.parentTableMode === \"tree-table\"\n\t\t\t\t\t\t\t\t? context.params.parentIdRef || null\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tparentIdRef: localeGroupRef,\n\t\t\t\t\t\tbrickIdByLocale:\n\t\t\t\t\t\t\tcontext.params.type === \"brick\" ||\n\t\t\t\t\t\t\tcontext.params.type === \"document-fields\"\n\t\t\t\t\t\t\t\t? context.brickIdRefByLocale\n\t\t\t\t\t\t\t\t: context.params.brickIdByLocale,\n\t\t\t\t\t\torder: group.order !== undefined ? group.order : groupIndex,\n\t\t\t\t\t\topen: group.open ?? false,\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t});\n\t\t},\n\t},\n\t\"relation-table\": {\n\t\tbuildChildTables: (context) => {\n\t\t\tconst databaseConfig =\n\t\t\t\tregisteredFields[context.field.type].config.database;\n\t\t\tif (!isStorageMode(databaseConfig, \"relation-table\")) return [];\n\t\t\tif (!context.field.key) return [];\n\n\t\t\tconst parentId =\n\t\t\t\tcontext.parentTableMode === \"tree-table\"\n\t\t\t\t\t? context.params.parentIdRef\n\t\t\t\t\t: context.params.type === \"brick\" ||\n\t\t\t\t\t\t\tcontext.params.type === \"document-fields\"\n\t\t\t\t\t\t? context.brickIdRefByLocale\n\t\t\t\t\t\t: context.params.brickIdByLocale;\n\t\t\tif (!parentId) return [];\n\n\t\t\tconst parentPriority = getTablePriority({\n\t\t\t\tmode: context.parentTableMode,\n\t\t\t\tfieldPath: context.params.fieldPath,\n\t\t\t\tpriority: context.params.priority,\n\t\t\t});\n\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\ttype: databaseConfig.tableType,\n\t\t\t\t\ttargetFields: [context.field],\n\t\t\t\t\tfieldPath: [context.field.key],\n\t\t\t\t\tpriority: parentPriority + 1,\n\t\t\t\t\tparentId: parentId,\n\t\t\t\t\tparentIdRef: parentId,\n\t\t\t\t\tbrickIdByLocale: undefined,\n\t\t\t\t\torder: 0,\n\t\t\t\t\topen: false,\n\t\t\t\t},\n\t\t\t];\n\t\t},\n\t},\n};\n\n/**\n * Builds one insert row per localized relation value for relation-table fields.\n */\nconst constructRelationTableRows = (\n\tparams: ConstructBrickTableParams,\n): Array<Partial<Insert<LucidBricksTable>>> => {\n\tconst field = params.targetFields[0];\n\tif (!field?.key) return [];\n\n\tconst fieldOwner = getFieldOwner(params);\n\tif (!fieldOwner) return [];\n\n\tconst fieldInstance = fieldOwner.fields.get(field.key);\n\tif (!fieldInstance) return [];\n\n\tconst valuesByLocale = processFieldValues(\n\t\tfield,\n\t\tparams.localization.locales,\n\t\tparams.localization.defaultLocale,\n\t);\n\tconst rows: Array<Partial<Insert<LucidBricksTable>>> = [];\n\n\tfor (const locale of params.localization.locales) {\n\t\tconst parentId = params.parentId?.get(locale);\n\t\tif (typeof parentId !== \"number\") continue;\n\n\t\tconst relationRows = fieldInstance.serializeRelationFieldValue(\n\t\t\tvaluesByLocale.get(locale),\n\t\t);\n\n\t\trelationRows.forEach((relationRow, index) => {\n\t\t\trows.push({\n\t\t\t\tcollection_key: params.collection.key,\n\t\t\t\tdocument_id: params.documentId,\n\t\t\t\tdocument_version_id: params.versionId,\n\t\t\t\tlocale: locale,\n\t\t\t\tposition: index,\n\t\t\t\tparent_id: parentId,\n\t\t\t\t...relationRow,\n\t\t\t});\n\t\t});\n\t}\n\n\treturn rows;\n};\n\n/**\n * Generate a key for mapping brick to table names.\n * Stops us from doing duplicate work generating table names.\n */\nconst genTableMapKey = (params: {\n\tbrickKey?: string;\n\tfieldPath?: Array<string>;\n}): string => {\n\tconst prefix = params.brickKey ?? \"pseudo-brick\";\n\tif (!params.fieldPath || params.fieldPath.length === 0) return prefix;\n\treturn `${prefix}:${params.fieldPath.join(\":\")}`;\n};\n\n/**\n * Construct brick/tree-table table data ready to insert into the DB\n */\nconst constructBrickTable = (\n\tbrickTables: Array<InsertBrickTables>,\n\tparams: ConstructBrickTableParams,\n): void => {\n\tconst tableMode = getTableMode(params.type);\n\n\tif (tableMode === \"relation-table\") {\n\t\tconst relationRows = constructRelationTableRows(params);\n\t\tif (relationRows.length === 0) return;\n\n\t\tconst mapKey = genTableMapKey({\n\t\t\tbrickKey: params.brick?.key,\n\t\t\tfieldPath: params.fieldPath,\n\t\t});\n\n\t\tlet tableName: LucidBrickTableName;\n\t\tif (params.brickKeyTableNameMap.has(mapKey)) {\n\t\t\t// biome-ignore lint/style/noNonNullAssertion: explanation\n\t\t\ttableName = params.brickKeyTableNameMap.get(mapKey)!;\n\t\t} else {\n\t\t\tconst brickTableNameRes = buildTableName<LucidBrickTableName>(\n\t\t\t\tparams.type,\n\t\t\t\t{\n\t\t\t\t\tcollection: params.collection.key,\n\t\t\t\t\tbrick: params.brick?.key,\n\t\t\t\t\tfieldPath: params.fieldPath,\n\t\t\t\t},\n\t\t\t\tparams.tableNameByteLimit,\n\t\t\t);\n\t\t\tif (brickTableNameRes.error) return;\n\t\t\ttableName = brickTableNameRes.data.name;\n\t\t\tparams.brickKeyTableNameMap.set(mapKey, brickTableNameRes.data.name);\n\t\t}\n\n\t\tconst tableIndex = brickTables.findIndex(\n\t\t\t(table) => table.table === tableName,\n\t\t);\n\t\tif (tableIndex === -1) {\n\t\t\tbrickTables.push({\n\t\t\t\ttable: tableName,\n\t\t\t\tdata: relationRows,\n\t\t\t\tpriority: getTablePriority({\n\t\t\t\t\tmode: tableMode,\n\t\t\t\t\tfieldPath: params.fieldPath,\n\t\t\t\t\tpriority: params.priority,\n\t\t\t\t}),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tbrickTables[tableIndex]?.data.push(...relationRows);\n\t\treturn;\n\t}\n\n\t//* get or build the table name\n\tconst mapKey = genTableMapKey({\n\t\tbrickKey: params.brick?.key,\n\t\tfieldPath: params.fieldPath,\n\t});\n\n\tlet tableName: LucidBrickTableName;\n\tif (params.brickKeyTableNameMap.has(mapKey)) {\n\t\t// biome-ignore lint/style/noNonNullAssertion: explanation\n\t\ttableName = params.brickKeyTableNameMap.get(mapKey)!;\n\t} else {\n\t\tconst brickTableNameRes = buildTableName<LucidBrickTableName>(\n\t\t\tparams.type,\n\t\t\t{\n\t\t\t\tcollection: params.collection.key,\n\t\t\t\tbrick: params.brick?.key,\n\t\t\t\tfieldPath: params.fieldPath,\n\t\t\t},\n\t\t\tparams.tableNameByteLimit,\n\t\t);\n\t\tif (brickTableNameRes.error) return;\n\t\ttableName = brickTableNameRes.data.name;\n\t\tparams.brickKeyTableNameMap.set(mapKey, brickTableNameRes.data.name);\n\t}\n\n\t//* find existing table or create new one\n\tlet tableIndex = brickTables.findIndex((table) => table.table === tableName);\n\tif (tableIndex === -1) {\n\t\tbrickTables.push({\n\t\t\ttable: tableName,\n\t\t\tdata: [],\n\t\t\tpriority: getTablePriority({\n\t\t\t\tmode: tableMode,\n\t\t\t\tfieldPath: params.fieldPath,\n\t\t\t\tpriority: params.priority,\n\t\t\t}),\n\t\t});\n\t\ttableIndex = brickTables.length - 1;\n\t}\n\n\tconst brickInstanceId = crypto.randomUUID();\n\tconst rowsByLocale = new Map<string, Partial<Insert<LucidBricksTable>>>();\n\tconst brickIdRefByLocale = new Map<string, number>();\n\n\t//* initialize rows for each locale\n\tfor (const locale of params.localization.locales) {\n\t\tconst baseRowData: Partial<Insert<LucidBricksTable>> = {\n\t\t\tcollection_key: params.collection.key,\n\t\t\tdocument_id: params.documentId,\n\t\t\tdocument_version_id: params.versionId,\n\t\t\tlocale: locale,\n\t\t\tposition: params.order,\n\t\t};\n\t\tbaseRowData.is_open = params.open;\n\n\t\tif (params.type === \"brick\") {\n\t\t\tbaseRowData.brick_type = params.brick?.type;\n\t\t\tbaseRowData.brick_instance_id = brickInstanceId;\n\t\t}\n\n\t\t//* generate brick_id_ref for each brick by locale\n\t\tif (params.type === \"brick\" || params.type === \"document-fields\") {\n\t\t\tconst localeSpecificBrickRef = createTempRelationId();\n\t\t\tbaseRowData.brick_id_ref = localeSpecificBrickRef;\n\t\t\tbrickIdRefByLocale.set(locale, localeSpecificBrickRef);\n\t\t}\n\n\t\tapplyTableModeColumns({\n\t\t\tmode: tableMode,\n\t\t\trow: baseRowData,\n\t\t\tlocale: locale,\n\t\t\tparams,\n\t\t});\n\n\t\trowsByLocale.set(locale, baseRowData);\n\t}\n\n\tconst childTableBuilds: ChildTableBuild[] = [];\n\n\tfor (const field of params.targetFields) {\n\t\tconst fieldMode = registeredFields[field.type].config.database.mode;\n\t\tconst handler = fieldModeHandlers[fieldMode];\n\n\t\thandler.writeColumns?.({\n\t\t\tfield,\n\t\t\tparams,\n\t\t\trowsByLocale,\n\t\t\tbrickIdRefByLocale,\n\t\t\tparentTableMode: tableMode,\n\t\t});\n\n\t\tconst fieldChildBuilds = handler.buildChildTables?.({\n\t\t\tfield,\n\t\t\tparams,\n\t\t\trowsByLocale,\n\t\t\tbrickIdRefByLocale,\n\t\t\tparentTableMode: tableMode,\n\t\t});\n\t\tif (!fieldChildBuilds) continue;\n\t\tchildTableBuilds.push(...fieldChildBuilds);\n\t}\n\n\t//* add the rows to the table\n\tfor (const row of rowsByLocale.values()) {\n\t\tbrickTables[tableIndex]?.data.push(row);\n\t}\n\n\tfor (const childBuild of childTableBuilds) {\n\t\tconstructBrickTable(brickTables, {\n\t\t\ttype: childBuild.type,\n\t\t\tcollection: params.collection,\n\t\t\tdocumentId: params.documentId,\n\t\t\tversionId: params.versionId,\n\t\t\ttargetFields: childBuild.targetFields,\n\t\t\tfieldPath: childBuild.fieldPath,\n\t\t\tpriority: childBuild.priority,\n\t\t\tparentId: childBuild.parentId,\n\t\t\tparentIdRef: childBuild.parentIdRef,\n\t\t\tbrickIdByLocale: childBuild.brickIdByLocale,\n\t\t\tlocalization: params.localization,\n\t\t\tbrickKeyTableNameMap: params.brickKeyTableNameMap,\n\t\t\tbrick: params.brick,\n\t\t\torder: childBuild.order,\n\t\t\topen: childBuild.open,\n\t\t\ttableNameByteLimit: params.tableNameByteLimit,\n\t\t});\n\t}\n};\n\nexport default constructBrickTable;\n"],"mappings":"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"}