@decaf-ts/core
Version:
Core persistence module for the decaf framework
345 lines • 15.7 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Model, required, } from "@decaf-ts/decorator-validation";
import { GroupOperator, Operator } from "./constants.js";
import { QueryError } from "./errors.js";
/**
* @description Represents a logical condition for database queries
* @summary A class that encapsulates query conditions with support for complex logical operations.
* This class allows for building and combining query conditions using logical operators (AND, OR, NOT)
* and comparison operators (equals, not equals, greater than, etc.).
* @template M - The model type this condition operates on
* @param {string | Condition<M>} attr1 - The attribute name or a nested condition
* @param {Operator | GroupOperator} operator - The operator to use for the condition
* @param {any} comparison - The value to compare against or another condition
* @class Condition
* @example
* // Create a simple condition
* const nameCondition = Condition.attribute("name").eq("John");
*
* // Create a complex condition
* const complexCondition = Condition.attribute("age").gt(18)
* .and(Condition.attribute("status").eq("active"));
*
* // Use the builder pattern
* const userQuery = Condition.builder()
* .attribute("email").regexp(".*@example.com")
* .and(Condition.attribute("lastLogin").gt(new Date("2023-01-01")));
* @mermaid
* sequenceDiagram
* participant Dev
* participant Condition
* Dev->>Condition: builder().attribute("age").gt(18)
* Condition-->>Dev: Condition(age > 18)
* Dev->>Condition: .and(attribute("status").eq("active"))
* Condition-->>Dev: Condition((age > 18) AND (status = "active"))
*/
export class Condition extends Model {
constructor(attr1, operator, comparison) {
super();
this.attr1 = undefined;
this.operator = undefined;
this.comparison = undefined;
if (!operator && !comparison) {
Model.fromModel(this, attr1);
}
else {
this.attr1 = attr1;
this.operator = operator;
this.comparison = comparison;
}
}
/**
* @description Combines this condition with another using logical AND
* @summary Joins two conditions with an AND operator, requiring both to be true
* @param {Condition<M>} condition - The condition to combine with this one
* @return {Condition<M>} A new condition representing the AND operation
*/
and(condition) {
return Condition.and(this, condition);
}
/**
* @description Combines this condition with another using logical OR
* @summary Joins two conditions with an OR operator, requiring at least one to be true
* @param {Condition<M>} condition - The condition to combine with this one
* @return {Condition<M>} A new condition representing the OR operation
*/
or(condition) {
return Condition.or(this, condition);
}
/**
* @description Creates a negation condition
* @summary Excludes a value from the result by applying a NOT operator
* @param {any} val - The value to negate
* @return {Condition<M>} A new condition representing the NOT operation
*/
not(val) {
return new Condition(this, Operator.NOT, val);
}
/**
* @description Validates the condition and checks for errors
* @summary Extends the base validation to ensure the condition is properly formed
* @param {...string[]} exceptions - Fields to exclude from validation
* @return {ModelErrorDefinition | undefined} Error definition if validation fails, undefined otherwise
*/
hasErrors(...exceptions) {
const conditionCheck = () => {
const invalidOpMessage = `Invalid operator ${this.operator}}`;
if (typeof this.attr1 === "string") {
if (this.comparison instanceof Condition)
return {
comparison: {
condition: "Both sides of the comparison must be of the same type",
},
};
if (Object.values(Operator).indexOf(this.operator) === -1)
return {
operator: {
condition: invalidOpMessage,
},
};
}
if (this.attr1 instanceof Condition) {
if (!(this.comparison instanceof Condition) &&
this.operator !== Operator.NOT)
return {
comparison: {
condition: invalidOpMessage,
},
};
if (Object.values(GroupOperator).indexOf(this.operator) === -1 &&
this.operator !== Operator.NOT)
return {
operator: {
condition: invalidOpMessage,
},
};
}
};
const errors = super.hasErrors(...exceptions);
if (!this.isAsync())
return (errors ??
conditionCheck());
return (async () => {
const resolved = await Promise.resolve(errors);
return resolved ?? conditionCheck();
})();
}
/**
* @description Creates a new condition that combines two conditions with logical AND
* @summary Static method that joins two conditions with an AND operator, requiring both to be true
* @template M - The model type this condition operates on
* @param {Condition<M>} condition1 - The first condition
* @param {Condition<M>} condition2 - The second condition
* @return {Condition<M>} A new condition representing the AND operation
*/
static and(condition1, condition2) {
return Condition.group(condition1, GroupOperator.AND, condition2);
}
/**
* @description Creates a new condition that combines two conditions with logical OR
* @summary Static method that joins two conditions with an OR operator, requiring at least one to be true
* @template M - The model type this condition operates on
* @param {Condition<M>} condition1 - The first condition
* @param {Condition<M>} condition2 - The second condition
* @return {Condition<M>} A new condition representing the OR operation
*/
static or(condition1, condition2) {
return Condition.group(condition1, GroupOperator.OR, condition2);
}
/**
* @description Creates a new condition that groups two conditions with a specified operator
* @summary Private static method that combines two conditions using the specified group operator
* @template M - The model type this condition operates on
* @param {Condition<M>} condition1 - The first condition
* @param {GroupOperator} operator - The group operator to use (AND, OR)
* @param {Condition<M>} condition2 - The second condition
* @return {Condition<M>} A new condition representing the grouped operation
*/
static group(condition1, operator, condition2) {
return new Condition(condition1, operator, condition2);
}
/**
* @description Creates a condition builder for a specific model attribute
* @summary Static method that initializes a condition builder with the specified attribute
* @template M - The model type this condition operates on
* @param attr - The model attribute to build a condition for
* @return {AttributeOption<M>} A condition builder initialized with the attribute
*/
static attribute(attr) {
return new Condition.Builder().attribute(attr);
}
/**
* @description Alias for the attribute method
* @summary Shorthand method that initializes a condition builder with the specified attribute
* @template M - The model type this condition operates on
* @param attr - The model attribute to build a condition for
* @return {AttributeOption<M>} A condition builder initialized with the attribute
*/
static attr(attr) {
return this.attribute(attr);
}
/**
* @description Provides a fluent API to build query conditions
* @summary A builder class that simplifies the creation of database query conditions
* with a chainable interface for setting attributes and operators
* @template M - The model type this condition builder operates on
* @class ConditionBuilder
*/
static { this.Builder = class ConditionBuilder {
constructor() {
this.attr1 = undefined;
this.operator = undefined;
this.comparison = undefined;
}
/**
* @description Sets the attribute for the condition
* @summary Specifies which model attribute the condition will operate on
* @param attr - The model attribute to use in the condition
* @return {AttributeOption<M>} This builder instance for method chaining
*/
attribute(attr) {
this.attr1 = attr;
return this;
}
/**
* @description Alias for the attribute method
* @summary Shorthand method to specify which model attribute the condition will operate on
* @param attr - The model attribute to use in the condition
* @return {AttributeOption<M>} This builder instance for method chaining
*/
attr(attr) {
return this.attribute(attr);
}
/**
* @description Creates an equality condition
* @summary Builds a condition that checks if the attribute equals the specified value
* @param {any} val - The value to compare the attribute against
* @return {Condition<M>} A new condition representing the equality comparison
*/
eq(val) {
return this.setOp(Operator.EQUAL, val);
}
/**
* @description Creates an inequality condition
* @summary Builds a condition that checks if the attribute is different from the specified value
* @param {any} val - The value to compare the attribute against
* @return {Condition<M>} A new condition representing the inequality comparison
*/
dif(val) {
return this.setOp(Operator.DIFFERENT, val);
}
/**
* @description Creates a greater than condition
* @summary Builds a condition that checks if the attribute is greater than the specified value
* @param {any} val - The value to compare the attribute against
* @return {Condition<M>} A new condition representing the greater than comparison
*/
gt(val) {
return this.setOp(Operator.BIGGER, val);
}
/**
* @description Creates a less than condition
* @summary Builds a condition that checks if the attribute is less than the specified value
* @param {any} val - The value to compare the attribute against
* @return {Condition<M>} A new condition representing the less than comparison
*/
lt(val) {
return this.setOp(Operator.SMALLER, val);
}
/**
* @description Creates a greater than or equal to condition
* @summary Builds a condition that checks if the attribute is greater than or equal to the specified value
* @param {any} val - The value to compare the attribute against
* @return {Condition<M>} A new condition representing the greater than or equal comparison
*/
gte(val) {
return this.setOp(Operator.BIGGER_EQ, val);
}
/**
* @description Creates a less than or equal to condition
* @summary Builds a condition that checks if the attribute is less than or equal to the specified value
* @param {any} val - The value to compare the attribute against
* @return {Condition<M>} A new condition representing the less than or equal comparison
*/
lte(val) {
return this.setOp(Operator.SMALLER_EQ, val);
}
/**
* @description Creates an inclusion condition
* @summary Builds a condition that checks if the attribute value is included in the specified array
* @param {any[]} arr - The array of values to check against
* @return {Condition<M>} A new condition representing the inclusion comparison
*/
in(arr) {
return this.setOp(Operator.IN, arr);
}
/**
* @description Creates a regular expression condition
* @summary Builds a condition that checks if the attribute matches the specified regular expression pattern
* @param {any} val - The regular expression pattern to match against
* @return {Condition<M>} A new condition representing the regular expression comparison
*/
regexp(val) {
return this.setOp(Operator.REGEXP, new RegExp(val).source);
}
/**
* @description Sets the operator and comparison value for the condition
* @summary Private method that configures the condition with the specified operator and value
* @param {Operator} op - The operator to use for the condition
* @param {any} val - The value to compare against
* @return {Condition<M>} A new condition with the specified operator and value
*/
setOp(op, val) {
this.operator = op;
this.comparison = val;
return this.build();
}
/**
* @description Constructs a Condition instance from the builder's state
* @summary Finalizes the condition building process by creating a new Condition instance
* @throws {QueryError} If the condition cannot be built due to invalid parameters
* @return {Condition<M>} A new condition instance with the configured attributes
*/
build() {
try {
return new Condition(this.attr1, this.operator, this.comparison);
}
catch (e) {
throw new QueryError(e);
}
}
}; }
/**
* @description Creates a new condition builder
* @summary Factory method that returns a new instance of the condition builder
* @template M - The model type this condition builder will operate on
* @return {ConditionBuilderOption<M>} A new condition builder instance
*/
static builder() {
return new Condition.Builder();
}
static from(obj) {
return new Condition(obj);
}
}
__decorate([
required(),
__metadata("design:type", Object)
], Condition.prototype, "attr1", void 0);
__decorate([
required(),
__metadata("design:type", String)
], Condition.prototype, "operator", void 0);
__decorate([
required(),
__metadata("design:type", Object)
], Condition.prototype, "comparison", void 0);
//# sourceMappingURL=Condition.js.map