@dbcube/query-builder 1.0.49 → 1.0.50

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,23 +1,85 @@
1
- # query-builder
1
+ # @dbcube/query-builder
2
2
 
3
- The DBCube Query Builder is a lightweight, flexible, and fluent library for building queries across multiple database engines, including MySQL, PostgreSQL, SQLite, and MongoDB, using JavaScript/Node.js.
3
+ ## Language/Lenguaje
4
4
 
5
- Its agnostic design allows you to generate data manipulation (DML) and data definition (DDL) operations with a clean, chainable syntax—without sacrificing power or expressiveness.
5
+ - [English](#english-documentation)
6
+ - [Español](#documentación-en-español)
6
7
 
7
- It’s designed to work seamlessly in both SQL and NoSQL environments, providing a consistent abstraction layer across different storage technologies while still leveraging the native capabilities of each engine.
8
+ ---
9
+
10
+ ## English documentation
11
+
12
+ ## Table of contents 🚀
13
+
14
+ - [Introduction](#introduction)
15
+ - [Features](#features)
16
+ - [Installation](#installation)
17
+ - [Configuration](#configuration)
18
+ - [Basic Usage](#basic-usage)
19
+ - [Database Connection](#database-connection)
20
+ - [Table Operations](#table-operations)
21
+ - [CRUD Operations](#crud-operations)
22
+ - [Inserting Data](#inserting-data)
23
+ - [Selecting Data](#selecting-data)
24
+ - [Updating Data](#updating-data)
25
+ - [Deleting Data](#deleting-data)
26
+ - [Advanced Queries](#advanced-queries)
27
+ - [WHERE Query](#where-query)
28
+ - [OR WHERE Query](#or-where-query)
29
+ - [WHERE Condition Groups](#where-condition-groups)
30
+ - [BETWEEN Query](#between-query)
31
+ - [IN Query](#in-query)
32
+ - [IS NULL / IS NOT NULL Query](#is-null--is-not-null-query)
33
+ - [JOIN Query](#join-query)
34
+ - [LEFT JOIN Query](#left-join-query)
35
+ - [RIGHT JOIN Query](#right-join-query)
36
+ - [ORDER BY Query](#order-by-query)
37
+ - [LIMIT and OFFSET Query (Pagination)](#limit-and-offset-query-pagination)
38
+ - [GROUP BY Query](#group-by-query)
39
+ - [DISTINCT Query](#distinct-query)
40
+ - [Aggregate Functions](#aggregate-functions)
41
+ - [count](#count)
42
+ - [sum](#sum)
43
+ - [avg](#avg)
44
+ - [max](#max)
45
+ - [min](#min)
46
+ - [Finding Records](#finding-records)
47
+ - [find](#find)
48
+ - [first](#first)
49
+ - [Computed Fields and Triggers](#computed-fields-and-triggers)
50
+ - [Executing Raw SQL Queries](#executing-raw-sql-queries)
51
+ - [Error Handling](#error-handling)
52
+ - [Complete API](#complete-api)
53
+ - [Database Class](#database-class)
54
+ - [Table Class](#table-class)
55
+ - [Multi-Database Support](#multi-database-support)
56
+ - [Advanced Features](#advanced-features)
57
+ - [License](#license)
58
+
59
+ ## Introduction
60
+
61
+ `@dbcube/query-builder` is a lightweight, flexible, and fluent Node.js library designed to build queries across multiple database engines, including MySQL, PostgreSQL, SQLite, and MongoDB, using JavaScript/TypeScript.
62
+
63
+ Its agnostic design allows you to generate data manipulation (DML) and data definition (DDL) operations with a clean, chainable syntax—without sacrificing power or expressiveness. It's designed to work seamlessly in both SQL and NoSQL environments, providing a consistent abstraction layer across different storage technologies while still leveraging the native capabilities of each engine.
64
+
65
+ **Key differentiator**: Unlike other query builders that focus on a single database type, DBCube Query Builder provides a unified API that works across SQL and NoSQL databases, making it perfect for modern polyglot architectures.
8
66
 
9
67
  ## Features
10
68
 
11
- - **Fluent API** for building SQL queries
12
- - **Type-safe** query construction
13
- - **Support for SELECT, INSERT, UPDATE, DELETE**
69
+ - **Multi-Database Support**: MySQL, PostgreSQL, SQLite, and MongoDB
70
+ - **Fluent API** for building SQL queries with chainable methods
71
+ - **Type-safe** query construction with TypeScript support
72
+ - **Complete CRUD Operations**: SELECT, INSERT, UPDATE, DELETE
14
73
  - **Advanced WHERE conditions** (AND, OR, groups, BETWEEN, IN, NULL checks)
15
- - **JOINs**: INNER, LEFT, RIGHT
74
+ - **JOIN Support**: INNER, LEFT, RIGHT joins
16
75
  - **Aggregations**: COUNT, SUM, AVG, MAX, MIN
17
- - **Ordering, Grouping, Distinct, Pagination**
18
- - **Column management** (future extension)
76
+ - **Query Modifiers**: ORDER BY, GROUP BY, DISTINCT, LIMIT/OFFSET
77
+ - **Computed Fields**: Dynamic field calculations
78
+ - **Triggers**: Before/after operation hooks
19
79
  - **Promise-based asynchronous API**
20
- - **Singleton connection management**
80
+ - **Connection pooling** through @dbcube/core
81
+ - **Error handling** with descriptive messages
82
+ - **Cross-platform compatibility** (Windows, macOS, Linux)
21
83
 
22
84
  ## Installation
23
85
 
@@ -25,110 +87,1614 @@ It’s designed to work seamlessly in both SQL and NoSQL environments, providing
25
87
  npm install @dbcube/query-builder
26
88
  ```
27
89
 
28
- ## Quick Start
90
+ ## Configuration
91
+
92
+ DBCube Query Builder works with the DBCube ecosystem. Make sure you have the proper database configuration through @dbcube/core.
93
+
94
+ ```typescript
95
+ // No explicit configuration needed - works through DBCube core
96
+ import { Database } from "@dbcube/query-builder";
97
+ ```
98
+
99
+ ## Basic Usage
100
+
101
+ ### Database Connection
102
+
103
+ The connection is automatically managed through the DBCube core system.
29
104
 
30
105
  ```typescript
31
- import Database from "@dbcube/query-builder";
106
+ import { Database } from "@dbcube/query-builder";
32
107
 
108
+ // Create a database instance
33
109
  const db = new Database("my_database");
34
110
 
35
- // Select all users
36
- const users = await db.table("users").get();
111
+ // Get a table reference
112
+ const usersTable = db.table("users");
113
+ ```
37
114
 
38
- // Select users with conditions
39
- const activeUsers = await db
40
- .table("users")
115
+ ## Table Operations
116
+
117
+ DBCube Query Builder focuses on data operations. Table creation and schema management are handled by other DBCube components.
118
+
119
+ ```typescript
120
+ // Access table for operations
121
+ const usersTable = db.table("users");
122
+ ```
123
+
124
+ ## CRUD Operations
125
+
126
+ ### Inserting Data
127
+
128
+ Use the `insert` method to add new records to a table.
129
+
130
+ ```typescript
131
+ // Insert single record
132
+ const newUser = await usersTable.insert([
133
+ { name: "Alice", email: "alice@example.com", age: 28 }
134
+ ]);
135
+
136
+ // Insert multiple records
137
+ const newUsers = await usersTable.insert([
138
+ { name: "Alice", email: "alice@example.com", age: 28 },
139
+ { name: "Bob", email: "bob@example.com", age: 32 },
140
+ { name: "Charlie", email: "charlie@example.com", age: 35 }
141
+ ]);
142
+
143
+ console.log(newUsers);
144
+ // Returns the inserted records with generated IDs
145
+ ```
146
+
147
+ ### Selecting Data
148
+
149
+ Use the `select` method to specify columns and `get()` to retrieve data.
150
+
151
+ ```typescript
152
+ // Select all columns
153
+ const allUsers = await usersTable.get();
154
+
155
+ // Select specific columns
156
+ const users = await usersTable
157
+ .select(["id", "name", "email"])
158
+ .get();
159
+
160
+ // Select with conditions
161
+ const activeUsers = await usersTable
162
+ .select(["name", "email"])
41
163
  .where("status", "=", "active")
42
164
  .orderBy("created_at", "DESC")
43
165
  .limit(10)
44
166
  .get();
45
167
 
46
- // Insert new users
47
- await db
48
- .table("users")
49
- .insert([{ name: "John", email: "john@example.com", age: 30 }]);
168
+ console.log(users);
169
+ // [{ id: 1, name: 'Alice', email: 'alice@example.com' }, ...]
170
+ ```
171
+
172
+ ### Updating Data
173
+
174
+ Use the `update` method to modify existing records. **Requires WHERE conditions**.
175
+
176
+ ```typescript
177
+ // Update single field
178
+ await usersTable
179
+ .where("id", "=", 1)
180
+ .update({ age: 29 });
181
+
182
+ // Update multiple fields
183
+ await usersTable
184
+ .where("email", "=", "alice@example.com")
185
+ .update({
186
+ name: "Alice Smith",
187
+ age: 29,
188
+ updated_at: new Date()
189
+ });
190
+
191
+ // Update with complex conditions
192
+ await usersTable
193
+ .where("age", ">", 30)
194
+ .where("status", "=", "inactive")
195
+ .update({ status: "archived" });
196
+ ```
197
+
198
+ ### Deleting Data
199
+
200
+ Use the `delete` method to remove records. **Requires WHERE conditions**.
201
+
202
+ ```typescript
203
+ // Delete specific record
204
+ await usersTable
205
+ .where("id", "=", 2)
206
+ .delete();
207
+
208
+ // Delete with conditions
209
+ await usersTable
210
+ .where("status", "=", "deleted")
211
+ .where("created_at", "<", "2023-01-01")
212
+ .delete();
213
+ ```
214
+
215
+ ## Advanced Queries
216
+
217
+ ### WHERE Query
218
+
219
+ Filter records using the `where` method with various operators.
220
+
221
+ ```typescript
222
+ // Basic comparisons
223
+ const adultUsers = await usersTable.where("age", ">", 18).get();
224
+ const exactMatch = await usersTable.where("name", "=", "Alice").get();
225
+ const notEqual = await usersTable.where("status", "!=", "deleted").get();
226
+
227
+ // String operations
228
+ const emailUsers = await usersTable.where("email", "LIKE", "%@gmail.com").get();
229
+
230
+ console.log(adultUsers);
231
+ // [{ id: 1, name: 'Alice', age: 28 }, ...]
232
+ ```
233
+
234
+ ### OR WHERE Query
235
+
236
+ Use `orWhere` to add OR conditions to your query.
237
+
238
+ ```typescript
239
+ const users = await usersTable
240
+ .where("age", ">", 25)
241
+ .orWhere("name", "=", "Alice")
242
+ .get();
243
+
244
+ // Complex OR conditions
245
+ const premiumUsers = await usersTable
246
+ .where("subscription", "=", "premium")
247
+ .orWhere("total_purchases", ">", 1000)
248
+ .orWhere("member_since", "<", "2020-01-01")
249
+ .get();
250
+
251
+ console.log(users);
252
+ // [{ id: 1, name: 'Alice', age: 28 }, ...]
253
+ ```
254
+
255
+ ### WHERE Condition Groups
256
+
257
+ Group conditions using `whereGroup` for complex logic.
258
+
259
+ ```typescript
260
+ // (age > 25 OR name = 'Jane') AND status = 'active'
261
+ const users = await usersTable
262
+ .whereGroup((query) => {
263
+ query.where("age", ">", 25).orWhere("name", "=", "Jane");
264
+ })
265
+ .where("status", "=", "active")
266
+ .get();
267
+
268
+ // Nested groups
269
+ const complexQuery = await usersTable
270
+ .whereGroup((query) => {
271
+ query.where("country", "=", "US").orWhere("country", "=", "CA");
272
+ })
273
+ .where("active", "=", true)
274
+ .whereGroup((query) => {
275
+ query.where("age", ">=", 21).orWhere("verified", "=", true);
276
+ })
277
+ .get();
278
+ ```
279
+
280
+ ### BETWEEN Query
281
+
282
+ Search for values within a range using `whereBetween`.
283
+
284
+ ```typescript
285
+ // Age between 25 and 35
286
+ const users = await usersTable.whereBetween("age", [25, 35]).get();
287
+
288
+ // Date ranges
289
+ const recentUsers = await usersTable
290
+ .whereBetween("created_at", ["2024-01-01", "2024-12-31"])
291
+ .get();
292
+
293
+ console.log(users);
294
+ // [{ id: 1, name: 'Alice', age: 28 }, { id: 2, name: 'Bob', age: 32 }]
295
+ ```
296
+
297
+ ### IN Query
298
+
299
+ Search for values that match a set of values using `whereIn`.
300
+
301
+ ```typescript
302
+ // Specific IDs
303
+ const users = await usersTable.whereIn("id", [1, 3, 5]).get();
304
+
305
+ // Multiple statuses
306
+ const filteredUsers = await usersTable
307
+ .whereIn("status", ["active", "pending", "verified"])
308
+ .get();
309
+
310
+ // String values
311
+ const emailDomains = await usersTable
312
+ .whereIn("email_domain", ["gmail.com", "yahoo.com", "hotmail.com"])
313
+ .get();
314
+
315
+ console.log(users);
316
+ // [{ id: 1, name: 'Alice', age: 28 }, { id: 3, name: 'Charlie', age: 35 }]
317
+ ```
318
+
319
+ ### IS NULL / IS NOT NULL Query
320
+
321
+ Search for null or non-null values using `whereNull` and `whereNotNull`.
322
+
323
+ ```typescript
324
+ // Users without email
325
+ const usersWithoutEmail = await usersTable.whereNull("email").get();
326
+
327
+ // Users with email
328
+ const usersWithEmail = await usersTable.whereNotNull("email").get();
329
+
330
+ // Combine with other conditions
331
+ const incompleteProfiles = await usersTable
332
+ .whereNull("phone")
333
+ .orWhere("avatar", "IS NULL")
334
+ .whereNotNull("email")
335
+ .get();
336
+ ```
337
+
338
+ ### JOIN Query
339
+
340
+ Join tables using the `join` method for INNER JOIN.
341
+
342
+ ```typescript
343
+ // Basic INNER JOIN
344
+ const usersWithOrders = await usersTable
345
+ .join("orders", "users.id", "=", "orders.user_id")
346
+ .select(["users.name", "orders.order_id", "orders.total"])
347
+ .get();
348
+
349
+ // Multiple JOINs
350
+ const detailedOrders = await usersTable
351
+ .join("orders", "users.id", "=", "orders.user_id")
352
+ .join("order_items", "orders.id", "=", "order_items.order_id")
353
+ .join("products", "order_items.product_id", "=", "products.id")
354
+ .select(["users.name", "orders.order_id", "products.name AS product_name"])
355
+ .get();
356
+
357
+ console.log(usersWithOrders);
358
+ // [{ name: 'Alice', order_id: 101, total: 150.00 }, ...]
359
+ ```
360
+
361
+ ### LEFT JOIN Query
362
+
363
+ Perform a left join using the `leftJoin` method.
364
+
365
+ ```typescript
366
+ // Include users even if they have no orders
367
+ const usersWithOrders = await usersTable
368
+ .leftJoin("orders", "users.id", "=", "orders.user_id")
369
+ .select(["users.name", "orders.order_id"])
370
+ .get();
371
+
372
+ // Left join with aggregation
373
+ const usersOrderCount = await usersTable
374
+ .leftJoin("orders", "users.id", "=", "orders.user_id")
375
+ .select(["users.name"])
376
+ .count("orders.id")
377
+ .groupBy("users.id")
378
+ .get();
379
+
380
+ console.log(usersWithOrders);
381
+ // [{ name: 'Alice', order_id: 101 }, { name: 'Bob', order_id: null }, ...]
382
+ ```
383
+
384
+ ### RIGHT JOIN Query
385
+
386
+ Perform a right join using the `rightJoin` method.
387
+
388
+ ```typescript
389
+ // Include orders even if user data is missing
390
+ const ordersWithUsers = await usersTable
391
+ .rightJoin("orders", "users.id", "=", "orders.user_id")
392
+ .select(["users.name", "orders.order_id"])
393
+ .get();
394
+
395
+ console.log(ordersWithUsers);
396
+ // [{ name: 'Alice', order_id: 101 }, { name: null, order_id: 102 }, ...]
397
+ ```
398
+
399
+ ### ORDER BY Query
50
400
 
51
- // Update a user
52
- await db.table("users").where("id", "=", 1).update({ status: "inactive" });
401
+ Sort results using the `orderBy` method.
53
402
 
54
- // Delete users
55
- await db.table("users").where("status", "=", "deleted").delete();
403
+ ```typescript
404
+ // Single column sorting
405
+ const sortedUsers = await usersTable
406
+ .orderBy("name", "ASC")
407
+ .get();
408
+
409
+ // Multiple column sorting
410
+ const complexSort = await usersTable
411
+ .orderBy("country", "ASC")
412
+ .orderBy("age", "DESC")
413
+ .orderBy("name", "ASC")
414
+ .get();
415
+
416
+ // Sort with conditions
417
+ const recentActiveUsers = await usersTable
418
+ .where("status", "=", "active")
419
+ .orderBy("last_login", "DESC")
420
+ .limit(20)
421
+ .get();
422
+
423
+ console.log(sortedUsers);
424
+ // [{ id: 1, name: 'Alice', ... }, { id: 2, name: 'Bob', ... }]
425
+ ```
426
+
427
+ ### LIMIT and OFFSET Query (Pagination)
428
+
429
+ Limit the number of results and implement pagination using `limit` and `page`.
430
+
431
+ ```typescript
432
+ // Simple limit
433
+ const firstTenUsers = await usersTable.limit(10).get();
434
+
435
+ // Pagination
436
+ const firstPage = await usersTable.limit(5).page(1).get();
437
+ const secondPage = await usersTable.limit(5).page(2).get();
438
+
439
+ // Pagination with sorting
440
+ const paginatedUsers = await usersTable
441
+ .orderBy("created_at", "DESC")
442
+ .limit(10)
443
+ .page(3) // Skip first 20 records (pages 1-2)
444
+ .get();
445
+
446
+ console.log(firstPage); // Records 1-5
447
+ console.log(secondPage); // Records 6-10
448
+ ```
449
+
450
+ ### GROUP BY Query
451
+
452
+ Group results using the `groupBy` method.
453
+
454
+ ```typescript
455
+ // Simple grouping
456
+ const usersByAge = await usersTable
457
+ .select(["age"])
458
+ .count("*")
459
+ .groupBy("age")
460
+ .get();
461
+
462
+ // Multiple grouping columns
463
+ const usersByCountryAndAge = await usersTable
464
+ .select(["country", "age"])
465
+ .count("*")
466
+ .groupBy("country")
467
+ .groupBy("age")
468
+ .get();
469
+
470
+ console.log(usersByAge);
471
+ // [{ age: 28, count: 2 }, { age: 32, count: 1 }]
472
+ ```
473
+
474
+ ### DISTINCT Query
475
+
476
+ Retrieve unique records using the `distinct` method.
477
+
478
+ ```typescript
479
+ // Distinct values
480
+ const uniqueCountries = await usersTable
481
+ .distinct()
482
+ .select(["country"])
483
+ .get();
484
+
485
+ // Distinct with conditions
486
+ const activeUserCountries = await usersTable
487
+ .distinct()
488
+ .select(["country"])
489
+ .where("status", "=", "active")
490
+ .get();
491
+
492
+ console.log(uniqueCountries);
493
+ // [{ country: 'USA' }, { country: 'Canada' }, { country: 'UK' }]
494
+ ```
495
+
496
+ ## Aggregate Functions
497
+
498
+ ### count
499
+
500
+ Count the number of records.
501
+
502
+ ```typescript
503
+ // Count all records
504
+ const totalUsers = await usersTable.count().first();
505
+ console.log(totalUsers); // { count: 150 }
506
+
507
+ // Count specific column
508
+ const usersWithEmail = await usersTable.count("email").first();
509
+
510
+ // Count with conditions
511
+ const activeUsers = await usersTable
512
+ .where("status", "=", "active")
513
+ .count()
514
+ .first();
515
+ ```
516
+
517
+ ### sum
518
+
519
+ Calculate the sum of a column.
520
+
521
+ ```typescript
522
+ // Sum of ages
523
+ const totalAge = await usersTable.sum("age").first();
524
+ console.log(totalAge); // { sum: 4250 }
525
+
526
+ // Sum with conditions
527
+ const premiumRevenue = await usersTable
528
+ .join("orders", "users.id", "=", "orders.user_id")
529
+ .where("users.subscription", "=", "premium")
530
+ .sum("orders.total")
531
+ .first();
532
+ ```
533
+
534
+ ### avg
535
+
536
+ Calculate the average of a column.
537
+
538
+ ```typescript
539
+ // Average age
540
+ const averageAge = await usersTable.avg("age").first();
541
+ console.log(averageAge); // { avg: 28.33 }
542
+
543
+ // Average with grouping
544
+ const avgAgeByCountry = await usersTable
545
+ .select(["country"])
546
+ .avg("age")
547
+ .groupBy("country")
548
+ .get();
549
+ ```
550
+
551
+ ### max
552
+
553
+ Find the maximum value in a column.
554
+
555
+ ```typescript
556
+ // Oldest user
557
+ const maxAge = await usersTable.max("age").first();
558
+ console.log(maxAge); // { max: 65 }
559
+
560
+ // Most recent registration
561
+ const latestUser = await usersTable.max("created_at").first();
562
+ ```
563
+
564
+ ### min
565
+
566
+ Find the minimum value in a column.
567
+
568
+ ```typescript
569
+ // Youngest user
570
+ const minAge = await usersTable.min("age").first();
571
+ console.log(minAge); // { min: 18 }
572
+
573
+ // Earliest registration
574
+ const firstUser = await usersTable.min("created_at").first();
575
+ ```
576
+
577
+ ## Finding Records
578
+
579
+ ### find
580
+
581
+ Find a record by a specific column value (defaults to 'id').
582
+
583
+ ```typescript
584
+ // Find by ID (default)
585
+ const user = await usersTable.find(1);
586
+ console.log(user);
587
+ // { id: 1, name: 'Alice', email: 'alice@example.com', age: 28 }
588
+
589
+ // Find by specific column
590
+ const userByEmail = await usersTable.find("alice@example.com", "email");
591
+
592
+ // Find returns null if not found
593
+ const nonExistent = await usersTable.find(999);
594
+ console.log(nonExistent); // null
595
+ ```
596
+
597
+ ### first
598
+
599
+ Get only the first record that meets the conditions.
600
+
601
+ ```typescript
602
+ // First user matching condition
603
+ const firstUser = await usersTable
604
+ .where("age", ">", 25)
605
+ .orderBy("created_at", "ASC")
606
+ .first();
607
+
608
+ // First user in general
609
+ const oldestAccount = await usersTable
610
+ .orderBy("created_at", "ASC")
611
+ .first();
612
+
613
+ console.log(firstUser);
614
+ // { id: 1, name: 'Alice', age: 28, ... } or null if no match
615
+ ```
616
+
617
+ ## Computed Fields and Triggers
618
+
619
+ DBCube Query Builder supports computed fields and triggers for advanced data processing.
620
+
621
+ ```typescript
622
+ // Enable computed fields (processed automatically)
623
+ await db.useComputes();
624
+
625
+ // Enable triggers
626
+ await db.useTriggers();
627
+
628
+ // Triggers and computed fields are configured through other DBCube components
629
+ ```
630
+
631
+ ## Executing Raw SQL Queries
632
+
633
+ For complex queries that require raw SQL, use the underlying engine.
634
+
635
+ ```typescript
636
+ // Access the underlying engine for raw queries
637
+ // (Implementation depends on your specific DBCube core setup)
638
+
639
+ // Note: Raw SQL queries bypass the query builder's abstraction layer
640
+ // and are database-specific
641
+ ```
642
+
643
+ ### Error Handling
644
+
645
+ The library provides comprehensive error handling with descriptive messages.
646
+
647
+ ```typescript
648
+ try {
649
+ // This will throw an error - UPDATE requires WHERE conditions
650
+ await usersTable.update({ name: "Updated" });
651
+ } catch (error) {
652
+ console.error(error.message);
653
+ // "You must specify at least one WHERE condition to perform an update."
654
+ }
655
+
656
+ try {
657
+ // This will throw an error - invalid data format
658
+ await usersTable.insert("invalid data");
659
+ } catch (error) {
660
+ console.error(error.message);
661
+ // "The insert method requires an array of objects with key-value pairs."
662
+ }
663
+
664
+ // Connection and database errors are also properly handled
665
+ try {
666
+ const result = await usersTable.get();
667
+ } catch (error) {
668
+ // Database connection or query execution errors
669
+ console.error("Database error:", error);
670
+ }
56
671
  ```
57
672
 
58
- ## API Documentation
673
+ ## Complete API
59
674
 
60
- ### Database
675
+ ### Database Class
61
676
 
62
677
  #### `new Database(name: string)`
63
678
 
64
679
  Creates a new database connection instance.
65
680
 
681
+ ```typescript
682
+ const db = new Database("my_database");
683
+ ```
684
+
66
685
  #### `table(tableName: string): Table`
67
686
 
68
687
  Returns a Table instance for building queries on the specified table.
69
688
 
70
- ### Table
71
-
72
- #### Query Methods
73
-
74
- - `select(fields?: string[])`: Specify columns to select.
75
- - `where(column, operator, value)`: Add a WHERE condition.
76
- - `orWhere(column, operator, value)`: Add an OR WHERE condition.
77
- - `whereGroup(callback)`: Grouped WHERE conditions.
78
- - `whereBetween(column, [min, max])`: WHERE BETWEEN condition.
79
- - `whereIn(column, values)`: WHERE IN condition.
80
- - `whereNull(column)`: WHERE IS NULL condition.
81
- - `whereNotNull(column)`: WHERE IS NOT NULL condition.
82
- - `join(table, column1, operator, column2)`: INNER JOIN.
83
- - `leftJoin(table, column1, operator, column2)`: LEFT JOIN.
84
- - `rightJoin(table, column1, operator, column2)`: RIGHT JOIN.
85
- - `orderBy(column, direction)`: ORDER BY clause.
86
- - `groupBy(column)`: GROUP BY clause.
87
- - `distinct()`: DISTINCT clause.
88
- - `count(column?)`: COUNT aggregation.
89
- - `sum(column)`: SUM aggregation.
90
- - `avg(column)`: AVG aggregation.
91
- - `max(column)`: MAX aggregation.
92
- - `min(column)`: MIN aggregation.
93
- - `limit(number)`: LIMIT clause.
94
- - `page(number)`: Pagination (requires limit).
689
+ ```typescript
690
+ const usersTable = db.table("users");
691
+ ```
95
692
 
96
- #### Execution Methods
693
+ #### `useComputes(): Promise<void>`
694
+
695
+ Enables computed fields processing for the database.
97
696
 
98
- - `get()`: Execute and return all matching rows.
99
- - `first()`: Execute and return the first matching row.
100
- - `find(value, column?)`: Find a row by column value (default: id).
101
- - `insert(data)`: Insert one or more rows.
102
- - `update(data)`: Update rows matching the conditions.
103
- - `delete()`: Delete rows matching the conditions.
697
+ ```typescript
698
+ await db.useComputes();
699
+ ```
104
700
 
105
- ## Example Usage
701
+ #### `useTriggers(): Promise<void>`
702
+
703
+ Enables trigger processing for the database.
106
704
 
107
705
  ```typescript
108
- // Complex query with joins, grouping, and aggregation
109
- const results = await db
110
- .table("orders")
111
- .join("users", "orders.user_id", "=", "users.id")
112
- .where("orders.status", "=", "completed")
113
- .groupBy("users.country")
114
- .sum("orders.total")
115
- .orderBy("sum", "DESC")
116
- .limit(5)
117
- .get();
706
+ await db.useTriggers();
118
707
  ```
119
708
 
120
- ## Error Handling
709
+ #### `connect(): Promise<void>`
121
710
 
122
- All methods throw descriptive errors for invalid usage, such as missing WHERE conditions on update/delete, or invalid data types.
711
+ Establishes database connection (handled automatically).
123
712
 
124
- ## License
713
+ #### `disconnect(): Promise<void>`
714
+
715
+ Closes database connection.
716
+
717
+ ### Table Class
125
718
 
126
- This project is licensed under the MIT License.
719
+ #### Query Building Methods
127
720
 
128
- ## Contributing
721
+ **`select(fields?: string[]): Table`**
722
+ Specify columns to select.
129
723
 
130
- Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
724
+ ```typescript
725
+ usersTable.select(["id", "name", "email"]);
726
+ ```
727
+
728
+ **`where(column, operator, value): Table`**
729
+ Add a WHERE condition.
730
+
731
+ ```typescript
732
+ usersTable.where("age", ">", 25);
733
+ usersTable.where("email", "IS NOT NULL");
734
+ ```
735
+
736
+ **`orWhere(column, operator, value): Table`**
737
+ Add an OR WHERE condition.
738
+
739
+ ```typescript
740
+ usersTable.orWhere("name", "=", "Jane");
741
+ ```
742
+
743
+ **`whereGroup(callback): Table`**
744
+ Grouped WHERE conditions.
745
+
746
+ ```typescript
747
+ usersTable.whereGroup((query) => {
748
+ query.where("age", ">", 25).orWhere("name", "=", "Jane");
749
+ });
750
+ ```
751
+
752
+ **`whereBetween(column, [min, max]): Table`**
753
+ WHERE BETWEEN condition.
754
+
755
+ ```typescript
756
+ usersTable.whereBetween("age", [25, 35]);
757
+ ```
758
+
759
+ **`whereIn(column, values): Table`**
760
+ WHERE IN condition.
761
+
762
+ ```typescript
763
+ usersTable.whereIn("id", [1, 3, 5]);
764
+ ```
765
+
766
+ **`whereNull(column): Table`** / **`whereNotNull(column): Table`**
767
+ NULL checks.
768
+
769
+ ```typescript
770
+ usersTable.whereNull("deleted_at");
771
+ usersTable.whereNotNull("email");
772
+ ```
773
+
774
+ **`join(table, column1, operator, column2): Table`**
775
+ INNER JOIN.
776
+
777
+ ```typescript
778
+ usersTable.join("orders", "users.id", "=", "orders.user_id");
779
+ ```
780
+
781
+ **`leftJoin(table, column1, operator, column2): Table`**
782
+ LEFT JOIN.
783
+
784
+ **`rightJoin(table, column1, operator, column2): Table`**
785
+ RIGHT JOIN.
786
+
787
+ **`orderBy(column, direction): Table`**
788
+ ORDER BY clause.
789
+
790
+ ```typescript
791
+ usersTable.orderBy("name", "ASC");
792
+ ```
793
+
794
+ **`groupBy(column): Table`**
795
+ GROUP BY clause.
796
+
797
+ **`distinct(): Table`**
798
+ DISTINCT clause.
799
+
800
+ **`limit(number): Table`**
801
+ LIMIT clause.
802
+
803
+ **`page(number): Table`**
804
+ Pagination (requires limit).
805
+
806
+ #### Aggregation Methods
807
+
808
+ **`count(column?): Table`**
809
+ COUNT aggregation.
810
+
811
+ **`sum(column): Table`**
812
+ SUM aggregation.
813
+
814
+ **`avg(column): Table`**
815
+ AVG aggregation.
816
+
817
+ **`max(column): Table`**
818
+ MAX aggregation.
819
+
820
+ **`min(column): Table`**
821
+ MIN aggregation.
822
+
823
+ #### Execution Methods
824
+
825
+ **`get(): Promise<DatabaseRecord[]>`**
826
+ Execute and return all matching rows.
827
+
828
+ **`first(): Promise<DatabaseRecord | null>`**
829
+ Execute and return the first matching row.
830
+
831
+ **`find(value, column?): Promise<DatabaseRecord | null>`**
832
+ Find a row by column value (default: id).
833
+
834
+ **`insert(data): Promise<DatabaseRecord[]>`**
835
+ Insert one or more rows.
836
+
837
+ **`update(data): Promise<any>`**
838
+ Update rows matching the conditions.
839
+
840
+ **`delete(): Promise<any>`**
841
+ Delete rows matching the conditions.
842
+
843
+ ## Multi-Database Support
844
+
845
+ DBCube Query Builder works with multiple database engines:
846
+
847
+ ```typescript
848
+ // MySQL
849
+ const mysqlDb = new Database("mysql_database");
850
+
851
+ // PostgreSQL
852
+ const postgresDb = new Database("postgres_database");
853
+
854
+ // SQLite
855
+ const sqliteDb = new Database("sqlite_database");
856
+
857
+ // MongoDB
858
+ const mongoDb = new Database("mongo_database");
859
+
860
+ // Same API works across all databases
861
+ const users = await mysqlDb.table("users").get();
862
+ const posts = await postgresDb.table("posts").get();
863
+ const logs = await sqliteDb.table("logs").get();
864
+ const analytics = await mongoDb.table("analytics").get();
865
+ ```
866
+
867
+ ## Advanced Features
868
+
869
+ ### Complex Query Example
870
+
871
+ ```typescript
872
+ // Complex business query
873
+ const monthlyReport = await db.table("orders")
874
+ .join("users", "orders.user_id", "=", "users.id")
875
+ .join("order_items", "orders.id", "=", "order_items.order_id")
876
+ .join("products", "order_items.product_id", "=", "products.id")
877
+ .select([
878
+ "users.country",
879
+ "products.category"
880
+ ])
881
+ .sum("order_items.quantity * order_items.price")
882
+ .where("orders.status", "=", "completed")
883
+ .whereBetween("orders.created_at", ["2024-01-01", "2024-01-31"])
884
+ .groupBy("users.country")
885
+ .groupBy("products.category")
886
+ .orderBy("sum", "DESC")
887
+ .limit(10)
888
+ .get();
889
+ ```
890
+
891
+ ### Method Chaining
892
+
893
+ All query builder methods return the Table instance, enabling fluent method chaining:
894
+
895
+ ```typescript
896
+ const result = await db
897
+ .table("users")
898
+ .select(["name", "email", "country"])
899
+ .where("active", "=", true)
900
+ .whereNotNull("email_verified_at")
901
+ .whereGroup((query) => {
902
+ query.where("subscription", "=", "premium")
903
+ .orWhere("total_orders", ">", 10);
904
+ })
905
+ .join("user_profiles", "users.id", "=", "user_profiles.user_id")
906
+ .orderBy("users.created_at", "DESC")
907
+ .limit(50)
908
+ .page(1)
909
+ .get();
910
+ ```
911
+
912
+ ## License
913
+
914
+ This project is licensed under the MIT License - see the LICENSE file for details.
915
+
916
+ ---
917
+
918
+ ## Documentación en español
919
+
920
+ ## Tabla de contenidos 🚀
921
+
922
+ - [Introducción](#introducción)
923
+ - [Características](#características-1)
924
+ - [Instalación](#instalación-1)
925
+ - [Configuración](#configuración-1)
926
+ - [Uso básico](#uso-básico)
927
+ - [Conexión a la base de datos](#conexión-a-la-base-de-datos)
928
+ - [Operaciones de tabla](#operaciones-de-tabla)
929
+ - [Operaciones CRUD](#operaciones-crud-1)
930
+ - [Insertar datos](#insertar-datos)
931
+ - [Seleccionar datos](#seleccionar-datos)
932
+ - [Actualizar datos](#actualizar-datos)
933
+ - [Eliminar datos](#eliminar-datos)
934
+ - [Consultas avanzadas](#consultas-avanzadas-1)
935
+ - [Consulta con WHERE](#consulta-con-where)
936
+ - [Consulta con OR WHERE](#consulta-con-or-where)
937
+ - [Consulta con grupos de condiciones WHERE](#consulta-con-grupos-de-condiciones-where)
938
+ - [Consulta con BETWEEN](#consulta-con-between)
939
+ - [Consulta con IN](#consulta-con-in)
940
+ - [Consulta con IS NULL / IS NOT NULL](#consulta-con-is-null--is-not-null)
941
+ - [Consulta con JOIN](#consulta-con-join)
942
+ - [Consulta con LEFT JOIN](#consulta-con-left-join)
943
+ - [Consulta con RIGHT JOIN](#consulta-con-right-join)
944
+ - [Consulta con ORDER BY](#consulta-con-order-by)
945
+ - [Consulta con LIMIT y OFFSET](#consulta-con-limit-y-offset-paginación)
946
+ - [Consulta con GROUP BY](#consulta-con-group-by)
947
+ - [Consulta con DISTINCT](#consulta-con-distinct)
948
+ - [Funciones de agregación](#funciones-de-agregación-1)
949
+ - [count](#count-1)
950
+ - [sum](#sum-1)
951
+ - [avg](#avg-1)
952
+ - [max](#max-1)
953
+ - [min](#min-1)
954
+ - [Buscar registros](#buscar-registros)
955
+ - [find](#find-1)
956
+ - [first](#first-1)
957
+ - [Campos calculados y triggers](#campos-calculados-y-triggers)
958
+ - [Ejecutar consultas SQL crudas](#ejecutar-consultas-sql-crudas)
959
+ - [Manejo de errores](#manejo-de-errores)
960
+ - [API completa](#api-completa-1)
961
+ - [Clase Database](#clase-database)
962
+ - [Clase Table](#clase-table)
963
+ - [Soporte multi-base de datos](#soporte-multi-base-de-datos)
964
+ - [Características avanzadas](#características-avanzadas)
965
+ - [Licencia](#licencia)
966
+
967
+ ## Introducción
968
+
969
+ `@dbcube/query-builder` es una biblioteca de Node.js ligera, flexible y fluida diseñada para construir consultas a través de múltiples motores de base de datos, incluyendo MySQL, PostgreSQL, SQLite y MongoDB, usando JavaScript/TypeScript.
970
+
971
+ Su diseño agnóstico te permite generar operaciones de manipulación de datos (DML) y definición de datos (DDL) con una sintaxis limpia y encadenable, sin sacrificar potencia o expresividad. Está diseñada para trabajar perfectamente en entornos SQL y NoSQL, proporcionando una capa de abstracción consistente a través de diferentes tecnologías de almacenamiento mientras aprovecha las capacidades nativas de cada motor.
972
+
973
+ **Diferenciador clave**: A diferencia de otros constructores de consultas que se enfocan en un solo tipo de base de datos, DBCube Query Builder proporciona una API unificada que funciona a través de bases de datos SQL y NoSQL, haciéndola perfecta para arquitecturas políglotas modernas.
974
+
975
+ ## Características
976
+
977
+ - **Soporte multi-base de datos**: MySQL, PostgreSQL, SQLite y MongoDB
978
+ - **API fluida** para construir consultas SQL con métodos encadenables
979
+ - **Construcción de consultas type-safe** con soporte TypeScript
980
+ - **Operaciones CRUD completas**: SELECT, INSERT, UPDATE, DELETE
981
+ - **Condiciones WHERE avanzadas** (AND, OR, grupos, BETWEEN, IN, verificaciones NULL)
982
+ - **Soporte JOIN**: INNER, LEFT, RIGHT joins
983
+ - **Agregaciones**: COUNT, SUM, AVG, MAX, MIN
984
+ - **Modificadores de consulta**: ORDER BY, GROUP BY, DISTINCT, LIMIT/OFFSET
985
+ - **Campos calculados**: Cálculos dinámicos de campos
986
+ - **Triggers**: Hooks antes/después de operaciones
987
+ - **API asíncrona basada en promesas**
988
+ - **Connection pooling** a través de @dbcube/core
989
+ - **Manejo de errores** con mensajes descriptivos
990
+ - **Compatibilidad multiplataforma** (Windows, macOS, Linux)
991
+
992
+ ## Instalación
993
+
994
+ ```bash
995
+ npm install @dbcube/query-builder
996
+ ```
997
+
998
+ ## Configuración
999
+
1000
+ DBCube Query Builder funciona con el ecosistema DBCube. Asegúrate de tener la configuración adecuada de base de datos a través de @dbcube/core.
1001
+
1002
+ ```typescript
1003
+ // No se necesita configuración explícita - funciona a través de DBCube core
1004
+ import { Database } from "@dbcube/query-builder";
1005
+ ```
1006
+
1007
+ ## Uso básico
1008
+
1009
+ ### Conexión a la base de datos
1010
+
1011
+ La conexión se gestiona automáticamente a través del sistema core de DBCube.
1012
+
1013
+ ```typescript
1014
+ import { Database } from "@dbcube/query-builder";
1015
+
1016
+ // Crear una instancia de base de datos
1017
+ const db = new Database("mi_base_de_datos");
1018
+
1019
+ // Obtener una referencia de tabla
1020
+ const tablaUsuarios = db.table("usuarios");
1021
+ ```
1022
+
1023
+ ## Operaciones de tabla
1024
+
1025
+ DBCube Query Builder se enfoca en operaciones de datos. La creación de tablas y gestión de esquemas se maneja por otros componentes de DBCube.
1026
+
1027
+ ```typescript
1028
+ // Acceder a tabla para operaciones
1029
+ const tablaUsuarios = db.table("usuarios");
1030
+ ```
1031
+
1032
+ ## Operaciones CRUD
1033
+
1034
+ ### Insertar datos
1035
+
1036
+ Utiliza el método `insert` para añadir nuevos registros a una tabla.
1037
+
1038
+ ```typescript
1039
+ // Insertar un solo registro
1040
+ const nuevoUsuario = await tablaUsuarios.insert([
1041
+ { nombre: "Alicia", email: "alicia@ejemplo.com", edad: 28 }
1042
+ ]);
1043
+
1044
+ // Insertar múltiples registros
1045
+ const nuevosUsuarios = await tablaUsuarios.insert([
1046
+ { nombre: "Alicia", email: "alicia@ejemplo.com", edad: 28 },
1047
+ { nombre: "Roberto", email: "roberto@ejemplo.com", edad: 32 },
1048
+ { nombre: "Carlos", email: "carlos@ejemplo.com", edad: 35 }
1049
+ ]);
1050
+
1051
+ console.log(nuevosUsuarios);
1052
+ // Devuelve los registros insertados con IDs generados
1053
+ ```
1054
+
1055
+ ### Seleccionar datos
1056
+
1057
+ Utiliza el método `select` para especificar columnas y `get()` para recuperar datos.
1058
+
1059
+ ```typescript
1060
+ // Seleccionar todas las columnas
1061
+ const todosUsuarios = await tablaUsuarios.get();
1062
+
1063
+ // Seleccionar columnas específicas
1064
+ const usuarios = await tablaUsuarios
1065
+ .select(["id", "nombre", "email"])
1066
+ .get();
1067
+
1068
+ // Seleccionar con condiciones
1069
+ const usuariosActivos = await tablaUsuarios
1070
+ .select(["nombre", "email"])
1071
+ .where("estado", "=", "activo")
1072
+ .orderBy("fecha_creacion", "DESC")
1073
+ .limit(10)
1074
+ .get();
1075
+
1076
+ console.log(usuarios);
1077
+ // [{ id: 1, nombre: 'Alicia', email: 'alicia@ejemplo.com' }, ...]
1078
+ ```
1079
+
1080
+ ### Actualizar datos
1081
+
1082
+ Utiliza el método `update` para modificar registros existentes. **Requiere condiciones WHERE**.
1083
+
1084
+ ```typescript
1085
+ // Actualizar un campo
1086
+ await tablaUsuarios
1087
+ .where("id", "=", 1)
1088
+ .update({ edad: 29 });
1089
+
1090
+ // Actualizar múltiples campos
1091
+ await tablaUsuarios
1092
+ .where("email", "=", "alicia@ejemplo.com")
1093
+ .update({
1094
+ nombre: "Alicia García",
1095
+ edad: 29,
1096
+ actualizado_en: new Date()
1097
+ });
1098
+
1099
+ // Actualizar con condiciones complejas
1100
+ await tablaUsuarios
1101
+ .where("edad", ">", 30)
1102
+ .where("estado", "=", "inactivo")
1103
+ .update({ estado: "archivado" });
1104
+ ```
1105
+
1106
+ ### Eliminar datos
1107
+
1108
+ Utiliza el método `delete` para eliminar registros. **Requiere condiciones WHERE**.
1109
+
1110
+ ```typescript
1111
+ // Eliminar registro específico
1112
+ await tablaUsuarios
1113
+ .where("id", "=", 2)
1114
+ .delete();
1115
+
1116
+ // Eliminar con condiciones
1117
+ await tablaUsuarios
1118
+ .where("estado", "=", "eliminado")
1119
+ .where("fecha_creacion", "<", "2023-01-01")
1120
+ .delete();
1121
+ ```
1122
+
1123
+ ## Consultas avanzadas
1124
+
1125
+ ### Consulta con WHERE
1126
+
1127
+ Filtra registros utilizando el método `where` con varios operadores.
1128
+
1129
+ ```typescript
1130
+ // Comparaciones básicas
1131
+ const usuariosAdultos = await tablaUsuarios.where("edad", ">", 18).get();
1132
+ const coincidenciaExacta = await tablaUsuarios.where("nombre", "=", "Alicia").get();
1133
+ const noIgual = await tablaUsuarios.where("estado", "!=", "eliminado").get();
1134
+
1135
+ // Operaciones con strings
1136
+ const usuariosGmail = await tablaUsuarios.where("email", "LIKE", "%@gmail.com").get();
1137
+
1138
+ console.log(usuariosAdultos);
1139
+ // [{ id: 1, nombre: 'Alicia', edad: 28 }, ...]
1140
+ ```
1141
+
1142
+ ### Consulta con OR WHERE
1143
+
1144
+ Utiliza `orWhere` para añadir condiciones OR a tu consulta.
1145
+
1146
+ ```typescript
1147
+ const usuarios = await tablaUsuarios
1148
+ .where("edad", ">", 25)
1149
+ .orWhere("nombre", "=", "Alicia")
1150
+ .get();
1151
+
1152
+ // Condiciones OR complejas
1153
+ const usuariosPremium = await tablaUsuarios
1154
+ .where("suscripcion", "=", "premium")
1155
+ .orWhere("compras_totales", ">", 1000)
1156
+ .orWhere("miembro_desde", "<", "2020-01-01")
1157
+ .get();
1158
+
1159
+ console.log(usuarios);
1160
+ // [{ id: 1, nombre: 'Alicia', edad: 28 }, ...]
1161
+ ```
1162
+
1163
+ ### Consulta con grupos de condiciones WHERE
1164
+
1165
+ Agrupa condiciones utilizando `whereGroup` para lógica compleja.
1166
+
1167
+ ```typescript
1168
+ // (edad > 25 OR nombre = 'Juana') AND estado = 'activo'
1169
+ const usuarios = await tablaUsuarios
1170
+ .whereGroup((query) => {
1171
+ query.where("edad", ">", 25).orWhere("nombre", "=", "Juana");
1172
+ })
1173
+ .where("estado", "=", "activo")
1174
+ .get();
1175
+
1176
+ // Grupos anidados
1177
+ const consultaCompleja = await tablaUsuarios
1178
+ .whereGroup((query) => {
1179
+ query.where("pais", "=", "ES").orWhere("pais", "=", "MX");
1180
+ })
1181
+ .where("activo", "=", true)
1182
+ .whereGroup((query) => {
1183
+ query.where("edad", ">=", 21).orWhere("verificado", "=", true);
1184
+ })
1185
+ .get();
1186
+ ```
1187
+
1188
+ ### Consulta con BETWEEN
1189
+
1190
+ Busca valores dentro de un rango utilizando `whereBetween`.
1191
+
1192
+ ```typescript
1193
+ // Edad entre 25 y 35
1194
+ const usuarios = await tablaUsuarios.whereBetween("edad", [25, 35]).get();
1195
+
1196
+ // Rangos de fechas
1197
+ const usuariosRecientes = await tablaUsuarios
1198
+ .whereBetween("fecha_creacion", ["2024-01-01", "2024-12-31"])
1199
+ .get();
1200
+
1201
+ console.log(usuarios);
1202
+ // [{ id: 1, nombre: 'Alicia', edad: 28 }, { id: 2, nombre: 'Roberto', edad: 32 }]
1203
+ ```
1204
+
1205
+ ### Consulta con IN
1206
+
1207
+ Busca valores que coincidan con un conjunto de valores utilizando `whereIn`.
1208
+
1209
+ ```typescript
1210
+ // IDs específicos
1211
+ const usuarios = await tablaUsuarios.whereIn("id", [1, 3, 5]).get();
1212
+
1213
+ // Múltiples estados
1214
+ const usuariosFiltrados = await tablaUsuarios
1215
+ .whereIn("estado", ["activo", "pendiente", "verificado"])
1216
+ .get();
1217
+
1218
+ // Valores string
1219
+ const dominiosEmail = await tablaUsuarios
1220
+ .whereIn("dominio_email", ["gmail.com", "yahoo.com", "hotmail.com"])
1221
+ .get();
1222
+
1223
+ console.log(usuarios);
1224
+ // [{ id: 1, nombre: 'Alicia', edad: 28 }, { id: 3, nombre: 'Carlos', edad: 35 }]
1225
+ ```
1226
+
1227
+ ### Consulta con IS NULL / IS NOT NULL
1228
+
1229
+ Busca valores nulos o no nulos utilizando `whereNull` y `whereNotNull`.
1230
+
1231
+ ```typescript
1232
+ // Usuarios sin email
1233
+ const usuariosSinEmail = await tablaUsuarios.whereNull("email").get();
1234
+
1235
+ // Usuarios con email
1236
+ const usuariosConEmail = await tablaUsuarios.whereNotNull("email").get();
1237
+
1238
+ // Combinar con otras condiciones
1239
+ const perfilesIncompletos = await tablaUsuarios
1240
+ .whereNull("telefono")
1241
+ .orWhere("avatar", "IS NULL")
1242
+ .whereNotNull("email")
1243
+ .get();
1244
+ ```
1245
+
1246
+ ### Consulta con JOIN
1247
+
1248
+ Une tablas utilizando el método `join` para INNER JOIN.
1249
+
1250
+ ```typescript
1251
+ // INNER JOIN básico
1252
+ const usuariosConPedidos = await tablaUsuarios
1253
+ .join("pedidos", "usuarios.id", "=", "pedidos.usuario_id")
1254
+ .select(["usuarios.nombre", "pedidos.pedido_id", "pedidos.total"])
1255
+ .get();
1256
+
1257
+ // Múltiples JOINs
1258
+ const pedidosDetallados = await tablaUsuarios
1259
+ .join("pedidos", "usuarios.id", "=", "pedidos.usuario_id")
1260
+ .join("items_pedido", "pedidos.id", "=", "items_pedido.pedido_id")
1261
+ .join("productos", "items_pedido.producto_id", "=", "productos.id")
1262
+ .select(["usuarios.nombre", "pedidos.pedido_id", "productos.nombre AS nombre_producto"])
1263
+ .get();
1264
+
1265
+ console.log(usuariosConPedidos);
1266
+ // [{ nombre: 'Alicia', pedido_id: 101, total: 150.00 }, ...]
1267
+ ```
1268
+
1269
+ ### Consulta con LEFT JOIN
1270
+
1271
+ Realiza un left join utilizando el método `leftJoin`.
1272
+
1273
+ ```typescript
1274
+ // Incluir usuarios aunque no tengan pedidos
1275
+ const usuariosConPedidos = await tablaUsuarios
1276
+ .leftJoin("pedidos", "usuarios.id", "=", "pedidos.usuario_id")
1277
+ .select(["usuarios.nombre", "pedidos.pedido_id"])
1278
+ .get();
1279
+
1280
+ // Left join con agregación
1281
+ const contadorPedidosUsuarios = await tablaUsuarios
1282
+ .leftJoin("pedidos", "usuarios.id", "=", "pedidos.usuario_id")
1283
+ .select(["usuarios.nombre"])
1284
+ .count("pedidos.id")
1285
+ .groupBy("usuarios.id")
1286
+ .get();
1287
+
1288
+ console.log(usuariosConPedidos);
1289
+ // [{ nombre: 'Alicia', pedido_id: 101 }, { nombre: 'Roberto', pedido_id: null }, ...]
1290
+ ```
1291
+
1292
+ ### Consulta con RIGHT JOIN
1293
+
1294
+ Realiza un right join utilizando el método `rightJoin`.
1295
+
1296
+ ```typescript
1297
+ // Incluir pedidos aunque falten datos del usuario
1298
+ const pedidosConUsuarios = await tablaUsuarios
1299
+ .rightJoin("pedidos", "usuarios.id", "=", "pedidos.usuario_id")
1300
+ .select(["usuarios.nombre", "pedidos.pedido_id"])
1301
+ .get();
1302
+
1303
+ console.log(pedidosConUsuarios);
1304
+ // [{ nombre: 'Alicia', pedido_id: 101 }, { nombre: null, pedido_id: 102 }, ...]
1305
+ ```
1306
+
1307
+ ### Consulta con ORDER BY
1308
+
1309
+ Ordena resultados utilizando el método `orderBy`.
1310
+
1311
+ ```typescript
1312
+ // Ordenamiento de una columna
1313
+ const usuariosOrdenados = await tablaUsuarios
1314
+ .orderBy("nombre", "ASC")
1315
+ .get();
1316
+
1317
+ // Ordenamiento de múltiples columnas
1318
+ const ordenComplejo = await tablaUsuarios
1319
+ .orderBy("pais", "ASC")
1320
+ .orderBy("edad", "DESC")
1321
+ .orderBy("nombre", "ASC")
1322
+ .get();
1323
+
1324
+ // Ordenar con condiciones
1325
+ const usuariosActivosRecientes = await tablaUsuarios
1326
+ .where("estado", "=", "activo")
1327
+ .orderBy("ultimo_acceso", "DESC")
1328
+ .limit(20)
1329
+ .get();
1330
+
1331
+ console.log(usuariosOrdenados);
1332
+ // [{ id: 1, nombre: 'Alicia', ... }, { id: 2, nombre: 'Roberto', ... }]
1333
+ ```
1334
+
1335
+ ### Consulta con LIMIT y OFFSET (paginación)
1336
+
1337
+ Limita el número de resultados e implementa paginación utilizando `limit` y `page`.
1338
+
1339
+ ```typescript
1340
+ // Límite simple
1341
+ const primerosDiezUsuarios = await tablaUsuarios.limit(10).get();
1342
+
1343
+ // Paginación
1344
+ const primeraPagina = await tablaUsuarios.limit(5).page(1).get();
1345
+ const segundaPagina = await tablaUsuarios.limit(5).page(2).get();
1346
+
1347
+ // Paginación con ordenamiento
1348
+ const usuariosPaginados = await tablaUsuarios
1349
+ .orderBy("fecha_creacion", "DESC")
1350
+ .limit(10)
1351
+ .page(3) // Omitir los primeros 20 registros (páginas 1-2)
1352
+ .get();
1353
+
1354
+ console.log(primeraPagina); // Registros 1-5
1355
+ console.log(segundaPagina); // Registros 6-10
1356
+ ```
1357
+
1358
+ ### Consulta con GROUP BY
1359
+
1360
+ Agrupa resultados utilizando el método `groupBy`.
1361
+
1362
+ ```typescript
1363
+ // Agrupamiento simple
1364
+ const usuariosPorEdad = await tablaUsuarios
1365
+ .select(["edad"])
1366
+ .count("*")
1367
+ .groupBy("edad")
1368
+ .get();
1369
+
1370
+ // Múltiples columnas de agrupamiento
1371
+ const usuariosPorPaisYEdad = await tablaUsuarios
1372
+ .select(["pais", "edad"])
1373
+ .count("*")
1374
+ .groupBy("pais")
1375
+ .groupBy("edad")
1376
+ .get();
1377
+
1378
+ console.log(usuariosPorEdad);
1379
+ // [{ edad: 28, count: 2 }, { edad: 32, count: 1 }]
1380
+ ```
1381
+
1382
+ ### Consulta con DISTINCT
1383
+
1384
+ Recupera registros únicos utilizando el método `distinct`.
1385
+
1386
+ ```typescript
1387
+ // Valores únicos
1388
+ const paisesUnicos = await tablaUsuarios
1389
+ .distinct()
1390
+ .select(["pais"])
1391
+ .get();
1392
+
1393
+ // Distinct con condiciones
1394
+ const paisesUsuariosActivos = await tablaUsuarios
1395
+ .distinct()
1396
+ .select(["pais"])
1397
+ .where("estado", "=", "activo")
1398
+ .get();
1399
+
1400
+ console.log(paisesUnicos);
1401
+ // [{ pais: 'España' }, { pais: 'México' }, { pais: 'Argentina' }]
1402
+ ```
1403
+
1404
+ ## Funciones de agregación
1405
+
1406
+ ### count
1407
+
1408
+ Cuenta el número de registros.
1409
+
1410
+ ```typescript
1411
+ // Contar todos los registros
1412
+ const totalUsuarios = await tablaUsuarios.count().first();
1413
+ console.log(totalUsuarios); // { count: 150 }
1414
+
1415
+ // Contar columna específica
1416
+ const usuariosConEmail = await tablaUsuarios.count("email").first();
1417
+
1418
+ // Contar con condiciones
1419
+ const usuariosActivos = await tablaUsuarios
1420
+ .where("estado", "=", "activo")
1421
+ .count()
1422
+ .first();
1423
+ ```
1424
+
1425
+ ### sum
1426
+
1427
+ Calcula la suma de una columna.
1428
+
1429
+ ```typescript
1430
+ // Suma de edades
1431
+ const edadTotal = await tablaUsuarios.sum("edad").first();
1432
+ console.log(edadTotal); // { sum: 4250 }
1433
+
1434
+ // Suma con condiciones
1435
+ const ingresosPremium = await tablaUsuarios
1436
+ .join("pedidos", "usuarios.id", "=", "pedidos.usuario_id")
1437
+ .where("usuarios.suscripcion", "=", "premium")
1438
+ .sum("pedidos.total")
1439
+ .first();
1440
+ ```
1441
+
1442
+ ### avg
1443
+
1444
+ Calcula el promedio de una columna.
1445
+
1446
+ ```typescript
1447
+ // Edad promedio
1448
+ const edadPromedio = await tablaUsuarios.avg("edad").first();
1449
+ console.log(edadPromedio); // { avg: 28.33 }
1450
+
1451
+ // Promedio con agrupamiento
1452
+ const edadPromedioPorPais = await tablaUsuarios
1453
+ .select(["pais"])
1454
+ .avg("edad")
1455
+ .groupBy("pais")
1456
+ .get();
1457
+ ```
1458
+
1459
+ ### max
1460
+
1461
+ Encuentra el valor máximo en una columna.
1462
+
1463
+ ```typescript
1464
+ // Usuario más viejo
1465
+ const edadMaxima = await tablaUsuarios.max("edad").first();
1466
+ console.log(edadMaxima); // { max: 65 }
1467
+
1468
+ // Registro más reciente
1469
+ const usuarioMasReciente = await tablaUsuarios.max("fecha_creacion").first();
1470
+ ```
1471
+
1472
+ ### min
1473
+
1474
+ Encuentra el valor mínimo en una columna.
1475
+
1476
+ ```typescript
1477
+ // Usuario más joven
1478
+ const edadMinima = await tablaUsuarios.min("edad").first();
1479
+ console.log(edadMinima); // { min: 18 }
1480
+
1481
+ // Primer registro
1482
+ const primerUsuario = await tablaUsuarios.min("fecha_creacion").first();
1483
+ ```
1484
+
1485
+ ## Buscar registros
1486
+
1487
+ ### find
1488
+
1489
+ Encuentra un registro por un valor específico de columna (por defecto 'id').
1490
+
1491
+ ```typescript
1492
+ // Buscar por ID (por defecto)
1493
+ const usuario = await tablaUsuarios.find(1);
1494
+ console.log(usuario);
1495
+ // { id: 1, nombre: 'Alicia', email: 'alicia@ejemplo.com', edad: 28 }
1496
+
1497
+ // Buscar por columna específica
1498
+ const usuarioPorEmail = await tablaUsuarios.find("alicia@ejemplo.com", "email");
1499
+
1500
+ // Find devuelve null si no se encuentra
1501
+ const noExistente = await tablaUsuarios.find(999);
1502
+ console.log(noExistente); // null
1503
+ ```
1504
+
1505
+ ### first
1506
+
1507
+ Obtiene solo el primer registro que cumple con las condiciones.
1508
+
1509
+ ```typescript
1510
+ // Primer usuario que cumple la condición
1511
+ const primerUsuario = await tablaUsuarios
1512
+ .where("edad", ">", 25)
1513
+ .orderBy("fecha_creacion", "ASC")
1514
+ .first();
1515
+
1516
+ // Primer usuario en general
1517
+ const cuentaMasAntigua = await tablaUsuarios
1518
+ .orderBy("fecha_creacion", "ASC")
1519
+ .first();
1520
+
1521
+ console.log(primerUsuario);
1522
+ // { id: 1, nombre: 'Alicia', edad: 28, ... } o null si no hay coincidencia
1523
+ ```
1524
+
1525
+ ## Campos calculados y triggers
1526
+
1527
+ DBCube Query Builder soporta campos calculados y triggers para procesamiento avanzado de datos.
1528
+
1529
+ ```typescript
1530
+ // Habilitar campos calculados (procesados automáticamente)
1531
+ await db.useComputes();
1532
+
1533
+ // Habilitar triggers
1534
+ await db.useTriggers();
1535
+
1536
+ // Los triggers y campos calculados se configuran a través de otros componentes DBCube
1537
+ ```
1538
+
1539
+ ## Ejecutar consultas SQL crudas
1540
+
1541
+ Para consultas complejas que requieren SQL crudo, utiliza el motor subyacente.
1542
+
1543
+ ```typescript
1544
+ // Acceder al motor subyacente para consultas crudas
1545
+ // (La implementación depende de tu configuración específica de DBCube core)
1546
+
1547
+ // Nota: Las consultas SQL crudas evitan la capa de abstracción del query builder
1548
+ // y son específicas de la base de datos
1549
+ ```
1550
+
1551
+ ### Manejo de errores
1552
+
1553
+ La biblioteca proporciona manejo comprehensivo de errores con mensajes descriptivos.
1554
+
1555
+ ```typescript
1556
+ try {
1557
+ // Esto arrojará un error - UPDATE requiere condiciones WHERE
1558
+ await tablaUsuarios.update({ nombre: "Actualizado" });
1559
+ } catch (error) {
1560
+ console.error(error.message);
1561
+ // "Debes especificar al menos una condición WHERE para realizar una actualización."
1562
+ }
1563
+
1564
+ try {
1565
+ // Esto arrojará un error - formato de datos inválido
1566
+ await tablaUsuarios.insert("datos inválidos");
1567
+ } catch (error) {
1568
+ console.error(error.message);
1569
+ // "El método insert requiere un array de objetos con pares clave-valor."
1570
+ }
1571
+
1572
+ // Los errores de conexión y base de datos también se manejan apropiadamente
1573
+ try {
1574
+ const resultado = await tablaUsuarios.get();
1575
+ } catch (error) {
1576
+ // Errores de conexión a base de datos o ejecución de consultas
1577
+ console.error("Error de base de datos:", error);
1578
+ }
1579
+ ```
1580
+
1581
+ ## API completa
1582
+
1583
+ ### Clase Database
1584
+
1585
+ #### `new Database(name: string)`
1586
+
1587
+ Crea una nueva instancia de conexión a base de datos.
1588
+
1589
+ ```typescript
1590
+ const db = new Database("mi_base_de_datos");
1591
+ ```
1592
+
1593
+ #### `table(tableName: string): Table`
1594
+
1595
+ Devuelve una instancia Table para construir consultas en la tabla especificada.
1596
+
1597
+ ```typescript
1598
+ const tablaUsuarios = db.table("usuarios");
1599
+ ```
1600
+
1601
+ #### `useComputes(): Promise<void>`
1602
+
1603
+ Habilita el procesamiento de campos calculados para la base de datos.
1604
+
1605
+ ```typescript
1606
+ await db.useComputes();
1607
+ ```
1608
+
1609
+ #### `useTriggers(): Promise<void>`
1610
+
1611
+ Habilita el procesamiento de triggers para la base de datos.
1612
+
1613
+ ```typescript
1614
+ await db.useTriggers();
1615
+ ```
1616
+
1617
+ #### `connect(): Promise<void>`
1618
+
1619
+ Establece conexión a base de datos (manejado automáticamente).
1620
+
1621
+ #### `disconnect(): Promise<void>`
1622
+
1623
+ Cierra conexión a base de datos.
1624
+
1625
+ ### Clase Table
1626
+
1627
+ Los métodos de la clase Table siguen la misma API que se documentó en la sección en inglés, con la funcionalidad idéntica.
1628
+
1629
+ ## Soporte multi-base de datos
1630
+
1631
+ DBCube Query Builder funciona con múltiples motores de base de datos:
1632
+
1633
+ ```typescript
1634
+ // MySQL
1635
+ const mysqlDb = new Database("base_datos_mysql");
1636
+
1637
+ // PostgreSQL
1638
+ const postgresDb = new Database("base_datos_postgres");
1639
+
1640
+ // SQLite
1641
+ const sqliteDb = new Database("base_datos_sqlite");
1642
+
1643
+ // MongoDB
1644
+ const mongoDb = new Database("base_datos_mongo");
1645
+
1646
+ // La misma API funciona a través de todas las bases de datos
1647
+ const usuarios = await mysqlDb.table("usuarios").get();
1648
+ const posts = await postgresDb.table("posts").get();
1649
+ const logs = await sqliteDb.table("logs").get();
1650
+ const analiticas = await mongoDb.table("analiticas").get();
1651
+ ```
1652
+
1653
+ ## Características avanzadas
1654
+
1655
+ ### Ejemplo de consulta compleja
1656
+
1657
+ ```typescript
1658
+ // Consulta de negocio compleja
1659
+ const reporteMensual = await db.table("pedidos")
1660
+ .join("usuarios", "pedidos.usuario_id", "=", "usuarios.id")
1661
+ .join("items_pedido", "pedidos.id", "=", "items_pedido.pedido_id")
1662
+ .join("productos", "items_pedido.producto_id", "=", "productos.id")
1663
+ .select([
1664
+ "usuarios.pais",
1665
+ "productos.categoria"
1666
+ ])
1667
+ .sum("items_pedido.cantidad * items_pedido.precio")
1668
+ .where("pedidos.estado", "=", "completado")
1669
+ .whereBetween("pedidos.fecha_creacion", ["2024-01-01", "2024-01-31"])
1670
+ .groupBy("usuarios.pais")
1671
+ .groupBy("productos.categoria")
1672
+ .orderBy("sum", "DESC")
1673
+ .limit(10)
1674
+ .get();
1675
+ ```
1676
+
1677
+ ### Encadenamiento de métodos
1678
+
1679
+ Todos los métodos del query builder devuelven la instancia Table, habilitando el encadenamiento fluido de métodos:
1680
+
1681
+ ```typescript
1682
+ const resultado = await db
1683
+ .table("usuarios")
1684
+ .select(["nombre", "email", "pais"])
1685
+ .where("activo", "=", true)
1686
+ .whereNotNull("email_verificado_en")
1687
+ .whereGroup((query) => {
1688
+ query.where("suscripcion", "=", "premium")
1689
+ .orWhere("pedidos_totales", ">", 10);
1690
+ })
1691
+ .join("perfiles_usuario", "usuarios.id", "=", "perfiles_usuario.usuario_id")
1692
+ .orderBy("usuarios.fecha_creacion", "DESC")
1693
+ .limit(50)
1694
+ .page(1)
1695
+ .get();
1696
+ ```
131
1697
 
132
- ## About
1698
+ ## Licencia
133
1699
 
134
- dbcube-query-builder is part of the dbcube ecosystem, designed to provide a robust and flexible query building experience for modern Node.js applications.
1700
+ Este proyecto está licenciado bajo la Licencia MIT - consulta el archivo LICENSE para más detalles.