Skip to content

Commit

Permalink
feat: add from url adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
rgomezcasas committed Jun 11, 2024
1 parent 1a02a93 commit 80dfebb
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/tame-spoons-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@codelytv/criteria-from-url": major
---

add criteria from url
23 changes: 23 additions & 0 deletions packages/criteria-from-url/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<p align="center">
<a href="https://codely.com">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://codely.com/logo/codely_logo-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://codely.com/logo/codely_logo-light.svg">
<img alt="Codely logo" src="https://codely.com/logo/codely_logo.svg">
</picture>
</a>
</p>

<h1 align="center">
🌐 Criteria from URL
</h1>

<p align="center">
<a href="https://github.com/CodelyTV"><img src="https://img.shields.io/badge/Codely-OS-green.svg?style=flat-square" alt="codely.com"/></a>
</p>

## 📥 Installation

```sh
npm i @codelytv/criteria-from-url
```
20 changes: 20 additions & 0 deletions packages/criteria-from-url/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@codelytv/criteria-from-url",
"version": "0.0.1",
"description": "",
"keywords": [],
"author": "Codely (https://codely.com)",
"license": "MIT",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"test": "node --import tsx --test test/*.test.ts",
"build": "tsc --build --verbose tsconfig.json"
},
"dependencies": {
"@codelytv/criteria": "workspace:^"
},
"devDependencies": {
"@codelytv/criteria-test-mother": "workspace:^"
}
}
49 changes: 49 additions & 0 deletions packages/criteria-from-url/src/CriteriaFromUrlConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { Criteria, FiltersPrimitives } from "@codelytv/criteria";

export class CriteriaFromUrlConverter {
public toCriteria(url: URL): Criteria {
const { searchParams } = url;

const filters = this.parseFilters(searchParams);

return Criteria.fromPrimitives(
filters,
searchParams.get("orderBy"),
searchParams.get("order"),
searchParams.has("pageSize") ? parseInt(searchParams.get("pageSize") as string, 10) : null,
searchParams.has("pageNumber")
? parseInt(searchParams.get("pageNumber") as string, 10)
: null,
);
}

public toFiltersPrimitives(url: URL): FiltersPrimitives[] {
const { searchParams } = url;

return this.parseFilters(searchParams);
}

private parseFilters(searchParams: URLSearchParams): FiltersPrimitives[] {
const tempFilters: Record<string, Partial<FiltersPrimitives>> = {};

searchParams.forEach((value, key) => {
const match = key.match(/filters\[(\d+)]\[(.+)]/);
if (match) {
const index = match[1];
const property = match[2] as keyof FiltersPrimitives;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!tempFilters[index]) {
tempFilters[index] = {};
}
tempFilters[index][property] = value;
}
});

// @ts-ignore
return Object.values(tempFilters).filter(
(filter) =>
filter.field !== undefined && filter.operator !== undefined && filter.value !== undefined,
);
}
}
1 change: 1 addition & 0 deletions packages/criteria-from-url/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./CriteriaFromUrlConverter";
107 changes: 107 additions & 0 deletions packages/criteria-from-url/test/CriteriaFromUrlConverter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import assert from "node:assert";
import { describe, it } from "node:test";

import { CriteriaMother } from "@codelytv/criteria-test-mother";

import { CriteriaFromUrlConverter } from "../src";

describe("CriteriaFromUrlConverter should", () => {
const converter = new CriteriaFromUrlConverter();

it("Converts a url with one filter", () => {
const url = new URL(
"http://localhost:3000/api/users?filters[0][field]=name&filters[0][operator]=CONTAINS&filters[0][value]=Javi",
);

const expectedCriteria = CriteriaMother.withOneFilter("name", "CONTAINS", "Javi");

assert.deepEqual(converter.toCriteria(url), expectedCriteria);
});

it("Converts a url with multiple filters", () => {
const url = new URL(
"http://localhost:3000/api/users?filters[0][field]=name&filters[0][operator]=CONTAINS&filters[0][value]=Javi&filters[1][field]=email&filters[1][operator]=CONTAINS&filters[1][value]=gmail",
);

const expectedCriteria = CriteriaMother.create({
filters: [
{
field: "name",
operator: "CONTAINS",
value: "Javi",
},
{
field: "email",
operator: "CONTAINS",
value: "gmail",
},
],
orderBy: null,
orderType: null,
pageSize: null,
pageNumber: null,
});

assert.deepEqual(converter.toCriteria(url), expectedCriteria);
});

it("Converts a url with multiple filters order and pagination", () => {
const url = new URL(
"http://localhost:3000/api/users" +
"?filters[0][field]=name&filters[0][operator]=CONTAINS&filters[0][value]=Javi" +
"&filters[1][field]=email&filters[1][operator]=CONTAINS&filters[1][value]=gmail",
);

const expectedCriteria = CriteriaMother.create({
filters: [
{
field: "name",
operator: "CONTAINS",
value: "Javi",
},
{
field: "email",
operator: "CONTAINS",
value: "gmail",
},
],
orderBy: null,
orderType: null,
pageSize: null,
pageNumber: null,
});

assert.deepEqual(converter.toCriteria(url), expectedCriteria);
});

it("Converts a url with multiple filters order and pagination", () => {
const url = new URL(
"http://localhost:3000/api/users" +
"?filters[0][field]=name&filters[0][operator]=CONTAINS&filters[0][value]=Javi" +
"&filters[1][field]=email&filters[1][operator]=CONTAINS&filters[1][value]=gmail" +
"&orderBy=name&order=ASC" +
"&pageSize=10&pageNumber=2",
);

const expectedCriteria = CriteriaMother.create({
filters: [
{
field: "name",
operator: "CONTAINS",
value: "Javi",
},
{
field: "email",
operator: "CONTAINS",
value: "gmail",
},
],
orderBy: "name",
orderType: "ASC",
pageSize: 10,
pageNumber: 2,
});

assert.deepEqual(converter.toCriteria(url), expectedCriteria);
});
});
7 changes: 7 additions & 0 deletions packages/criteria-from-url/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["src/**/*"],
}
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 80dfebb

Please sign in to comment.