cyb/src/services/CozoDb/cozoDbCommandFactory.ts

import { DbEntity } from './types/entities';
import { Column, DBSchema, GetCommandOptions } from './types/types';
import { entityToArray } from './utils';

export function createCozoDbCommandFactory(dbSchema: DBSchema) {
  const schema = dbSchema;

  const generateRmCommand = (tableName: string, keys: string[]): string => {
    return `:rm ${tableName} {${keys}}`;
  };

  const generateModifyCommand = (
    tableName: string,
    command: 'put' | 'update' = 'put',
    fieldNames: string[] = []
  ): string => {
    const { keys, values } = schema[tableName];
    const hasValues = values.length > 0;

    const actualValues =
      fieldNames.length > 0 ? fieldNames.filter((f) => values.includes(f)) : values;

    return !hasValues
      ? `:${command} ${tableName} {${keys}}`
      : `:${command} ${tableName} {${keys} => ${actualValues}}`;
  };

  const generateAtomCommand = (
    tableName: string,
    items: Partial<DbEntity>[],
    fieldNames: string[] = []
  ): string => {
    const tableSchema = dbSchema[tableName];

    const selectedColumns =
      fieldNames.length > 0
        ? Object.keys(tableSchema.columns).reduce(
            (acc, key) => {
              if (fieldNames.includes(key)) {
                acc[key] = tableSchema.columns[key];
              }
              return acc;
            },
            {} as Record<string, Column>
          )
        : tableSchema.columns;

    const colKeys = Object.keys(selectedColumns);
    const colValues = Object.values(selectedColumns) as Column[];

    return `?[${colKeys.join(', ')}] <- [${items
      .map((item) => entityToArray(item, colValues))
      .join(', ')}]`;
  };

  const generatePut = (tableName: string, array: Partial<DbEntity>[]) => {
    const fields = Object.keys(array[0]);
    const atomCommand = generateAtomCommand(tableName, array, fields);
    const putCommand = generateModifyCommand(tableName, 'put');
    return `${atomCommand}\r\n${putCommand}`;
  };

  const generateRm = (tableName: string, keyValues: Partial<DbEntity>[]) => {
    const { keys } = schema[tableName];

    const atomCommand = generateAtomCommand(tableName, keyValues, keys);
    const rmCommand = generateRmCommand(tableName, keys);
    return `${atomCommand}\r\n${rmCommand}`;
  };

  const generateUpdate = (tableName: string, array: Partial<DbEntity>[]) => {
    // align fields by first entity
    const fields = Object.keys(array[0]);
    const atomCommand = generateAtomCommand(tableName, array, fields);
    const updateCommand = generateModifyCommand(tableName, 'update', fields);
    return `${atomCommand}\r\n${updateCommand}`;
  };

  const generateGet = (
    tableName: string,
    selectFields: string[] = [],
    conditions: string[] = [],
    conditionFields: string[] = [],
    options: GetCommandOptions = {}
  ) => {
    const tableSchema = dbSchema[tableName];

    const queryFields = selectFields.length > 0 ? selectFields : Object.keys(tableSchema.columns);

    const requiredFields = [...queryFields, ...conditionFields];

    const conditionsStr = conditions.length > 0 ? `, ${conditions.join(', ')} ` : '';

    const orderByStr = options.orderBy ? `:order ${options.orderBy}` : '';
    const limitStr = options.limit ? `:limit ${options.limit}` : '';
    const offsetStr = options.limit ? `:offset ${options.offset}` : '';
    return `?[${queryFields.join(', ')}] := *${tableName}{${requiredFields.join(
      ', '
    )}} ${conditionsStr} ${orderByStr} ${limitStr} ${offsetStr}`;
  };

  return {
    generateModifyCommand,
    generateAtomCommand,
    generatePut,
    generateGet,
    generateUpdate,
    generateRm,
  };
}

Synonyms

pussy-ts/src/services/CozoDb/cozoDbCommandFactory.ts

Neighbours