@medyll/idae-query 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # create-svelte
2
+
3
+ Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
4
+
5
+ Read more about creating a library [in the docs](https://kit.svelte.dev/docs/packaging).
6
+
7
+ ## Creating a project
8
+
9
+ If you're seeing this, you've probably already done this step. Congrats!
10
+
11
+ ```bash
12
+ # create a new project in the current directory
13
+ npm create svelte@latest
14
+
15
+ # create a new project in my-app
16
+ npm create svelte@latest my-app
17
+ ```
18
+
19
+ ## Developing
20
+
21
+ Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
22
+
23
+ ```bash
24
+ npm run dev
25
+
26
+ # or start the server and open the app in a new browser tab
27
+ npm run dev -- --open
28
+ ```
29
+
30
+ Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
31
+
32
+ ## Building
33
+
34
+ To build your library:
35
+
36
+ ```bash
37
+ npm run package
38
+ ```
39
+
40
+ To create a production version of your showcase app:
41
+
42
+ ```bash
43
+ npm run build
44
+ ```
45
+
46
+ You can preview the production build with `npm run preview`.
47
+
48
+ > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
49
+
50
+ ## Publishing
51
+
52
+ Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
53
+
54
+ To publish your library to [npm](https://www.npmjs.com):
55
+
56
+ ```bash
57
+ npm publish
58
+ ```
@@ -0,0 +1,5 @@
1
+ export * from './operators/operators.js';
2
+ export * from './path/pathResolver.js';
3
+ export * from './query/query.js';
4
+ export * from './resultset/resultset.js';
5
+ export * from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // Reexport of entry components
2
+ export * from './operators/operators.js';
3
+ export * from './path/pathResolver.js';
4
+ export * from './query/query.js';
5
+ export * from './resultset/resultset.js';
6
+ export * from './types.js';
@@ -0,0 +1,8 @@
1
+ import { type Operator, type OperatorType, type Where } from '../types.js';
2
+ export declare class Operators {
3
+ #private;
4
+ static operators: (keyof OperatorType)[];
5
+ static parse<T extends object>(data: T[], qy: Where<T>): T[];
6
+ static filters<F extends object>(fieldName: keyof F | Operator, operator: keyof OperatorType, value: OperatorType[typeof operator], data: F[]): F[];
7
+ static addCustomOperator(operatorName: string, operatorFunction: <T extends object>(fieldName: keyof T, value: any, data: T) => boolean): void;
8
+ }
@@ -0,0 +1,161 @@
1
+ /* D:\boulot\app-node\idbql\src\lib\scripts\operators\operators.ts */
2
+ import {} from '../types.js';
3
+ export class Operators {
4
+ static operators = [
5
+ 'eq',
6
+ 'gt',
7
+ 'gte',
8
+ 'lt',
9
+ 'lte',
10
+ 'ne',
11
+ 'in',
12
+ 'nin',
13
+ 'contains',
14
+ 'startsWith',
15
+ 'endsWith',
16
+ 'btw'
17
+ ];
18
+ static #operatorsFunctions = {
19
+ eq: this.#equalityComparison,
20
+ gt: this.#greaterThanComparison,
21
+ gte: this.#greaterThanOrEqualComparison,
22
+ in: this.#inclusionComparison,
23
+ nin: this.#exclusionComparison,
24
+ lt: this.#lessThanComparison,
25
+ lte: this.#lessThanOrEqualComparison,
26
+ ne: this.#notEqualComparison,
27
+ contains: this.#containsComparison,
28
+ startsWith: this.#startsWithComparison,
29
+ endsWith: this.#endsWithComparison,
30
+ btw: this.#betweenComparison
31
+ };
32
+ static parse(data, qy) {
33
+ return data.filter((dt) => {
34
+ for (const fieldName in qy) {
35
+ const query = qy[fieldName];
36
+ if (typeof query === 'object' &&
37
+ Operators.operators.includes(Object.keys(query)[0])) {
38
+ for (const key in query) {
39
+ if (Operators.operators.includes(key)) {
40
+ const operator = key;
41
+ let value = query[key];
42
+ // Convertir en Set pour 'in' et 'nin'
43
+ if (operator === 'in' || operator === 'nin') {
44
+ value = new Set(value);
45
+ }
46
+ return this.#operatorsFunctions[operator](fieldName, value, dt);
47
+ }
48
+ }
49
+ }
50
+ else {
51
+ return dt[fieldName] == query;
52
+ }
53
+ }
54
+ });
55
+ }
56
+ static filters(fieldName, operator, value, data) {
57
+ // Utilisation de Set pour 'in' et 'nin'
58
+ if (operator === 'in' || operator === 'nin') {
59
+ value = new Set(value);
60
+ }
61
+ // Gestion des cas où fieldName est un opérateur (pour les nouvelles formes de requête)
62
+ if (this.operators.includes(fieldName)) {
63
+ return data.filter((item) => this.#applyOperatorToObject(fieldName, value, item));
64
+ }
65
+ return data.filter((dta) => this.#operatorsFunctions[operator](fieldName, value, dta));
66
+ }
67
+ static #applyOperatorToObject(operator, conditions, item) {
68
+ for (const field in conditions) {
69
+ if (!this.#operatorsFunctions[operator](field, conditions[field], item)) {
70
+ return false;
71
+ }
72
+ }
73
+ return true;
74
+ }
75
+ static #equalityComparison(fieldName, value, data) {
76
+ if (!(fieldName in data)) {
77
+ console.warn(`Field "${String(fieldName)}" not found in data`);
78
+ return false;
79
+ }
80
+ const dataValue = data[fieldName];
81
+ if (typeof dataValue === 'string' && typeof value === 'string') {
82
+ const valueStr = value.toString();
83
+ const startsWith = valueStr.startsWith('*');
84
+ const endsWith = valueStr.endsWith('*');
85
+ if (startsWith && endsWith) {
86
+ return dataValue.includes(valueStr.slice(1, -1));
87
+ }
88
+ else if (startsWith) {
89
+ return dataValue.endsWith(valueStr.slice(1));
90
+ }
91
+ else if (endsWith) {
92
+ return dataValue.startsWith(valueStr.slice(0, -1));
93
+ }
94
+ }
95
+ return dataValue === value;
96
+ }
97
+ static addCustomOperator(operatorName, operatorFunction) {
98
+ if (this.operators.includes(operatorName)) {
99
+ console.warn(`Operator "${operatorName}" already exists. It will be overwritten.`);
100
+ }
101
+ this.operators.push(operatorName);
102
+ this.#operatorsFunctions[operatorName] = operatorFunction;
103
+ }
104
+ static #greaterThanComparison(fieldName, value, data) {
105
+ return value < data[fieldName];
106
+ }
107
+ static #greaterThanOrEqualComparison(fieldName, value, data) {
108
+ return value <= data[fieldName];
109
+ }
110
+ /**
111
+ * Checks if the field value is in the given set.
112
+ * @param fieldName - The name of the field to check
113
+ * @param value - A Set of values to check against
114
+ * @param data - The object containing the field
115
+ * @returns {boolean} - True if the field value is in the set, false otherwise
116
+ */
117
+ static #inclusionComparison(fieldName, value, data) {
118
+ return value.has(data[fieldName]);
119
+ }
120
+ /**
121
+ * Checks if the field value is not in the given set.
122
+ * @param fieldName - The name of the field to check
123
+ * @param value - A Set of values to check against
124
+ * @param data - The object containing the field
125
+ * @returns {boolean} - True if the field value is not in the set, false otherwise
126
+ */
127
+ static #exclusionComparison(fieldName, value, data) {
128
+ return !value.has(data[fieldName]);
129
+ }
130
+ static #lessThanComparison(fieldName, value, data) {
131
+ return value > data[fieldName];
132
+ }
133
+ static #lessThanOrEqualComparison(fieldName, value, data) {
134
+ return value >= data[fieldName];
135
+ }
136
+ static #notEqualComparison(fieldName, value, data) {
137
+ return value !== data[fieldName];
138
+ }
139
+ static #containsComparison(fieldName, value, data) {
140
+ return `${data[fieldName]}`.includes(value);
141
+ }
142
+ static #startsWithComparison(fieldName, value, data) {
143
+ return `${data[fieldName]}`.startsWith(value);
144
+ }
145
+ static #endsWithComparison(fieldName, value, data) {
146
+ return `${data[fieldName]}`.endsWith(value);
147
+ }
148
+ static #betweenComparison(fieldName, value, data) {
149
+ if (!(fieldName in data)) {
150
+ console.warn(`Field "${String(fieldName)}" not found in data`);
151
+ return false;
152
+ }
153
+ const fieldValue = data[fieldName];
154
+ if (typeof fieldValue !== 'number') {
155
+ console.warn(`Field "${String(fieldName)}" is not a number`);
156
+ return false;
157
+ }
158
+ const [min, max] = value;
159
+ return fieldValue >= min && fieldValue <= max;
160
+ }
161
+ }
@@ -0,0 +1,14 @@
1
+ export type DotPath<T> = T extends object ? {
2
+ [K in keyof T]: T[K] extends null | undefined ? K & string : `${K & string}${"" extends DotPath<T[K]> ? "" : "."}${DotPath<T[K]>}`;
3
+ }[keyof T] : "";
4
+ /**
5
+ * Resolves a dot path on an object and returns the value at that path.
6
+ * If the path does not exist, it returns the defaultValue.
7
+ *
8
+ * @template T - The type of the value to be returned.
9
+ * @param object - The object to resolve the path on.
10
+ * @param path - The dot path to resolve.
11
+ * @param defaultValue - The default value to return if the path does not exist. (optional)
12
+ * @returns The value at the specified path, or the defaultValue if the path does not exist.
13
+ */
14
+ export declare function dotPath<T = unknown>(object: Record<string, any>, path: string, defaultValue?: any): T;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Resolves a dot path on an object and returns the value at that path.
3
+ * If the path does not exist, it returns the defaultValue.
4
+ *
5
+ * @template T - The type of the value to be returned.
6
+ * @param object - The object to resolve the path on.
7
+ * @param path - The dot path to resolve.
8
+ * @param defaultValue - The default value to return if the path does not exist. (optional)
9
+ * @returns The value at the specified path, or the defaultValue if the path does not exist.
10
+ */
11
+ export function dotPath(object, path, defaultValue) {
12
+ return (path.split(".").reduce((r, s) => (r ? r[s] : defaultValue), object) ??
13
+ defaultValue);
14
+ }
@@ -0,0 +1,8 @@
1
+ import type { Where } from '../types.js';
2
+ export declare class Query<T extends object> {
3
+ data: T[];
4
+ constructor(data: T[]);
5
+ where(qy: Where<T>): import("../resultset/resultset.js").ResultSet<T>;
6
+ private matchesQuery;
7
+ private matchesField;
8
+ }
@@ -0,0 +1,33 @@
1
+ /* src\lib\scripts\query\query.ts */
2
+ import { Operators } from '../operators/operators.js';
3
+ import { getResultset } from '../resultset/resultset.js';
4
+ export class Query {
5
+ data;
6
+ constructor(data) {
7
+ this.data = data;
8
+ getResultset(this.data ?? []);
9
+ }
10
+ where(qy) {
11
+ this.data = this.data.filter((item) => this.matchesQuery(item, qy));
12
+ return getResultset(this.data);
13
+ }
14
+ matchesQuery(item, query) {
15
+ if (typeof query !== 'object' || query === null) {
16
+ return false;
17
+ }
18
+ return Object.entries(query).every(([key, value]) => {
19
+ if (Operators.operators.includes(key)) {
20
+ return Operators.filters(key, 'eq', value, [item]).length > 0;
21
+ }
22
+ else {
23
+ return this.matchesField(item, key, value);
24
+ }
25
+ });
26
+ }
27
+ matchesField(item, field, condition) {
28
+ if (typeof condition === 'object' && condition !== null && !Array.isArray(condition)) {
29
+ return Object.entries(condition).every(([op, val]) => Operators.filters(field, op, val, [item]).length > 0);
30
+ }
31
+ return Operators.filters(field, 'eq', condition, [item]).length > 0;
32
+ }
33
+ }
@@ -0,0 +1,39 @@
1
+ ## ResultSet.ts
2
+
3
+ This class `ResultSet` is used to manipulate and iterate over a set of data. The class is iterable, meaning it can be spread into an array or iterated over with a `for...of` loop.
4
+
5
+ ### Methods
6
+
7
+
8
+
9
+ #### setOptions<T>(options: OptionsType)
10
+
11
+ - Action: Sets the options for the result set in one pass.
12
+ - Arguments: An `OptionsType` object which can contain `sort`, `page`, and `groupBy` properties.
13
+ - `sort`: An object where the keys represent the properties to sort by, and the values represent the sort order ("asc" for ascending, "desc" for descending).
14
+ - `page`: An object with `size` and `number` properties, representing the number of items per page and the page number to retrieve, respectively.
15
+ - `groupBy`: A string or an array of strings, representing the field names to group by.
16
+ - Return: The updated result set.
17
+
18
+
19
+ #### sortBy(args: Record<string, "asc" | "desc">)
20
+
21
+ - Action: Sorts the data in the result set based on the provided sorting criteria.
22
+ - Arguments: An object where the keys represent the properties to sort by, and the values represent the sort order ("asc" for ascending, "desc" for descending).
23
+ - Return: The sorted result set.
24
+
25
+ #### getPage(size: number, page: number)
26
+
27
+ - Action: Retrieves a specific page of data from the result set.
28
+ - Arguments: The `size` parameter specifies the number of items per page, and the `page` parameter specifies the page number to retrieve.
29
+ - Return: A new result set containing the specified page of data.
30
+
31
+ #### groupBy(fieldName: string | string[], transform?: (value: any) => void)
32
+
33
+ - Action: Groups the result set by the specified field name(s).
34
+ - Arguments: The `fieldName` parameter can be a string or an array of strings, representing the field names to group by. The `transform` parameter is an optional transformation function to apply to each grouped value.
35
+ - Return: An object representing the grouped result set.
36
+
37
+ ### Iterability
38
+
39
+ The `ResultSet` class is iterable, meaning it can be spread into an array or iterated over with a `for...of` loop. This is achieved by implementing the `[Symbol.iterator]` method.
@@ -0,0 +1,35 @@
1
+ import { type DotPath } from "../path/pathResolver.js";
2
+ /**
3
+ * Represents the options for a result set.
4
+ * @template T - The type of the result set.
5
+ */
6
+ export type ResultsetOptions<T = any> = {
7
+ /** Can receive a dot path for sorting. */
8
+ sort?: Record<DotPath<T>, "asc" | "desc">;
9
+ /** Specifies the property to group the result set by. */
10
+ groupBy?: DotPath<T>;
11
+ /** Specifies the page size of the result set. */
12
+ pageSize?: number;
13
+ };
14
+ /**
15
+ * Represents a chainable and iterable result set of data.
16
+ * @template T The type of data in the result set.
17
+ */
18
+ export type ResultSet<T> = T[] & {
19
+ setOptions: (options: ResultsetOptions) => ResultSet<T>;
20
+ /** Accepts a dot path */
21
+ sortBy: (args: Record<string, "asc" | "desc">) => ResultSet<T>;
22
+ /** Accepts a dot path as fieldName */
23
+ groupBy: (fieldName: string | string[],
24
+ /** Transformer function to generate the grouped key */
25
+ transform?: (value: any) => void) => Record<string, T[]>;
26
+ getPage: (page: number, size: number) => ResultSet<T>;
27
+ toObject: (dotPath: DotPath<T>) => T[];
28
+ };
29
+ /**
30
+ * Generates a ResultSet based on the provided data array and defines additional properties like setOptions, sortBy, groupBy, and getPage for customization and manipulation.
31
+ *
32
+ * @param {T[]} data - The array of data to generate the ResultSet from.
33
+ * @return {ResultSet<T>} The generated ResultSet with additional properties for customization.
34
+ */
35
+ export declare function getResultset<T = (typeof arguments)[0]>(data: T[]): ResultSet<T>;
@@ -0,0 +1,76 @@
1
+ import { dotPath } from "../path/pathResolver.js";
2
+ /**
3
+ * Generates a ResultSet based on the provided data array and defines additional properties like setOptions, sortBy, groupBy, and getPage for customization and manipulation.
4
+ *
5
+ * @param {T[]} data - The array of data to generate the ResultSet from.
6
+ * @return {ResultSet<T>} The generated ResultSet with additional properties for customization.
7
+ */
8
+ export function getResultset(data) {
9
+ // : ResultSet<T>
10
+ Object.defineProperties(data, {
11
+ setOptions: {
12
+ value: function (options = {}) {
13
+ if (options.sort) {
14
+ this.sortBy(options.sort);
15
+ }
16
+ if (options.groupBy) {
17
+ this.groupBy(options.groupBy);
18
+ }
19
+ return this;
20
+ },
21
+ enumerable: false,
22
+ configurable: true,
23
+ },
24
+ sortBy: {
25
+ value: function (args) {
26
+ const keys = Object.keys(args);
27
+ const values = Object.values(args);
28
+ this.sort((a, b) => {
29
+ let i = 0;
30
+ let result = 0;
31
+ while (i < keys.length && result === 0) {
32
+ let value = keys[i];
33
+ result =
34
+ values[i] === "asc"
35
+ ? Number(dotPath(a, value)) - Number(dotPath(b, value))
36
+ : Number(dotPath(b, value)) - Number(dotPath(a, value));
37
+ i++;
38
+ }
39
+ return result;
40
+ });
41
+ // delete this?.sortBy;
42
+ return this;
43
+ },
44
+ enumerable: false,
45
+ configurable: true,
46
+ },
47
+ groupBy: {
48
+ value: function (fieldName, transform) {
49
+ const finalFieldName = typeof fieldName === "string" ? [fieldName] : fieldName;
50
+ return this.reduce((acc, curr) => {
51
+ let key = "";
52
+ for (let i = 0; i < finalFieldName.length; i++) {
53
+ key += dotPath(curr, finalFieldName[i]);
54
+ }
55
+ if (!acc[key]) {
56
+ acc[key] = [];
57
+ }
58
+ acc[key].push(curr);
59
+ return acc;
60
+ }, {});
61
+ },
62
+ enumerable: false,
63
+ configurable: true,
64
+ },
65
+ getPage: {
66
+ value: function (page, size) {
67
+ const dta = this.slice((size - 1) * page, (size - 1) * page + page);
68
+ delete this?.getPage;
69
+ return dta;
70
+ },
71
+ enumerable: false,
72
+ configurable: true,
73
+ },
74
+ });
75
+ return data;
76
+ }
@@ -0,0 +1,22 @@
1
+ export type Operator = keyof OperatorType;
2
+ export type OperatorType<T = any> = {
3
+ eq?: T;
4
+ gt?: T extends number | Date ? T : never;
5
+ gte?: T extends number | Date ? T : never;
6
+ lt?: T extends number | Date ? T : never;
7
+ lte?: T extends number | Date ? T : never;
8
+ ne?: T;
9
+ in?: T[];
10
+ nin?: T[];
11
+ contains?: T extends string ? string : never;
12
+ startsWith?: T extends string ? string : never;
13
+ endsWith?: T extends string ? string : never;
14
+ btw?: T extends number ? [T, T] : never;
15
+ };
16
+ type WhereCondition<T> = {
17
+ [K in keyof T]?: T[K] | Partial<OperatorType<T[K]>>;
18
+ };
19
+ export type Where<T = Record<string, any>> = WhereCondition<T> | {
20
+ [K in keyof OperatorType]?: Partial<T>;
21
+ };
22
+ export {};
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ /* path: D:\boulot\app-node\idbql\src\lib\scripts\types.ts */
2
+ export {};
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@medyll/idae-query",
3
+ "scope": "@medyll",
4
+ "version": "0.0.1",
5
+ "scripts": {
6
+ "dev": "vite dev",
7
+ "build": "vite build && npm run package",
8
+ "preview": "vite preview",
9
+ "package": "svelte-kit sync && svelte-package && publint",
10
+ "prepublishOnly": "npm run package",
11
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13
+ "test": "vitest",
14
+ "lint": "prettier --check . && eslint .",
15
+ "format": "prettier --write ."
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "svelte": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "!dist/**/*.test.*",
26
+ "!dist/**/*.spec.*"
27
+ ],
28
+ "peerDependencies": {
29
+ "svelte": "^4.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "@sveltejs/adapter-auto": "^3.0.0",
33
+ "@sveltejs/kit": "^2.0.0",
34
+ "@sveltejs/package": "^2.0.0",
35
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
36
+ "@types/eslint": "^8.56.7",
37
+ "eslint": "^9.0.0",
38
+ "eslint-config-prettier": "^9.1.0",
39
+ "eslint-plugin-svelte": "^2.36.0",
40
+ "globals": "^15.0.0",
41
+ "prettier": "^3.1.1",
42
+ "prettier-plugin-svelte": "^3.1.2",
43
+ "publint": "^0.1.9",
44
+ "svelte": "^5.0.0-next.181",
45
+ "svelte-check": "^3.6.0",
46
+ "tslib": "^2.4.1",
47
+ "typescript": "^5.0.0",
48
+ "typescript-eslint": "^8.0.0-alpha.20",
49
+ "vite": "^5.0.11",
50
+ "vitest": "^1.2.0"
51
+ },
52
+ "svelte": "./dist/index.js",
53
+ "types": "./dist/index.d.ts",
54
+ "type": "module"
55
+ }