function resolveSimpleScalarSubqueries(ast, tableSpecs, execute) {
  const companions = [];
  const resolved = resolveASTRecursive(ast, tableSpecs, execute, companions);
  return { ast: resolved, companions };
}
function resolveASTRecursive(ast, tableSpecs, execute, companions) {
  const where = ast.where ? resolveCondition(ast.where, tableSpecs, execute, companions) : void 0;
  const related = ast.related?.map((r) => ({
    ...r,
    subquery: resolveASTRecursive(r.subquery, tableSpecs, execute, companions)
  }));
  if (where !== ast.where || related !== ast.related) {
    return { ...ast, where, related };
  }
  return ast;
}
function resolveCondition(condition, tableSpecs, execute, companions) {
  switch (condition.type) {
    case "correlatedSubquery":
      if (condition.scalar) {
        return resolveScalarSubquery(
          condition,
          tableSpecs,
          execute,
          companions
        );
      }
      {
        const resolvedSubquery = resolveASTRecursive(
          condition.related.subquery,
          tableSpecs,
          execute,
          companions
        );
        if (resolvedSubquery !== condition.related.subquery) {
          return {
            ...condition,
            related: { ...condition.related, subquery: resolvedSubquery }
          };
        }
        return condition;
      }
    case "and":
    case "or": {
      const resolved = condition.conditions.map(
        (c) => resolveCondition(c, tableSpecs, execute, companions)
      );
      if (resolved.every((c, i) => c === condition.conditions[i])) {
        return condition;
      }
      return { type: condition.type, conditions: resolved };
    }
    default:
      return condition;
  }
}
function resolveScalarSubquery(condition, tableSpecs, execute, companions) {
  const parentField = condition.related.correlation.parentField[0];
  const childField = condition.related.correlation.childField[0];
  const subquery = resolveASTRecursive(
    condition.related.subquery,
    tableSpecs,
    execute,
    companions
  );
  if (!isSimpleSubquery(subquery, tableSpecs)) {
    if (subquery !== condition.related.subquery) {
      return {
        ...condition,
        related: { ...condition.related, subquery }
      };
    }
    return condition;
  }
  const value = execute(subquery, childField);
  companions.push({
    ast: subquery,
    childField,
    resolvedValue: value
  });
  if (value === void 0 || value === null) {
    return ALWAYS_FALSE;
  }
  const op = condition.op === "EXISTS" ? "=" : "IS NOT";
  return {
    type: "simple",
    op,
    left: { type: "column", name: parentField },
    right: { type: "literal", value }
  };
}
const ALWAYS_FALSE = {
  type: "simple",
  op: "=",
  left: { type: "literal", value: 1 },
  right: { type: "literal", value: 0 }
};
function isSimpleSubquery(subquery, tableSpecs) {
  const spec = tableSpecs.get(subquery.table);
  if (!spec) {
    return false;
  }
  if (!subquery.where) {
    return false;
  }
  const constraints = extractLiteralEqualityConstraints(subquery.where);
  if (constraints.size === 0) {
    return false;
  }
  const { uniqueKeys } = spec.tableSpec;
  return uniqueKeys.some((key) => key.every((col) => constraints.has(col)));
}
function extractLiteralEqualityConstraints(condition) {
  const constraints = /* @__PURE__ */ new Map();
  collectConstraints(condition, constraints);
  return constraints;
}
function collectConstraints(condition, constraints) {
  switch (condition.type) {
    case "simple":
      if (condition.op === "=") {
        if (condition.left.type === "column" && condition.right.type === "literal") {
          constraints.set(condition.left.name, condition.right.value);
        }
      }
      break;
    case "and":
      for (const c of condition.conditions) {
        collectConstraints(c, constraints);
      }
      break;
  }
}
export {
  extractLiteralEqualityConstraints,
  isSimpleSubquery,
  resolveSimpleScalarSubqueries
};
//# sourceMappingURL=resolve-scalar-subqueries.js.map
