This commit is contained in:
David Arranz 2024-07-03 12:27:58 +02:00
parent 985111af5f
commit a32ba80bb6
18 changed files with 225 additions and 138 deletions

View File

@ -10,6 +10,7 @@ export const checkUser = composeMiddleware([
session: false, session: false,
}), }),
(req: Express.Request, res: Express.Response, next: Express.NextFunction) => { (req: Express.Request, res: Express.Response, next: Express.NextFunction) => {
const user = <AuthUser>req.user;
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
return next(); return next();
} }
@ -33,6 +34,7 @@ export const checkAdminOrSelf = composeMiddleware([
checkUser, checkUser,
(req: Express.Request, res: Express.Response, next: Express.NextFunction) => { (req: Express.Request, res: Express.Response, next: Express.NextFunction) => {
const user = <AuthUser>req.user; const user = <AuthUser>req.user;
const { userId } = req.params; const { userId } = req.params;
if (user.isAdmin) { if (user.isAdmin) {

View File

@ -1,26 +1,52 @@
import { IRepositoryManager, RepositoryManager } from "../domain"; import { IRepositoryManager, RepositoryManager } from "../domain";
import { ISequelizeAdapter, createSequelizeAdapter } from "./sequelize"; import { ISequelizeAdapter, createSequelizeAdapter } from "./sequelize";
export interface IContext {
adapter: ISequelizeAdapter;
repositoryManager: IRepositoryManager;
}
export class ContextFactory {
private static instance: ContextFactory | null = null;
public static getInstance(): IContext {
if (!ContextFactory.instance) {
ContextFactory.instance = new ContextFactory({
adapter: createSequelizeAdapter(),
repositoryManager: RepositoryManager.getInstance(),
});
}
return ContextFactory.instance.context;
}
private context: IContext;
private constructor(context: IContext) {
this.context = context;
}
}
// ContextFactory.ts // ContextFactory.ts
export interface IContext<T> { /*export interface IContext {
adapter: ISequelizeAdapter; adapter: ISequelizeAdapter;
repositoryManager: IRepositoryManager; repositoryManager: IRepositoryManager;
services: T; services: T;
} }
export class ContextFactory<T> { export class ContextFactory {
private static instances: Map<string, ContextFactory<any>> = new Map(); private static instances: Map<string, ContextFactory<any>> = new Map();
public static getInstance<T>(constructor: new () => T): ContextFactory<T> { public static getInstance(constructor: new () => T): ContextFactory {
const key = constructor.name; const key = constructor.name;
if (!ContextFactory.instances.has(key)) { if (!ContextFactory.instances.has(key)) {
ContextFactory.instances.set(key, new ContextFactory<T>(constructor)); ContextFactory.instances.set(key, new ContextFactory(constructor));
} }
return ContextFactory.instances.get(key)! as ContextFactory<T>; return ContextFactory.instances.get(key)! as ContextFactory;
} }
private context: IContext<T>; private context: IContext;
private constructor(constructor: new () => T) { private constructor(constructor: new () => T) {
this.context = { this.context = {
@ -30,7 +56,7 @@ export class ContextFactory<T> {
}; };
} }
public getContext(): IContext<T> { public getContext(): IContext {
return this.context; return this.context;
} }
} }*/

View File

@ -73,7 +73,7 @@ export class CreateDealerUseCase
switch (domainError.code) { switch (domainError.code) {
case DomainError.INVALID_INPUT_DATA: case DomainError.INVALID_INPUT_DATA:
errorCode = UseCaseError.INVALID_INPUT_DATA; errorCode = UseCaseError.INVALID_INPUT_DATA;
message = "El usuario tiene algún dato erróneo."; message = "El distribuidor tiene algún dato erróneo.";
break; break;
default: default:

View File

@ -66,7 +66,7 @@ export class UpdateDealerUseCase
// Errores manuales // Errores manuales
case DomainError.INVALID_INPUT_DATA: case DomainError.INVALID_INPUT_DATA:
errorCode = UseCaseError.INVALID_INPUT_DATA; errorCode = UseCaseError.INVALID_INPUT_DATA;
message = "El usuario tiene algún dato erróneo."; message = "El distribuidor tiene algún dato erróneo.";
break; break;
default: default:

View File

@ -18,7 +18,16 @@ import {
UnitPrice, UnitPrice,
ensureIdIsValid, ensureIdIsValid,
} from "@shared/contexts"; } from "@shared/contexts";
import { IQuoteRepository, Quote, QuoteCustomer, QuoteItem, QuoteStatus } from "../../domain"; import {
Dealer,
IQuoteRepository,
Quote,
QuoteCustomer,
QuoteItem,
QuoteReference,
QuoteStatus,
} from "../../domain";
import { ISalesContext } from "../../infrastructure";
export type CreateQuoteResponseOrError = export type CreateQuoteResponseOrError =
| Result<never, IUseCaseError> // Misc errors (value objects) | Result<never, IUseCaseError> // Misc errors (value objects)
@ -29,16 +38,25 @@ export class CreateQuoteUseCase
{ {
private _adapter: ISequelizeAdapter; private _adapter: ISequelizeAdapter;
private _repositoryManager: IRepositoryManager; private _repositoryManager: IRepositoryManager;
private _dealer?: Dealer;
constructor(props: { adapter: ISequelizeAdapter; repositoryManager: IRepositoryManager }) { constructor(context: ISalesContext) {
this._adapter = props.adapter; this._adapter = context.adapter;
this._repositoryManager = props.repositoryManager; this._repositoryManager = context.repositoryManager;
this._dealer = context.dealer;
} }
async execute(request: ICreateQuote_Request_DTO) { async execute(request: ICreateQuote_Request_DTO) {
const { id } = request; const { id } = request;
// Validaciones de datos // Validaciones de datos
if (!this._dealer) {
const message = "Error. Missing Dealer";
return Result.fail(UseCaseError.create(UseCaseError.INVALID_INPUT_DATA, message));
}
const dealerId = this._dealer.id;
const idOrError = ensureIdIsValid(id); const idOrError = ensureIdIsValid(id);
if (idOrError.isFailure) { if (idOrError.isFailure) {
const message = idOrError.error.message; //`Quote ID ${quoteDTO.id} is not valid`; const message = idOrError.error.message; //`Quote ID ${quoteDTO.id} is not valid`;
@ -47,7 +65,7 @@ export class CreateQuoteUseCase
); );
} }
// Comprobar que no existe un usuario previo con esos datos // Comprobar que no existe un quote previo con esos datos
const quoteRepository = this._getQuoteRepository(); const quoteRepository = this._getQuoteRepository();
const idExists = await quoteRepository().exists(idOrError.object); const idExists = await quoteRepository().exists(idOrError.object);
@ -61,7 +79,7 @@ export class CreateQuoteUseCase
} }
// Crear quote // Crear quote
const quoteOrError = this._tryCreateQuoteInstance(request, idOrError.object); const quoteOrError = this._tryCreateQuoteInstance(request, idOrError.object, dealerId);
if (quoteOrError.isFailure) { if (quoteOrError.isFailure) {
const { error: domainError } = quoteOrError; const { error: domainError } = quoteOrError;
@ -71,7 +89,7 @@ export class CreateQuoteUseCase
switch (domainError.code) { switch (domainError.code) {
case DomainError.INVALID_INPUT_DATA: case DomainError.INVALID_INPUT_DATA:
errorCode = UseCaseError.INVALID_INPUT_DATA; errorCode = UseCaseError.INVALID_INPUT_DATA;
message = "El usuario tiene algún dato erróneo."; message = "El presupuesto tiene algún dato erróneo.";
break; break;
default: default:
@ -107,7 +125,8 @@ export class CreateQuoteUseCase
private _tryCreateQuoteInstance( private _tryCreateQuoteInstance(
quoteDTO: ICreateQuote_Request_DTO, quoteDTO: ICreateQuote_Request_DTO,
quoteId: UniqueID quoteId: UniqueID,
dealerId: UniqueID
): Result<Quote, IDomainError> { ): Result<Quote, IDomainError> {
const statusOrError = QuoteStatus.create(quoteDTO.status); const statusOrError = QuoteStatus.create(quoteDTO.status);
if (statusOrError.isFailure) { if (statusOrError.isFailure) {
@ -119,7 +138,7 @@ export class CreateQuoteUseCase
return Result.fail(dateOrError.error); return Result.fail(dateOrError.error);
} }
const referenceOrError = QuoteStatus.create(quoteDTO.reference); const referenceOrError = QuoteReference.create(quoteDTO.reference);
if (referenceOrError.isFailure) { if (referenceOrError.isFailure) {
return Result.fail(referenceOrError.error); return Result.fail(referenceOrError.error);
} }
@ -182,6 +201,8 @@ export class CreateQuoteUseCase
validity: validityOrError.object, validity: validityOrError.object,
items, items,
dealerId,
}, },
quoteId quoteId
); );

View File

@ -1,11 +1,12 @@
import { IUseCase, IUseCaseError, UseCaseError } from "@/contexts/common/application/useCases"; import { IUseCase, IUseCaseError, UseCaseError } from "@/contexts/common/application/useCases";
import { IRepositoryManager } from "@/contexts/common/domain"; import { IRepositoryManager } from "@/contexts/common/domain";
import { Collection, ICollection, IQueryCriteria, Result } from "@shared/contexts"; import { Collection, Filter, ICollection, IQueryCriteria, Result } from "@shared/contexts";
import { IInfrastructureError } from "@/contexts/common/infrastructure"; import { IInfrastructureError } from "@/contexts/common/infrastructure";
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize"; import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
import { Quote } from "../../domain"; import { Dealer, Quote } from "../../domain";
import { IQuoteRepository } from "../../domain/repository"; import { IQuoteRepository } from "../../domain/repository";
import { ISalesContext } from "../../infrastructure";
export interface IListQuotesParams { export interface IListQuotesParams {
queryCriteria: IQueryCriteria; queryCriteria: IQueryCriteria;
@ -18,15 +19,28 @@ export type ListQuotesResult =
export class ListQuotesUseCase implements IUseCase<IListQuotesParams, Promise<ListQuotesResult>> { export class ListQuotesUseCase implements IUseCase<IListQuotesParams, Promise<ListQuotesResult>> {
private _adapter: ISequelizeAdapter; private _adapter: ISequelizeAdapter;
private _repositoryManager: IRepositoryManager; private _repositoryManager: IRepositoryManager;
private _dealer?: Dealer;
constructor(props: { adapter: ISequelizeAdapter; repositoryManager: IRepositoryManager }) { constructor(context: ISalesContext) {
this._adapter = props.adapter; this._adapter = context.adapter;
this._repositoryManager = props.repositoryManager; this._repositoryManager = context.repositoryManager;
this._dealer = context.dealer;
} }
async execute(params: Partial<IListQuotesParams>): Promise<ListQuotesResult> { async execute(params: Partial<IListQuotesParams>): Promise<ListQuotesResult> {
const { queryCriteria } = params; const { queryCriteria } = params;
if (this._dealer) {
queryCriteria?.filters.add(
Filter.create({
operator: "eq",
field: "dealer_id",
value: this._dealer.id,
}).object,
"AND"
);
}
return this.findQuotes(queryCriteria); return this.findQuotes(queryCriteria);
} }

View File

@ -72,7 +72,7 @@ export class UpdateQuoteUseCase
// Errores manuales // Errores manuales
case DomainError.INVALID_INPUT_DATA: case DomainError.INVALID_INPUT_DATA:
errorCode = UseCaseError.INVALID_INPUT_DATA; errorCode = UseCaseError.INVALID_INPUT_DATA;
message = "El usuario tiene algún dato erróneo."; message = "El presupuesto tiene algún dato erróneo.";
break; break;
default: default:

View File

@ -111,6 +111,6 @@ export class Quote extends AggregateRoot<IQuoteProps> implements IQuote {
} }
get dealerId() { get dealerId() {
return this.dealerId; return this.props.dealerId;
} }
} }

View File

@ -1,2 +1,2 @@
export * from "./Dealer/Dealer"; export * from "./Dealer";
export * from "./Quotes"; export * from "./Quotes";

View File

@ -1,32 +1,7 @@
import { IRepositoryManager, RepositoryManager } from "@/contexts/common/domain"; import { IContext } from "@/contexts/common/infrastructure";
import { import { Dealer } from "../domain";
ISequelizeAdapter,
createSequelizeAdapter,
} from "@/contexts/common/infrastructure/sequelize";
export interface ISalesContext { export interface ISalesContext extends IContext {
adapter: ISequelizeAdapter;
repositoryManager: IRepositoryManager;
//services: IApplicationService; //services: IApplicationService;
} dealer?: Dealer;
export class SalesContext {
private static instance: SalesContext | null = null;
public static getInstance(): ISalesContext {
if (!SalesContext.instance) {
SalesContext.instance = new SalesContext({
adapter: createSequelizeAdapter(),
repositoryManager: RepositoryManager.getInstance(),
});
}
return SalesContext.instance.context;
}
private context: ISalesContext;
private constructor(context: ISalesContext) {
this.context = context;
}
} }

View File

@ -1,3 +1,34 @@
import { getDealerByUserController } from "../controllers/dealers/getDealerByUser"; import { AuthUser } from "@/contexts/auth/domain";
import { GetDealerByUserUseCase } from "@/contexts/sales/application";
import Express from "express";
import { registerDealerRepository } from "../../Dealer.repository";
import { ISalesContext } from "../../Sales.context";
export const getDealerMiddleware = getDealerByUserController; export const getDealerMiddleware = async (
req: Express.Request,
res: Express.Response,
next: Express.NextFunction
) => {
const user = <AuthUser>req.user;
const context: ISalesContext = res.locals.context;
registerDealerRepository(context);
try {
const dealerOrError = await new GetDealerByUserUseCase(context).execute({
userId: user.id,
});
if (dealerOrError.isFailure) {
return res.status(500).json().send();
//return this._handleExecuteError(result.error);
}
context.dealer = dealerOrError.object;
return next();
} catch (e: unknown) {
//return this.fail(e as IServerError);
return res.status(500).json().send();
}
};

View File

@ -20,29 +20,36 @@ class DealerMapper
} }
protected toDomainMappingImpl(source: Dealer_Model, params: any): Dealer { protected toDomainMappingImpl(source: Dealer_Model, params: any): Dealer {
const name = this.mapsValue(source, "name", Name.create);
const user_id = this.mapsValue(source, "user_id", UniqueID.create);
const status = this.mapsValue(source, "status", DealerStatus.create);
const language = this.mapsValue(source, "lang_code", Language.createFromCode);
const additionalInfoOrError = KeyValueMap.create([
["contact_information", source.contact_information],
["default_payment_method", source.default_payment_method],
["default_notes", source.default_notes],
["default_legal_terms", source.default_legal_terms],
["default_quote_validity", source.default_quote_validity],
]);
const props: IDealerProps = { const props: IDealerProps = {
user_id: this.mapsValue(source, "user_id", UniqueID.create), user_id,
logo: "", logo: "",
name: this.mapsValue(source, "name", Name.create), name,
status: this.mapsValue(source, "status", DealerStatus.create), status,
language: this.mapsValue(source, "language", Language.createFromCode), language,
additionalInfo: KeyValueMap.create([ additionalInfo: additionalInfoOrError.object,
["contact_information", source.contact_information],
["default_payment_method", source.default_payment_method],
["default_notes", source.default_notes],
["default_legal_terms", source.default_legal_terms],
["default_quote_validity", source.default_quote_validity],
]).object,
}; };
const id = this.mapsValue(source, "id", UniqueID.create); const id = this.mapsValue(source, "id", UniqueID.create);
const userOrError = Dealer.create(props, id); const dealerOrError = Dealer.create(props, id);
if (userOrError.isFailure) { if (dealerOrError.isFailure) {
throw userOrError.error; throw dealerOrError.error;
} }
return userOrError.object; return dealerOrError.object;
} }
protected toPersistenceMappingImpl(source: Dealer, params?: MapperParamsType | undefined) { protected toPersistenceMappingImpl(source: Dealer, params?: MapperParamsType | undefined) {
@ -53,7 +60,7 @@ class DealerMapper
logo: "", logo: "",
name: source.name.toPrimitive(), name: source.name.toPrimitive(),
status: source.status.toPrimitive(), status: source.status.toPrimitive(),
language: source.language.toPrimitive(), lang_code: source.language.toPrimitive(),
contact_information: source.additionalInfo.get("contact_information")?.toString() ?? "", contact_information: source.additionalInfo.get("contact_information")?.toString() ?? "",
default_payment_method: source.additionalInfo.get("default_payment_method")?.toString() ?? "", default_payment_method: source.additionalInfo.get("default_payment_method")?.toString() ?? "",
default_notes: source.additionalInfo.get("default_notes")?.toString() ?? "", default_notes: source.additionalInfo.get("default_notes")?.toString() ?? "",

View File

@ -1,5 +1,6 @@
import { UserCreationAttributes, User_Model } from "@/contexts/users"; import { User_Model } from "@/contexts/users";
import { import {
CreationOptional,
DataTypes, DataTypes,
InferAttributes, InferAttributes,
InferCreationAttributes, InferCreationAttributes,
@ -8,14 +9,14 @@ import {
Op, Op,
Sequelize, Sequelize,
} from "sequelize"; } from "sequelize";
import { QuoteCreationAttributes, Quote_Model } from "./quote.model"; import { Quote_Model } from "./quote.model";
export type DealerCreationAttributes = InferCreationAttributes< export type DealerCreationAttributes = InferCreationAttributes<
Dealer_Model, Dealer_Model,
{ omit: "user" | "quotes" } { omit: "user" | "quotes" }
> & { > & {
user: UserCreationAttributes; user_id: string;
quotes: QuoteCreationAttributes[]; //quotes?: QuoteCreationAttributes[];
}; };
export class Dealer_Model extends Model< export class Dealer_Model extends Model<
@ -45,15 +46,15 @@ export class Dealer_Model extends Model<
} }
declare id: string; declare id: string;
declare contact_id?: string; // number ?? declare contact_id?: CreationOptional<string>;
declare name: string; declare name: CreationOptional<string>;
declare contact_information: string; declare contact_information: CreationOptional<string>;
declare default_payment_method: string; declare default_payment_method: CreationOptional<string>;
declare default_notes: string; declare default_notes: CreationOptional<string>;
declare default_legal_terms: string; declare default_legal_terms: CreationOptional<string>;
declare default_quote_validity: string; declare default_quote_validity: CreationOptional<string>;
declare status: string; declare status: CreationOptional<string>;
declare language: string; declare lang_code: CreationOptional<string>;
declare user: NonAttribute<User_Model>; declare user: NonAttribute<User_Model>;
declare quotes: NonAttribute<Quote_Model>; declare quotes: NonAttribute<Quote_Model>;
@ -82,7 +83,12 @@ export default (sequelize: Sequelize) => {
default_notes: DataTypes.TEXT, default_notes: DataTypes.TEXT,
default_legal_terms: DataTypes.TEXT, default_legal_terms: DataTypes.TEXT,
default_quote_validity: DataTypes.TEXT, default_quote_validity: DataTypes.TEXT,
language: DataTypes.STRING,
lang_code: {
type: DataTypes.STRING(2),
allowNull: false,
defaultValue: "es",
},
status: { status: {
type: DataTypes.STRING, type: DataTypes.STRING,

View File

@ -33,8 +33,8 @@ export class Quote_Model extends Model<
}); });
Quote_Model.belongsTo(Dealer_Model, { Quote_Model.belongsTo(Dealer_Model, {
as: "dealer",
foreignKey: "dealer_id", foreignKey: "dealer_id",
as: "dealer",
onDelete: "RESTRICT", onDelete: "RESTRICT",
}); });
} }

View File

@ -1,7 +1,3 @@
import { RepositoryManager } from "@/contexts/common/domain"; import { ContextFactory } from "@/contexts/common/infrastructure";
import { createSequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
export const createContextMiddleware = () => ({ export const createContextMiddleware = () => ContextFactory.getInstance();
adapter: createSequelizeAdapter(),
repositoryManager: RepositoryManager.getInstance(),
});

View File

@ -3,13 +3,14 @@ import {
createQuoteController, createQuoteController,
listQuotesController, listQuotesController,
} from "@/contexts/sales/infrastructure/express/controllers"; } from "@/contexts/sales/infrastructure/express/controllers";
import { getDealerMiddleware } from "@/contexts/sales/infrastructure/express/middlewares/dealerMiddleware";
import Express from "express"; import Express from "express";
export const QuoteRouter = (appRouter: Express.Router) => { export const QuoteRouter = (appRouter: Express.Router) => {
const quoteRoutes: Express.Router = Express.Router({ mergeParams: true }); const quoteRoutes: Express.Router = Express.Router({ mergeParams: true });
quoteRoutes.get("/", checkUser, listQuotesController); quoteRoutes.get("/", checkUser, getDealerMiddleware, listQuotesController);
quoteRoutes.post("/", checkUser, createQuoteController); quoteRoutes.post("/", checkUser, getDealerMiddleware, createQuoteController);
//quoteRoutes.put("/:quoteId", checkUser, updateQuoteController); //quoteRoutes.put("/:quoteId", checkUser, updateQuoteController);

View File

@ -12,11 +12,17 @@ export interface IFilterCriteria {
toObject(): Record<string, any>; toObject(): Record<string, any>;
} }
export class FilterCriteria interface IFilterNode {
extends StringValueObject connection: string | undefined;
implements IFilterCriteria filter: Filter;
{ }
export class FilterCriteria extends StringValueObject implements IFilterCriteria {
protected _root: IFilterNode;
protected static parseFilterString = (filterString: string): string[][] => { protected static parseFilterString = (filterString: string): string[][] => {
// Ejemplo: lang_code[eq]pt|AND|dealer_id[eq]2222222|and|pepe[eq]assaas
// eslint-disable-next-line no-useless-escape // eslint-disable-next-line no-useless-escape
const regex = /(?:\|([^\]]+)(?:\|))*([^\[|]+)\[([^\]]+)\]([^\[|]+)/gi; const regex = /(?:\|([^\]]+)(?:\|))*([^\[|]+)\[([^\]]+)\]([^\[|]+)/gi;
const result: any[] = []; const result: any[] = [];
@ -40,14 +46,8 @@ export class FilterCriteria
} }
protected static validate(value: UndefinedOr<string>) { protected static validate(value: UndefinedOr<string>) {
if ( if (RuleValidator.validate(RuleValidator.RULE_NOT_NULL_OR_UNDEFINED, value).isSuccess) {
RuleValidator.validate(RuleValidator.RULE_NOT_NULL_OR_UNDEFINED, value) const stringOrError = RuleValidator.validate(RuleValidator.RULE_IS_TYPE_STRING, value);
.isSuccess
) {
const stringOrError = RuleValidator.validate(
RuleValidator.RULE_IS_TYPE_STRING,
value
);
if (stringOrError.isFailure) { if (stringOrError.isFailure) {
return stringOrError; return stringOrError;
@ -75,8 +75,13 @@ export class FilterCriteria
return Result.ok(filterString); return Result.ok(filterString);
} }
constructor(value: string) {
super(value);
this._root = this.buildFilterRoot(value);
}
public getFilterRoot(): any { public getFilterRoot(): any {
return this.buildFilterRoot(); return this._root;
} }
public toJSON(): string { public toJSON(): string {
@ -91,7 +96,7 @@ export class FilterCriteria
return this.getFilterRoot(); return this.getFilterRoot();
} }
protected buildFilterRoot(): any { protected buildFilterRoot(filterString: string): IFilterNode {
const __processNodes: any = (nodes: any[], prevFilter?: IFilter) => { const __processNodes: any = (nodes: any[], prevFilter?: IFilter) => {
const _node: any = nodes.shift(); const _node: any = nodes.shift();
@ -109,37 +114,39 @@ export class FilterCriteria
}; };
}; };
const filterString = String(this.props); const filterNodes = FilterCriteria.parseFilterString(filterString).map((token: string[]) => {
/** TOKEN
* [1] => and / or (optional)
* [2] => field
* [3] => operator
* [4] => value
*/
const connection = token[1] ? String(token[1]).toUpperCase() : undefined;
const filterNodes = FilterCriteria.parseFilterString(filterString).map( const filterOrError = Filter.create({
(token: string[]) => { field: token[2],
/** TOKEN operator: String(token[3]).toUpperCase(),
* [1] => and / or (opcional) value: token[4],
* [2] => field });
* [3] => operator
* [4] => value
*/
const connection = token[1]
? String(token[1]).toUpperCase()
: undefined;
const filterOrError = Filter.create({ if (filterOrError.isFailure) {
field: token[2], throw new Error(`Filter '${token.join()}' is not valid`);
operator: String(token[3]).toUpperCase(),
value: token[4],
});
if (filterOrError.isFailure) {
throw new Error(`Filter '${token.join()}' is not valid`);
}
return {
connection,
filter: filterOrError.object,
};
} }
);
return {
connection,
filter: filterOrError.object,
};
});
return __processNodes(filterNodes, null); return __processNodes(filterNodes, null);
} }
public add(filter: Filter, connection: string = "AND"): void {
const newFilterString = `${connection.toLowerCase()}|${
filter.field
}[${filter.operator.toLowerCase()}]${filter.value}`;
this._root = this.buildFilterRoot(`${this.props}|${newFilterString}`);
}
} }

View File

@ -1,4 +1,5 @@
export interface IGetDealerResponse_DTO { export interface IGetDealerResponse_DTO {
id: string; id: string;
name: string; name: string;
lang_code: string;
} }