@puls-atlas/cli
Version:
The Puls Atlas CLI tool for managing Atlas projects
182 lines • 8.3 kB
JavaScript
import { isPlainObject } from 'es-toolkit/compat';
import { normalizeOptionalString } from '../../../utils/value.js';
import { resolveSearchSourceCapabilities } from './capabilities.js';
const normalizeStringArray = value => {
if (!Array.isArray(value)) {
return [];
}
return [...new Set(value.map(entry => normalizeOptionalString(entry)).filter(Boolean))];
};
const filterNullEntries = value => Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== null));
const normalizeOptionalStringRecord = value => {
if (!isPlainObject(value)) {
return null;
}
const normalizedEntries = filterNullEntries(Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, normalizeOptionalString(entryValue)])));
return Object.keys(normalizedEntries).length > 0 ? normalizedEntries : null;
};
const normalizeOptionalObject = value => isPlainObject(value) ? value : null;
const normalizeSearchSourceEventarcConfig = eventarcConfig => {
if (!isPlainObject(eventarcConfig)) {
return null;
}
return filterNullEntries({
database: normalizeOptionalString(eventarcConfig.database),
documentPathPattern: normalizeOptionalString(eventarcConfig.documentPathPattern),
triggerRegion: normalizeOptionalString(eventarcConfig.triggerRegion)
});
};
const normalizeSearchSourceRequestConfig = requestConfig => {
if (!isPlainObject(requestConfig)) {
return null;
}
return filterNullEntries({
body: normalizeOptionalObject(requestConfig.body),
headers: normalizeOptionalStringRecord(requestConfig.headers),
method: normalizeOptionalString(requestConfig.method),
query: normalizeOptionalStringRecord(requestConfig.query),
url: normalizeOptionalString(requestConfig.url)
});
};
const normalizeSearchSourceIncrementalCursorRequestConfig = cursorRequestConfig => {
if (!isPlainObject(cursorRequestConfig)) {
return null;
}
return filterNullEntries({
bodyPath: normalizeOptionalString(cursorRequestConfig.bodyPath),
headerName: normalizeOptionalString(cursorRequestConfig.headerName),
queryParam: normalizeOptionalString(cursorRequestConfig.queryParam)
});
};
const normalizeSearchSourceIncrementalCursorResponseConfig = cursorResponseConfig => {
if (!isPlainObject(cursorResponseConfig)) {
return null;
}
return filterNullEntries({
hasMorePath: normalizeOptionalString(cursorResponseConfig.hasMorePath),
nextCursorPath: normalizeOptionalString(cursorResponseConfig.nextCursorPath)
});
};
const normalizeSearchSourceIncrementalCursorConfig = cursorConfig => {
if (!isPlainObject(cursorConfig)) {
return null;
}
return filterNullEntries({
idColumn: normalizeOptionalString(cursorConfig.idColumn),
request: normalizeSearchSourceIncrementalCursorRequestConfig(cursorConfig.request),
response: normalizeSearchSourceIncrementalCursorResponseConfig(cursorConfig.response),
versionColumn: normalizeOptionalString(cursorConfig.versionColumn)
});
};
const normalizeSearchSourceIncrementalMappingConfig = mappingConfig => {
if (!isPlainObject(mappingConfig)) {
return null;
}
return filterNullEntries({
afterPath: normalizeOptionalString(mappingConfig.afterPath),
beforePath: normalizeOptionalString(mappingConfig.beforePath),
deletedPath: normalizeOptionalString(mappingConfig.deletedPath),
idPath: normalizeOptionalString(mappingConfig.idPath),
versionPath: normalizeOptionalString(mappingConfig.versionPath)
});
};
const normalizeSearchSourceIncrementalResponseConfig = responseConfig => {
if (!isPlainObject(responseConfig)) {
return null;
}
return filterNullEntries({
itemsPath: normalizeOptionalString(responseConfig.itemsPath)
});
};
const normalizeSearchSourceIncrementalConfig = incrementalConfig => {
if (!isPlainObject(incrementalConfig)) {
return null;
}
return filterNullEntries({
batchSize: Number.isInteger(incrementalConfig.batchSize) && incrementalConfig.batchSize > 0 ? incrementalConfig.batchSize : null,
cursor: normalizeSearchSourceIncrementalCursorConfig(incrementalConfig.cursor),
deleteStrategy: normalizeOptionalString(incrementalConfig.deleteStrategy),
deletedColumn: normalizeOptionalString(incrementalConfig.deletedColumn),
idColumn: normalizeOptionalString(incrementalConfig.idColumn),
mapping: normalizeSearchSourceIncrementalMappingConfig(incrementalConfig.mapping),
response: normalizeSearchSourceIncrementalResponseConfig(incrementalConfig.response),
safetyLag: normalizeOptionalString(incrementalConfig.safetyLag),
sql: normalizeOptionalString(incrementalConfig.sql),
strategy: normalizeOptionalString(incrementalConfig.strategy),
versionColumn: normalizeOptionalString(incrementalConfig.versionColumn)
});
};
const normalizeSearchSourceSnapshotPaginationConfig = paginationConfig => {
if (!isPlainObject(paginationConfig)) {
return null;
}
return filterNullEntries({
batchSize: Number.isInteger(paginationConfig.batchSize) && paginationConfig.batchSize > 0 ? paginationConfig.batchSize : null,
keyColumn: normalizeOptionalString(paginationConfig.keyColumn),
mode: normalizeOptionalString(paginationConfig.mode)
});
};
const normalizeSearchSourceSnapshotConfig = snapshotConfig => {
if (!isPlainObject(snapshotConfig)) {
return null;
}
return filterNullEntries({
pagination: normalizeSearchSourceSnapshotPaginationConfig(snapshotConfig.pagination),
sql: normalizeOptionalString(snapshotConfig.sql)
});
};
const normalizeSearchSourcePromotionConfig = promotionConfig => {
if (!isPlainObject(promotionConfig)) {
return null;
}
return filterNullEntries({
mode: normalizeOptionalString(promotionConfig.mode),
rollbackGrace: normalizeOptionalString(promotionConfig.rollbackGrace)
});
};
export const normalizeSearchSourceConfig = (sourceName, sourceConfig) => {
const normalizedSourceConfig = {
capabilities: resolveSearchSourceCapabilities(sourceConfig),
collection: normalizeOptionalString(sourceConfig?.collection),
connectionSecret: normalizeOptionalString(sourceConfig?.connectionSecret),
description: normalizeOptionalString(sourceConfig?.description),
driver: normalizeOptionalString(sourceConfig?.driver),
enabled: sourceConfig?.enabled !== false,
eventarc: normalizeSearchSourceEventarcConfig(sourceConfig?.eventarc),
incremental: normalizeSearchSourceIncrementalConfig(sourceConfig?.incremental),
indexes: normalizeStringArray(sourceConfig?.indexes),
mapper: normalizeOptionalString(sourceConfig?.mapper),
promotion: normalizeSearchSourcePromotionConfig(sourceConfig?.promotion),
request: normalizeSearchSourceRequestConfig(sourceConfig?.request),
routeTemplate: normalizeOptionalString(sourceConfig?.routeTemplate),
schedule: normalizeOptionalString(sourceConfig?.schedule),
snapshot: normalizeSearchSourceSnapshotConfig(sourceConfig?.snapshot),
sourceName,
syncClass: normalizeOptionalString(sourceConfig?.syncClass),
type: normalizeOptionalString(sourceConfig?.type)
};
return filterNullEntries(normalizedSourceConfig);
};
const createRuntimeSourceConfigFromCollection = (collectionName, collectionConfig) => normalizeSearchSourceConfig(collectionName, {
collection: collectionName,
enabled: collectionConfig?.enabled !== false,
eventarc: {
documentPathPattern: normalizeOptionalString(collectionConfig?.sourcePathPattern) ?? `${collectionName}/*`
},
indexes: collectionConfig?.indexes,
mapper: collectionConfig?.mapper,
routeTemplate: collectionConfig?.routeTemplate,
syncClass: 'delta-merge',
type: 'firestore'
});
export const resolveSearchRuntimeSources = context => {
const configuredSources = context.config.sources ?? {};
if (Object.keys(configuredSources).length > 0) {
return Object.fromEntries(Object.entries(configuredSources).map(([sourceName, sourceConfig]) => [sourceName, normalizeSearchSourceConfig(sourceName, sourceConfig)]));
}
return Object.fromEntries(Object.entries(context.config.collections ?? {}).map(([collectionName, collectionConfig]) => [collectionName, createRuntimeSourceConfigFromCollection(collectionName, collectionConfig)]));
};
export default {
normalizeSearchSourceConfig,
resolveSearchRuntimeSources
};