import { assert } from "../../../shared/src/asserts.js";
import { stringCompare } from "../../../shared/src/string-compare.js";
import { valuesEqual } from "./data.js";
//#region ../zql/src/ivm/constraint.ts
function constraintMatchesRow(constraint, row) {
	for (const key in constraint) if (!valuesEqual(row[key], constraint[key])) return false;
	return true;
}
/**
* Constraints are compatible if:
* 1. They do not have any keys in common
* 2. They have keys in common, but the values for those keys are equal
*/
function constraintsAreCompatible(left, right) {
	for (const key in left) if (key in right && !valuesEqual(left[key], right[key])) return false;
	return true;
}
function constraintMatchesPrimaryKey(constraint, primary) {
	return keyMatchesPrimaryKey(Object.keys(constraint), primary);
}
function keyMatchesPrimaryKey(key, primary) {
	const constraintKeys = [...key];
	if (constraintKeys.length !== primary.length) return false;
	constraintKeys.sort(stringCompare);
	for (let i = 0; i < constraintKeys.length; i++) if (constraintKeys[i] !== primary[i]) return false;
	return true;
}
/**
* Pulls top level `and` components out of a condition tree.
* The resulting array of simple conditions would match a superset of
* values that the original condition would match.
*
* Examples:
* a AND b OR c
*
* In this case we cannot pull anything because the `or` is at the top level.
*
* a AND b AND c
* We can pull all three.
*
* a AND (b OR c)
* We can only pull `a`.
*/
function pullSimpleAndComponents(condition) {
	if (condition.type === "and") return condition.conditions.flatMap(pullSimpleAndComponents);
	if (condition.type === "simple") return [condition];
	if (condition.type === "or" && condition.conditions.length === 1) return pullSimpleAndComponents(condition.conditions[0]);
	return [];
}
/**
* Checks if the supplied filters constitute a primary key lookup.
* If so, returns the constraint that would be used to look up the primary key.
* If not, returns undefined.
*/
function primaryKeyConstraintFromFilters(condition, primary) {
	if (condition === void 0) return;
	const conditions = pullSimpleAndComponents(condition);
	if (conditions.length === 0) return;
	const ret = {};
	for (const subCondition of conditions) if (subCondition.op === "=") {
		const column = extractColumn(subCondition);
		if (column !== void 0) {
			if (!primary.includes(column.name)) continue;
			ret[column.name] = column.value;
		}
	}
	if (Object.keys(ret).length !== primary.length) return;
	return ret;
}
function extractColumn(condition) {
	if (condition.left.type === "column") {
		assert(condition.right.type === "literal", () => `extractColumn: expected right side to be literal, got ${condition.right.type}`);
		return {
			name: condition.left.name,
			value: condition.right.value
		};
	}
}
//#endregion
export { constraintMatchesPrimaryKey, constraintMatchesRow, constraintsAreCompatible, primaryKeyConstraintFromFilters };

//# sourceMappingURL=constraint.js.map