CodelyTV / typescript-criteria

https://www.npmjs.com/package/@codelytv/criteria
MIT License
40 stars 5 forks source link

[feat] Modelo de condicional profundo en consultas #13

Open WilmerRS opened 1 week ago

WilmerRS commented 1 week ago

Hola @CodelyTv, Wilmer desde Colombia. Felicidades y gracias por todas las contribuciones al desarrollo de software y la comunidad en espaƱol šŸ„³.

[Problema] Entiendo que el modelo Criteria se propone como una generalizaciĆ³n de consultas complejas a travĆ©s de REST API. Muchos de los frontends que requieren este tipo de consultas requieren concatenar condiciones mĆ”s profundas que permitan un filtrado preciso.

AquĆ­ un ejemplo del frontal de odoo v15.

image

[Propuesta] Un modelado de Filtro recursivo que permita seleccionar la relaciĆ³n entre operaciones (AND, OR).

Dejo esbozo de la idea.

import { FilterField } from "./FilterField";
import { FilterOperator, Operator } from "./FilterOperator";
import { FilterValue } from "./FilterValue";

export type Relation = 'AND' | 'OR';

export class Condition {
    readonly field: FilterField;
    readonly operator: FilterOperator;
    readonly value: FilterValue;

    constructor(field: FilterField, operator: FilterOperator, value: FilterValue) {
        this.field = field;
        this.operator = operator;
        this.value = value;
    }

    static fromPrimitives(field: string, operator: string, value: string): Condition {
        return new Condition(
            new FilterField(field),
            new FilterOperator(Operator[operator as keyof typeof Operator]),
            new FilterValue(value),
        );
    }

    toPrimitives(): FiltersPrimitives {
        return {
            field: this.field.value,
            operator: this.operator.value,
            value: this.value.value,
        };
    }
}

export class Filter {
    readonly relation: Relation;
    readonly filters: Array<Condition | Filter>;

    constructor(relation: Relation, filters: Array<Condition | Filter>) {
        this.relation = relation;
        this.filters = filters;
    }

    static fromPrimitives(relation: Relation, filters: Array<FiltersPrimitives>): Filter {
        return new Filter(
            relation,
            filters.map((filter) => {
                const isConditionFilter = 'field' in filter;
                if (isConditionFilter ) {
                    return Condition.fromPrimitives(filter.field, filter.operator, filter.value);
                }

                return Filter.fromPrimitives(filter.relation, filter.filters);
            })
        );
    }

    toPrimitives(): any {
        return {
            relation: this.relation,
            filters: this.filters.map((filter) => {
                eturn filter.toPrimitives();
            }),
        };
    }
}
WilmerRS commented 1 week ago

Ejemplo de uso

const filters = [
   {
      relation: "AND",
      filters: [
          {
              field: "name",
              operator: "=",
              value: "wilmer"
          },
          {
              field: "last_name",
              operator: "=",
              value: "rodriguez"
          },
          {
              relation: "OR",
              filters: [
                  {
                      field: "level",
                      operator: "=",
                      value: "senior"
                  },
                  {
                      field: "level",
                      operator: "=",
                      value: "mid"
                  },
              ],
          }
      ]
   }
];