@medyll/idae-query 0.0.1 → 0.1.0

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 CHANGED
@@ -1,58 +1,184 @@
1
- # create-svelte
1
+ # @medyll/idae-idbql
2
2
 
3
- Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
3
+ A powerful and flexible IndexedDB query library for TypeScript and JavaScript applications.
4
4
 
5
- Read more about creating a library [in the docs](https://kit.svelte.dev/docs/packaging).
5
+ ## Features
6
6
 
7
- ## Creating a project
7
+ - MongoDB-like query interface for IndexedDB
8
+ - Strong TypeScript support with full type inference
9
+ - Reactive state management for real-time UI updates
10
+ - Support for complex CRUD operations and advanced querying
11
+ - Flexible data modeling with automatic schema creation
12
+ - Built-in indexing and optimization features
13
+ - Easy integration with front-end frameworks, especially Svelte
14
+ - Robust error handling and logging
15
+ - Versioning and database migration support
16
+ - Support for svelte 5 state
8
17
 
9
- If you're seeing this, you've probably already done this step. Congrats!
18
+ ## Installation
10
19
 
11
20
  ```bash
12
- # create a new project in the current directory
13
- npm create svelte@latest
21
+ npm install @medyll/idae-idbql
22
+ ```
14
23
 
15
- # create a new project in my-app
16
- npm create svelte@latest my-app
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import { createIdbqDb } from '@medyll/idae-idbql';
28
+
29
+ // Define your data model
30
+ const exampleModel = {
31
+ messages: {
32
+ keyPath: "++id, chatId, created_at",
33
+ ts: {} as ChatMessage,
34
+ },
35
+ chat: {
36
+ keyPath: "&chatId, created_at, dateLastMessage",
37
+ ts: {} as Chat,
38
+ template: {},
39
+ },
40
+ };
41
+
42
+ // Create a database instance
43
+ const idbqStore = createIdbqDb(exampleModel, 1);
44
+ const { idbql, idbqlState, idbDatabase, idbqModel } = idbqStore.create("myDatabase");
45
+
46
+ // Perform database operations
47
+ async function fetchMessages() {
48
+ const messages = await idbql.messages.where({ chatId: "123" }).toArray();
49
+ console.log(messages);
50
+ }
51
+
52
+ fetchMessages();
17
53
  ```
18
54
 
19
- ## Developing
55
+ ## API Reference
20
56
 
21
- Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
57
+ ### createIdbqDb(model, version)
22
58
 
23
- ```bash
24
- npm run dev
59
+ Creates an IndexedDB database instance with the specified model and version.
60
+
61
+ ### idbql
62
+
63
+ The main interface for database operations. Provides methods for each collection defined in your model.
64
+
65
+ ### idbqlState
66
+
67
+ A reactive state object that reflects the current state of your database.
68
+
69
+ ### idbDatabase
70
+
71
+ Provides low-level access to the IndexedDB instance.
25
72
 
26
- # or start the server and open the app in a new browser tab
27
- npm run dev -- --open
73
+ ### idbqModel
74
+
75
+ Contains the database model definition.
76
+
77
+ ## Query Operations
78
+
79
+ ```typescript
80
+ // Add a new item
81
+ await idbql.messages.add({ chatId: "123", content: "Hello" });
82
+
83
+ // Update an item
84
+ await idbql.messages.put({ id: 1, content: "Updated message" });
85
+
86
+ // Delete an item
87
+ await idbql.messages.delete(1);
88
+
89
+ // Query items
90
+ const recentMessages = await idbql.messages
91
+ .where({ created_at: { gt: new Date(Date.now() - 86400000) } })
92
+ .toArray();
28
93
  ```
29
94
 
30
- Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
95
+ ## Transactions
31
96
 
32
- ## Building
97
+ idbql supports complex transactions across multiple object stores:
33
98
 
34
- To build your library:
99
+ ```typescript
100
+ const result = await idbql.transaction(
101
+ ["users", "posts"],
102
+ "readwrite",
103
+ async (tx) => {
104
+ const userStore = tx.objectStore("users");
105
+ const postStore = tx.objectStore("posts");
35
106
 
36
- ```bash
37
- npm run package
107
+ const userId = await userStore.add({ name: "Alice", email: "alice@example.com" });
108
+ const postId = await postStore.add({ userId, title: "Alice's First Post", content: "Hello, World!" });
109
+
110
+ return { userId, postId };
111
+ }
112
+ );
38
113
  ```
39
114
 
40
- To create a production version of your showcase app:
115
+ ## Reactive State Management
41
116
 
42
- ```bash
43
- npm run build
117
+ ```typescript
118
+ import { derived } from 'svelte/store';
119
+
120
+ const activeUsers = $derived(idbqlState.users.where({ isActive: true }));
44
121
  ```
