{"version":3,"file":"select.cjs","sources":["../../../src/query/select.ts"],"sourcesContent":["import { map } from \"@electric-sql/d2mini\"\nimport {\n  evaluateOperandOnNamespacedRow,\n  extractValueFromNamespacedRow,\n} from \"./extractors\"\nimport type { ConditionOperand, Query, SelectCallback } from \"./schema\"\nimport type { KeyedStream, NamespacedAndKeyedStream } from \"../types\"\n\nexport function processSelect(\n  pipeline: NamespacedAndKeyedStream,\n  query: Query,\n  mainTableAlias: string,\n  inputs: Record<string, KeyedStream>\n): KeyedStream {\n  return pipeline.pipe(\n    map(([key, namespacedRow]) => {\n      const result: Record<string, unknown> = {}\n\n      // Check if this is a grouped result (has no nested table structure)\n      // If it's a grouped result, we need to handle it differently\n      const isGroupedResult =\n        query.groupBy &&\n        Object.keys(namespacedRow).some(\n          (namespaceKey) =>\n            !Object.keys(inputs).includes(namespaceKey) &&\n            typeof namespacedRow[namespaceKey] !== `object`\n        )\n\n      if (!query.select) {\n        throw new Error(`Cannot process missing SELECT clause`)\n      }\n\n      for (const item of query.select) {\n        // Handle callback functions\n        if (typeof item === `function`) {\n          const callback = item as SelectCallback\n          const callbackResult = callback(namespacedRow)\n\n          // If the callback returns an object, merge its properties into the result\n          if (\n            callbackResult &&\n            typeof callbackResult === `object` &&\n            !Array.isArray(callbackResult)\n          ) {\n            Object.assign(result, callbackResult)\n          } else {\n            // If the callback returns a primitive value, we can't merge it\n            // This would need a specific key, but since we don't have one, we'll skip it\n            // In practice, select callbacks should return objects with keys\n            console.warn(\n              `SelectCallback returned a non-object value. SelectCallbacks should return objects with key-value pairs.`\n            )\n          }\n          continue\n        }\n\n        if (typeof item === `string`) {\n          // Handle wildcard select - all columns from all tables\n          if ((item as string) === `@*`) {\n            // For grouped results, just return the row as is\n            if (isGroupedResult) {\n              Object.assign(result, namespacedRow)\n            } else {\n              // Extract all columns from all tables\n              Object.assign(\n                result,\n                extractAllColumnsFromAllTables(namespacedRow)\n              )\n            }\n            continue\n          }\n\n          // Handle @table.* syntax - all columns from a specific table\n          if (\n            (item as string).startsWith(`@`) &&\n            (item as string).endsWith(`.*`)\n          ) {\n            const tableAlias = (item as string).slice(1, -2) // Remove the '@' and '.*' parts\n\n            // For grouped results, check if we have columns from this table\n            if (isGroupedResult) {\n              // In grouped results, we don't have the nested structure anymore\n              // So we can't extract by table. Just continue to the next item.\n              continue\n            } else {\n              // Extract all columns from the specified table\n              Object.assign(\n                result,\n                extractAllColumnsFromTable(namespacedRow, tableAlias)\n              )\n            }\n            continue\n          }\n\n          // Handle simple column references like \"@table.column\" or \"@column\"\n          if ((item as string).startsWith(`@`)) {\n            const columnRef = (item as string).substring(1)\n            const alias = columnRef\n\n            // For grouped results, check if the column is directly in the row first\n            if (isGroupedResult && columnRef in namespacedRow) {\n              result[alias] = namespacedRow[columnRef]\n            } else {\n              // Extract the value from the nested structure\n              result[alias] = extractValueFromNamespacedRow(\n                namespacedRow,\n                columnRef,\n                mainTableAlias,\n                undefined\n              )\n            }\n\n            // If the alias contains a dot (table.column),\n            // use just the column part as the field name\n            if (alias.includes(`.`)) {\n              const columnName = alias.split(`.`)[1]\n              result[columnName!] = result[alias]\n              delete result[alias]\n            }\n          }\n        } else {\n          // Handle aliased columns like { alias: \"@column_name\" }\n          for (const [alias, expr] of Object.entries(item)) {\n            if (typeof expr === `string` && (expr as string).startsWith(`@`)) {\n              const columnRef = (expr as string).substring(1)\n\n              // For grouped results, check if the column is directly in the row first\n              if (isGroupedResult && columnRef in namespacedRow) {\n                result[alias] = namespacedRow[columnRef]\n              } else {\n                // Extract the value from the nested structure\n                result[alias] = extractValueFromNamespacedRow(\n                  namespacedRow,\n                  columnRef,\n                  mainTableAlias,\n                  undefined\n                )\n              }\n            } else if (typeof expr === `object`) {\n              // For grouped results, the aggregate results are already in the row\n              if (isGroupedResult && alias in namespacedRow) {\n                result[alias] = namespacedRow[alias]\n              } else if ((expr as { ORDER_INDEX: unknown }).ORDER_INDEX) {\n                result[alias] = namespacedRow[mainTableAlias]![alias]\n              } else {\n                // This might be a function call\n                result[alias] = evaluateOperandOnNamespacedRow(\n                  namespacedRow,\n                  expr as ConditionOperand,\n                  mainTableAlias,\n                  undefined\n                )\n              }\n            }\n          }\n        }\n      }\n\n      return [key, result] as [string, typeof result]\n    })\n  )\n}\n\n// Helper function to extract all columns from all tables in a nested row\nfunction extractAllColumnsFromAllTables(\n  namespacedRow: Record<string, unknown>\n): Record<string, unknown> {\n  const result: Record<string, unknown> = {}\n\n  // Process each table in the nested row\n  for (const [tableAlias, tableData] of Object.entries(namespacedRow)) {\n    if (tableData && typeof tableData === `object`) {\n      // Add all columns from this table to the result\n      // If there are column name conflicts, the last table's columns will overwrite previous ones\n      Object.assign(\n        result,\n        extractAllColumnsFromTable(namespacedRow, tableAlias)\n      )\n    }\n  }\n\n  return result\n}\n\n// Helper function to extract all columns from a table in a nested row\nfunction extractAllColumnsFromTable(\n  namespacedRow: Record<string, unknown>,\n  tableAlias: string\n): Record<string, unknown> {\n  const result: Record<string, unknown> = {}\n\n  // Get the table data\n  const tableData = namespacedRow[tableAlias] as\n    | Record<string, unknown>\n    | null\n    | undefined\n\n  if (!tableData || typeof tableData !== `object`) {\n    return result\n  }\n\n  // Add all columns from the table to the result\n  for (const [columnName, value] of Object.entries(tableData)) {\n    result[columnName] = value\n  }\n\n  return result\n}\n"],"names":["map","extractValueFromNamespacedRow","evaluateOperandOnNamespacedRow"],"mappings":"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"}