45
122
 
46
- You can preview the production build with `npm run preview`.
123
+ ## Integration with Svelte
47
124
 
48
- > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
125
+ ```svelte
126
+ <script>
127
+ import { derived } from 'svelte/store';
128
+ import { idbqlState } from './store';
49
129
 
50
- ## Publishing
130
+ const messages = $derived(idbqlState.messages.where({ chatId: "123" }));
131
+ </script>
51
132
 
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/)).
133
+ {#each $messages as message}
134
+ <p>{message.content}</p>
135
+ {/each}
136
+ ```
53
137
 
54
- To publish your library to [npm](https://www.npmjs.com):
138
+ ## Versioning and Migrations
139
+
140
+ ```typescript
141
+ const idbqStore = createIdbqDb(myModel, 2);
142
+ const { idbDatabase } = idbqStore.create("myDb", {
143
+ upgrade(oldVersion, newVersion, transaction) {
144
+ if (oldVersion < 2) {
145
+ const userStore = transaction.objectStore("users");
146
+ userStore.createIndex("emailIndex", "email", { unique: true });
147
+ }
148
+ },
149
+ });
150
+ ```
55
151
 
56
- ```bash
57
- npm publish
152
+ ## Error Handling
153
+
154
+ ```typescript
155
+ try {
156
+ await idbql.users.add({ username: "existing_user" });
157
+ } catch (error) {
158
+ if (error instanceof UniqueConstraintError) {
159
+ console.error("Username already exists");
160
+ } else {
161
+ console.error("An unexpected error occurred", error);
162
+ }
163
+ }
58
164
  ```
165
+
166
+ ## Performance Tips
167
+
168
+ - Use appropriate indexes
169
+ - Limit result sets with `.limit(n)`
170
+ - Use `.count()` instead of `.toArray().length`
171
+ - Optimize queries to use indexes effectively
172
+
173
+ ## Contributing
174
+
175
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
176
+
177
+ ## License
178
+
179
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
180
+
181
+ ## Support
182
+
183
+ If you encounter any issues or have questions, please file an issue on the GitHub repository.
184
+
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './operators/operators.js';
2
2
  export * from './path/pathResolver.js';
3
3
  export * from './query/query.js';
4
- export * from './resultset/resultset.js';
4
+ export * from './resultSet/resultset.js';
5
5
  export * from './types.js';
package/dist/index.js CHANGED
@@ -2,5 +2,5 @@
2
2
  export * from './operators/operators.js';
3
3
  export * from './path/pathResolver.js';
4
4
  export * from './query/query.js';
5
- export * from './resultset/resultset.js';
5
+ export * from './resultSet/resultset.js';
6
6
  export * from './types.js';
@@ -1,6 +1,6 @@
1
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] : "";
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
4
  /**
5
5
  * Resolves a dot path on an object and returns the value at that path.
6
6
  * If the path does not exist, it returns the defaultValue.
@@ -9,6 +9,5 @@
9
9
  * @returns The value at the specified path, or the defaultValue if the path does not exist.
10
10
  */
11
11
  export function dotPath(object, path, defaultValue) {
12
- return (path.split(".").reduce((r, s) => (r ? r[s] : defaultValue), object) ??
13
- defaultValue);
12
+ return (path.split('.').reduce((r, s) => (r ? r[s] : defaultValue), object) ?? defaultValue);
14
13
  }
@@ -2,7 +2,7 @@ import type { Where } from '../types.js';
2
2
  export declare class Query<T extends object> {
3
3
  data: T[];
4
4
  constructor(data: T[]);
5
- where(qy: Where<T>): import("../resultset/resultset.js").ResultSet<T>;
5
+ where(qy: Where<T>): any;
6
6
  private matchesQuery;
7
7
  private matchesField;
8
8
  }
@@ -1,39 +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.
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.
@@ -1,11 +1,11 @@
1
- import { type DotPath } from "../path/pathResolver.js";
1
+ import { type DotPath } from '../path/pathResolver.js';
2
2
  /**
3
3
  * Represents the options for a result set.
4
4
  * @template T - The type of the result set.
5
5
  */
6
6
  export type ResultsetOptions<T = any> = {
7
7
  /** Can receive a dot path for sorting. */
8
- sort?: Record<DotPath<T>, "asc" | "desc">;
8
+ sort?: Record<DotPath<T>, 'asc' | 'desc'>;
9
9
  /** Specifies the property to group the result set by. */
10
10
  groupBy?: DotPath<T>;
11
11
  /** Specifies the page size of the result set. */
@@ -18,7 +18,7 @@ export type ResultsetOptions<T = any> = {
18
18
  export type ResultSet<T> = T[] & {
19
19
  setOptions: (options: ResultsetOptions) => ResultSet<T>;
20
20
  /** Accepts a dot path */
21
- sortBy: (args: Record<string, "asc" | "desc">) => ResultSet<T>;
21
+ sortBy: (args: Record<string, 'asc' | 'desc'>) => ResultSet<T>;
22
22
  /** Accepts a dot path as fieldName */
23
23
  groupBy: (fieldName: string | string[],
24
24
  /** Transformer function to generate the grouped key */
@@ -1,4 +1,4 @@
1
- import { dotPath } from "../path/pathResolver.js";
1
+ import { dotPath } from '../path/pathResolver.js';
2
2
  /**
3
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
4
  *
@@ -19,7 +19,7 @@ export function getResultset(data) {
19
19
  return this;
20
20
  },
21
21
  enumerable: false,
22
- configurable: true,
22
+ configurable: true
23
23
  },
24
24
  sortBy: {
25
25
  value: function (args) {
@@ -31,7 +31,7 @@ export function getResultset(data) {
31
31
  while (i < keys.length && result === 0) {
32
32
  let value = keys[i];
33
33
  result =
34
- values[i] === "asc"
34
+ values[i] === 'asc'
35
35
  ? Number(dotPath(a, value)) - Number(dotPath(b, value))
36
36
  : Number(dotPath(b, value)) - Number(dotPath(a, value));
37
37
  i++;
@@ -42,13 +42,13 @@ export function getResultset(data) {
42
42
  return this;
43
43
  },
44
44
  enumerable: false,
45
- configurable: true,
45
+ configurable: true
46
46
  },
47
47
  groupBy: {
48
48
  value: function (fieldName, transform) {
49
- const finalFieldName = typeof fieldName === "string" ? [fieldName] : fieldName;
49
+ const finalFieldName = typeof fieldName === 'string' ? [fieldName] : fieldName;
50
50
  return this.reduce((acc, curr) => {
51
- let key = "";
51
+ let key = '';
52
52
  for (let i = 0; i < finalFieldName.length; i++) {
53
53
  key += dotPath(curr, finalFieldName[i]);
54
54
  }
@@ -60,7 +60,7 @@ export function getResultset(data) {
60
60
  }, {});
61
61
  },
62
62
  enumerable: false,
63
- configurable: true,
63
+ configurable: true
64
64
  },
65
65
  getPage: {
66
66
  value: function (page, size) {
@@ -69,8 +69,8 @@ export function getResultset(data) {
69
69
  return dta;
70
70
  },
71
71
  enumerable: false,
72
- configurable: true,
73
- },
72
+ configurable: true
73
+ }
74
74
  });
75
75
  return data;
76
76
  }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@medyll/idae-query",
3
3
  "scope": "@medyll",
4
- "version": "0.0.1",
4
+ "version": "0.1.0",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
7
7
  "build": "vite build && npm run package",
8
8
  "preview": "vite preview",
9
9
  "package": "svelte-kit sync && svelte-package && publint",
10
+ "package:watch": "svelte-kit sync && svelte-package --watch",
10
11
  "prepublishOnly": "npm run package",
11
12
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
13
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
@@ -26,9 +27,10 @@
26
27
  "!dist/**/*.spec.*"
27
28
  ],
28
29
  "peerDependencies": {
29
- "svelte": "^4.0.0"
30
+ "svelte": "^5.0.0-next.1"
30
31
  },
31
32
  "devDependencies": {
33
+ "@medyll/idae-prettier-config": "^1.0.0",
32
34
  "@sveltejs/adapter-auto": "^3.0.0",
33
35
  "@sveltejs/kit": "^2.0.0",
34
36
  "@sveltejs/package": "^2.0.0",
@@ -41,7 +43,7 @@
41
43
  "prettier": "^3.1.1",
42
44
  "prettier-plugin-svelte": "^3.1.2",
43
45
  "publint": "^0.1.9",
44
- "svelte": "^5.0.0-next.181",
46
+ "svelte": "^5.0.0-next.183",
45
47
  "svelte-check": "^3.6.0",
46
48
  "tslib": "^2.4.1",
47
49
  "typescript": "^5.0.0",
@@ -52,4 +54,4 @@
52
54
  "svelte": "./dist/index.js",
53
55
  "types": "./dist/index.d.ts",
54
56
  "type": "module"
55
- }
57
+ }