@rvoh/dream 0.42.2 → 0.42.3

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.
Files changed (179) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/src/Dream.js +30 -0
  3. package/dist/cjs/src/dream/DreamClassTransactionBuilder.js +32 -0
  4. package/dist/cjs/src/dream/Query.js +50 -0
  5. package/dist/cjs/src/dream/internal/computedPaginatePage.js +10 -0
  6. package/dist/cjs/src/dream-app/index.js +7 -0
  7. package/dist/cjs/src/errors/pagination/CannotPaginateWithLimit.js +17 -0
  8. package/dist/cjs/src/errors/pagination/CannotPaginateWithOffset.js +17 -0
  9. package/dist/esm/src/Dream.js +30 -0
  10. package/dist/esm/src/dream/DreamClassTransactionBuilder.js +32 -0
  11. package/dist/esm/src/dream/Query.js +50 -0
  12. package/dist/esm/src/dream/internal/computedPaginatePage.js +7 -0
  13. package/dist/esm/src/dream-app/index.js +7 -0
  14. package/dist/esm/src/errors/pagination/CannotPaginateWithLimit.js +14 -0
  15. package/dist/esm/src/errors/pagination/CannotPaginateWithOffset.js +14 -0
  16. package/dist/types/src/Dream.d.ts +29 -1
  17. package/dist/types/src/dream/DreamClassTransactionBuilder.d.ts +31 -1
  18. package/dist/types/src/dream/Query.d.ts +29 -1
  19. package/dist/types/src/dream/internal/computedPaginatePage.d.ts +1 -0
  20. package/dist/types/src/dream-app/index.d.ts +4 -2
  21. package/dist/types/src/errors/pagination/CannotPaginateWithLimit.d.ts +3 -0
  22. package/dist/types/src/errors/pagination/CannotPaginateWithOffset.d.ts +3 -0
  23. package/dist/types/src/types/query.d.ts +28 -0
  24. package/dist/types/src/types/query.ts +34 -0
  25. package/docs/assets/search.js +1 -1
  26. package/docs/classes/Benchmark.html +2 -2
  27. package/docs/classes/CalendarDate.html +2 -2
  28. package/docs/classes/CreateOrFindByFailedToCreateAndFind.html +3 -3
  29. package/docs/classes/Decorators.html +19 -19
  30. package/docs/classes/Dream.html +162 -154
  31. package/docs/classes/DreamApp.html +5 -4
  32. package/docs/classes/DreamBin.html +2 -2
  33. package/docs/classes/DreamCLI.html +4 -4
  34. package/docs/classes/DreamImporter.html +2 -2
  35. package/docs/classes/DreamLogos.html +2 -2
  36. package/docs/classes/DreamMigrationHelpers.html +7 -7
  37. package/docs/classes/DreamSerializer.html +2 -2
  38. package/docs/classes/DreamTransaction.html +2 -2
  39. package/docs/classes/Encrypt.html +2 -2
  40. package/docs/classes/Env.html +2 -2
  41. package/docs/classes/GlobalNameNotSet.html +3 -3
  42. package/docs/classes/NonLoadedAssociation.html +3 -3
  43. package/docs/classes/Query.html +58 -50
  44. package/docs/classes/Range.html +2 -2
  45. package/docs/classes/RecordNotFound.html +3 -3
  46. package/docs/classes/ValidationError.html +3 -3
  47. package/docs/functions/Attribute.html +1 -1
  48. package/docs/functions/RendersMany.html +1 -1
  49. package/docs/functions/RendersOne.html +1 -1
  50. package/docs/functions/ReplicaSafe.html +1 -1
  51. package/docs/functions/STI.html +1 -1
  52. package/docs/functions/SoftDelete.html +1 -1
  53. package/docs/functions/camelize.html +1 -1
  54. package/docs/functions/capitalize.html +1 -1
  55. package/docs/functions/closeAllDbConnections.html +1 -1
  56. package/docs/functions/compact.html +1 -1
  57. package/docs/functions/dreamDbConnections.html +1 -1
  58. package/docs/functions/dreamPath.html +1 -1
  59. package/docs/functions/generateDream.html +1 -1
  60. package/docs/functions/globalClassNameFromFullyQualifiedModelName.html +1 -1
  61. package/docs/functions/hyphenize.html +1 -1
  62. package/docs/functions/inferSerializerFromDreamClassOrViewModelClass.html +1 -1
  63. package/docs/functions/inferSerializerFromDreamOrViewModel.html +1 -1
  64. package/docs/functions/intersection.html +1 -1
  65. package/docs/functions/isEmpty.html +1 -1
  66. package/docs/functions/loadRepl.html +1 -1
  67. package/docs/functions/lookupClassByGlobalName.html +1 -1
  68. package/docs/functions/pascalize.html +1 -1
  69. package/docs/functions/pgErrorType.html +1 -1
  70. package/docs/functions/range-1.html +1 -1
  71. package/docs/functions/relativeDreamPath.html +1 -1
  72. package/docs/functions/round.html +1 -1
  73. package/docs/functions/serializerNameFromFullyQualifiedModelName.html +1 -1
  74. package/docs/functions/sharedPathPrefix.html +1 -1
  75. package/docs/functions/snakeify.html +1 -1
  76. package/docs/functions/sort.html +1 -1
  77. package/docs/functions/sortBy.html +1 -1
  78. package/docs/functions/standardizeFullyQualifiedModelName.html +1 -1
  79. package/docs/functions/uncapitalize.html +1 -1
  80. package/docs/functions/uniq.html +1 -1
  81. package/docs/functions/untypedDb.html +1 -1
  82. package/docs/functions/validateColumn.html +1 -1
  83. package/docs/functions/validateTable.html +1 -1
  84. package/docs/index.html +1 -1
  85. package/docs/interfaces/AttributeStatement.html +2 -2
  86. package/docs/interfaces/DecoratorContext.html +2 -2
  87. package/docs/interfaces/DreamAppInitOptions.html +2 -2
  88. package/docs/interfaces/DreamAppOpts.html +2 -2
  89. package/docs/interfaces/DreamSerializerAssociationStatement.html +2 -2
  90. package/docs/interfaces/EncryptOptions.html +2 -2
  91. package/docs/interfaces/OpenapiSchemaProperties.html +1 -1
  92. package/docs/interfaces/OpenapiSchemaPropertiesShorthand.html +1 -1
  93. package/docs/interfaces/OpenapiTypeFieldObject.html +1 -1
  94. package/docs/types/Camelized.html +1 -1
  95. package/docs/types/CommonOpenapiSchemaObjectFields.html +1 -1
  96. package/docs/types/DateTime.html +1 -1
  97. package/docs/types/DbConnectionType.html +1 -1
  98. package/docs/types/DreamAssociationMetadata.html +1 -1
  99. package/docs/types/DreamAttributes.html +1 -1
  100. package/docs/types/DreamClassColumn.html +1 -1
  101. package/docs/types/DreamColumn.html +1 -1
  102. package/docs/types/DreamColumnNames.html +1 -1
  103. package/docs/types/DreamLogLevel.html +1 -1
  104. package/docs/types/DreamLogger.html +1 -1
  105. package/docs/types/DreamOrViewModelClassSerializerArrayKeys.html +1 -1
  106. package/docs/types/DreamOrViewModelClassSerializerKey.html +1 -1
  107. package/docs/types/DreamOrViewModelSerializerKey.html +1 -1
  108. package/docs/types/DreamParamSafeAttributes.html +1 -1
  109. package/docs/types/DreamParamSafeColumnNames.html +1 -1
  110. package/docs/types/DreamSerializable.html +1 -1
  111. package/docs/types/DreamSerializableArray.html +1 -1
  112. package/docs/types/DreamSerializerKey.html +1 -1
  113. package/docs/types/DreamSerializers.html +1 -1
  114. package/docs/types/DreamTableSchema.html +1 -1
  115. package/docs/types/DreamVirtualColumns.html +1 -1
  116. package/docs/types/EncryptAlgorithm.html +1 -1
  117. package/docs/types/Hyphenized.html +1 -1
  118. package/docs/types/IdType.html +1 -1
  119. package/docs/types/OpenapiAllTypes.html +1 -1
  120. package/docs/types/OpenapiFormats.html +1 -1
  121. package/docs/types/OpenapiNumberFormats.html +1 -1
  122. package/docs/types/OpenapiPrimitiveTypes.html +1 -1
  123. package/docs/types/OpenapiSchemaArray.html +1 -1
  124. package/docs/types/OpenapiSchemaArrayShorthand.html +1 -1
  125. package/docs/types/OpenapiSchemaBase.html +1 -1
  126. package/docs/types/OpenapiSchemaBody.html +1 -1
  127. package/docs/types/OpenapiSchemaBodyShorthand.html +1 -1
  128. package/docs/types/OpenapiSchemaCommonFields.html +1 -1
  129. package/docs/types/OpenapiSchemaExpressionAllOf.html +1 -1
  130. package/docs/types/OpenapiSchemaExpressionAnyOf.html +1 -1
  131. package/docs/types/OpenapiSchemaExpressionOneOf.html +1 -1
  132. package/docs/types/OpenapiSchemaExpressionRef.html +1 -1
  133. package/docs/types/OpenapiSchemaExpressionRefSchemaShorthand.html +1 -1
  134. package/docs/types/OpenapiSchemaInteger.html +1 -1
  135. package/docs/types/OpenapiSchemaNull.html +1 -1
  136. package/docs/types/OpenapiSchemaNumber.html +1 -1
  137. package/docs/types/OpenapiSchemaObject.html +1 -1
  138. package/docs/types/OpenapiSchemaObjectAllOf.html +1 -1
  139. package/docs/types/OpenapiSchemaObjectAllOfShorthand.html +1 -1
  140. package/docs/types/OpenapiSchemaObjectAnyOf.html +1 -1
  141. package/docs/types/OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  142. package/docs/types/OpenapiSchemaObjectBase.html +1 -1
  143. package/docs/types/OpenapiSchemaObjectBaseShorthand.html +1 -1
  144. package/docs/types/OpenapiSchemaObjectOneOf.html +1 -1
  145. package/docs/types/OpenapiSchemaObjectOneOfShorthand.html +1 -1
  146. package/docs/types/OpenapiSchemaObjectShorthand.html +1 -1
  147. package/docs/types/OpenapiSchemaPrimitiveGeneric.html +1 -1
  148. package/docs/types/OpenapiSchemaShorthandExpressionAllOf.html +1 -1
  149. package/docs/types/OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
  150. package/docs/types/OpenapiSchemaShorthandExpressionOneOf.html +1 -1
  151. package/docs/types/OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
  152. package/docs/types/OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
  153. package/docs/types/OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  154. package/docs/types/OpenapiSchemaString.html +1 -1
  155. package/docs/types/OpenapiShorthandAllTypes.html +1 -1
  156. package/docs/types/OpenapiShorthandPrimitiveTypes.html +1 -1
  157. package/docs/types/OpenapiTypeField.html +1 -1
  158. package/docs/types/Pascalized.html +1 -1
  159. package/docs/types/PrimaryKeyType.html +1 -1
  160. package/docs/types/RoundingPrecision.html +1 -1
  161. package/docs/types/SerializableClassOrSerializerCallback.html +1 -1
  162. package/docs/types/SerializableTypes.html +1 -1
  163. package/docs/types/Snakeified.html +1 -1
  164. package/docs/types/Timestamp.html +1 -1
  165. package/docs/types/UpdateableAssociationProperties.html +1 -1
  166. package/docs/types/UpdateableProperties.html +1 -1
  167. package/docs/types/ValidationType.html +1 -1
  168. package/docs/types/ViewModel.html +1 -1
  169. package/docs/types/ViewModelClass.html +1 -1
  170. package/docs/types/WhereStatementForDream.html +1 -1
  171. package/docs/types/WhereStatementForDreamClass.html +1 -1
  172. package/docs/variables/DateTime-1.html +1 -1
  173. package/docs/variables/DreamConst.html +1 -1
  174. package/docs/variables/TRIGRAM_OPERATORS.html +1 -1
  175. package/docs/variables/openapiPrimitiveTypes-1.html +1 -1
  176. package/docs/variables/openapiShorthandPrimitiveTypes-1.html +1 -1
  177. package/docs/variables/ops.html +1 -1
  178. package/docs/variables/primaryKeyTypes.html +1 -1
  179. package/package.json +1 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- > ATTENTION: we are currently in the process of releasing this code to the world, as of the afternoon of March 10th, 2025. This notice will be removed, and the version of this repo will be bumped to 1.0.0, once all of the repos have been migrated to the new spaces and we can verify that it is all working. This is anticipated to take 1 day.
1
+ > ATTENTION: we are currently in the process of releasing this code to the world, as of the afternoon of May 21st, 2025. This notice will be removed, and the version of this repo will be bumped to 1.0.0, once all of the repos have been migrated to the new spaces and we can verify that it is all working. This should happen sometime in the next month.
2
2
 
3
3
  Dream is a typescript-driven, esm-first ORM built on top of [kysely](http://kysely.dev). It is built to operate within the [Psychic web framework](https://psychic-docs.netlify.app), but can be brought into other projects and used without the encapsulating framework (though this is theoretical, and we do not encourage it at this time). It is actively being developed to support production-grade applications in use within the [RVOHealth organization](https://www.rvohealth.com), who has kindly sponsored the continued development of this ORM, as well as the Psychic web framework as a whole.
4
4
 
@@ -596,6 +596,36 @@ class Dream {
596
596
  static async all(options = {}) {
597
597
  return await this.query().all(options);
598
598
  }
599
+ /**
600
+ * Paginates the results of your query, accepting a pageSize and page argument,
601
+ * which it uses to segment your query into pages, leveraging limit and offset
602
+ * to deliver your query to you in pages.
603
+ *
604
+ * ```ts
605
+ * const paginated = await User.paginate({ pageSize: 100, page: 2 })
606
+ * paginated.results
607
+ * // [ { User{id: 101}, User{id: 102}, ...}]
608
+ *
609
+ * paginated.recordCount
610
+ * // 350
611
+ *
612
+ * paginated.pageCount
613
+ * // 4
614
+ *
615
+ * paginated.currentPage
616
+ * // 2
617
+ * ```
618
+ *
619
+ * @param opts.page - the page number that you want to fetch results for
620
+ * @param opts.pageSize - the number of results per page (optional)
621
+ * @returns results.recordCount - A number representing the total number of records matching your query
622
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
623
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
624
+ * @returns results.results - An array of records matching the current record
625
+ */
626
+ static async paginate(opts) {
627
+ return await this.query().paginate(opts);
628
+ }
599
629
  /**
600
630
  * Forces use of a database connection (e.g. 'primary') during the query.
601
631
  *
@@ -38,6 +38,38 @@ class DreamClassTransactionBuilder {
38
38
  async all(options = {}) {
39
39
  return this.queryInstance().all(options);
40
40
  }
41
+ /**
42
+ * Paginates the results of your query, accepting a pageSize and page argument,
43
+ * which it uses to segment your query into pages, leveraging limit and offset
44
+ * to deliver your query to you in pages.
45
+ *
46
+ * ```ts
47
+ * await ApplicationModel.transaction(async txn => {
48
+ * const paginated = await User.txn(txn).paginate({ pageSize: 100, page: 2 })
49
+ * paginated.results
50
+ * // [ { User{id: 101}, User{id: 102}, ...}]
51
+ *
52
+ * paginated.recordCount
53
+ * // 350
54
+ *
55
+ * paginated.pageCount
56
+ * // 4
57
+ *
58
+ * paginated.currentPage
59
+ * // 2
60
+ * })
61
+ * ```
62
+ *
63
+ * @param opts.page - the page number that you want to fetch results for
64
+ * @param opts.pageSize - the number of results per page (optional)
65
+ * @returns results.recordCount - A number representing the total number of records matching your query
66
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
67
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
68
+ * @returns results.results - An array of records matching the current record
69
+ */
70
+ async paginate(opts) {
71
+ return await this.queryInstance().paginate(opts);
72
+ }
41
73
  /**
42
74
  * Retrieves the number of records corresponding
43
75
  * to this model.
@@ -47,6 +47,10 @@ const orderByDirection_js_1 = require("./internal/orderByDirection.js");
47
47
  const shouldBypassDefaultScope_js_1 = require("./internal/shouldBypassDefaultScope.js");
48
48
  const SimilarityBuilder_js_1 = require("./internal/similarity/SimilarityBuilder.js");
49
49
  const sqlResultToDreamInstance_js_1 = require("./internal/sqlResultToDreamInstance.js");
50
+ const index_js_2 = require("../dream-app/index.js");
51
+ const CannotPaginateWithLimit_js_1 = require("../errors/pagination/CannotPaginateWithLimit.js");
52
+ const CannotPaginateWithOffset_js_1 = require("../errors/pagination/CannotPaginateWithOffset.js");
53
+ const computedPaginatePage_js_1 = require("./internal/computedPaginatePage.js");
50
54
  class Query extends ConnectedToDB_js_1.default {
51
55
  /**
52
56
  * @internal
@@ -1414,6 +1418,52 @@ class Query extends ConnectedToDB_js_1.default {
1414
1418
  await this.applyPreload(this.preloadStatements, this.preloadOnStatements, theAll);
1415
1419
  return theAll;
1416
1420
  }
1421
+ /**
1422
+ * Paginates the results of your query, accepting a pageSize and page argument,
1423
+ * which it uses to segment your query into pages, leveraging limit and offset
1424
+ * to deliver your query to you in pages.
1425
+ *
1426
+ * ```ts
1427
+ * const paginated = await User.order('email').paginate({ pageSize: 100, page: 2 })
1428
+ * paginated.results
1429
+ * // [ { User{id: 101}, User{id: 102}, ...}]
1430
+ *
1431
+ * paginated.recordCount
1432
+ * // 350
1433
+ *
1434
+ * paginated.pageCount
1435
+ * // 4
1436
+ *
1437
+ * paginated.currentPage
1438
+ * // 2
1439
+ * ```
1440
+ *
1441
+ * @param opts.page - the page number that you want to fetch results for
1442
+ * @param opts.pageSize - the number of results per page (optional)
1443
+ * @returns results.recordCount - A number representing the total number of records matching your query
1444
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
1445
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
1446
+ * @returns results.results - An array of records matching the current record
1447
+ */
1448
+ async paginate(opts) {
1449
+ if (this.limitStatement)
1450
+ throw new CannotPaginateWithLimit_js_1.default();
1451
+ if (this.offsetStatement)
1452
+ throw new CannotPaginateWithOffset_js_1.default();
1453
+ const page = (0, computedPaginatePage_js_1.default)(opts.page);
1454
+ const recordCount = await this.count();
1455
+ const pageSize = opts.pageSize || index_js_2.default.getOrFail().paginationPageSize;
1456
+ const pageCount = Math.ceil(recordCount / pageSize);
1457
+ const results = await this.limit(pageSize)
1458
+ .offset((page - 1) * pageSize)
1459
+ .all();
1460
+ return {
1461
+ recordCount,
1462
+ pageCount,
1463
+ currentPage: page,
1464
+ results,
1465
+ };
1466
+ }
1417
1467
  /**
1418
1468
  * Forces use of a database connection (e.g. 'primary') during the query.
1419
1469
  *
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = computedPaginatePage;
4
+ function computedPaginatePage(page) {
5
+ if (page === null)
6
+ return 1;
7
+ if (page === undefined)
8
+ return 1;
9
+ return page <= 1 ? 1 : Math.floor(page);
10
+ }
@@ -179,6 +179,10 @@ Try setting it to something valid, like:
179
179
  get unicodeNormalization() {
180
180
  return this._unicodeNormalization;
181
181
  }
182
+ _paginationPageSize = 25;
183
+ get paginationPageSize() {
184
+ return this._paginationPageSize;
185
+ }
182
186
  _primaryKeyType = 'bigserial';
183
187
  get primaryKeyType() {
184
188
  return this._primaryKeyType;
@@ -310,6 +314,9 @@ Try setting it to something valid, like:
310
314
  case 'unicodeNormalization':
311
315
  this._unicodeNormalization = options;
312
316
  break;
317
+ case 'paginationPageSize':
318
+ this._paginationPageSize = options;
319
+ break;
313
320
  default:
314
321
  throw new Error(`Unhandled applyOption encountered in Dreamconf: ${applyOption}`);
315
322
  }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class CannotPaginateWithLimit extends Error {
4
+ get message() {
5
+ return `\
6
+ Cannot call paginate on a query which has a limit applied.
7
+
8
+ Limit statements are automatically generated by the paginate method,
9
+ and adding custom limits interferes with paginate's ability to provide
10
+ a total count.
11
+
12
+ fix:
13
+ remove the limit statement from your query
14
+ `;
15
+ }
16
+ }
17
+ exports.default = CannotPaginateWithLimit;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class CannotPaginateWithOffset extends Error {
4
+ get message() {
5
+ return `\
6
+ Cannot call paginate on a query which has an offset applied.
7
+
8
+ Offset statements are automatically generated by the paginate method,
9
+ and adding custom offsets interferes with paginate's ability to provide
10
+ a total count.
11
+
12
+ fix:
13
+ remove the offset statement from your query
14
+ `;
15
+ }
16
+ }
17
+ exports.default = CannotPaginateWithOffset;
@@ -594,6 +594,36 @@ export default class Dream {
594
594
  static async all(options = {}) {
595
595
  return await this.query().all(options);
596
596
  }
597
+ /**
598
+ * Paginates the results of your query, accepting a pageSize and page argument,
599
+ * which it uses to segment your query into pages, leveraging limit and offset
600
+ * to deliver your query to you in pages.
601
+ *
602
+ * ```ts
603
+ * const paginated = await User.paginate({ pageSize: 100, page: 2 })
604
+ * paginated.results
605
+ * // [ { User{id: 101}, User{id: 102}, ...}]
606
+ *
607
+ * paginated.recordCount
608
+ * // 350
609
+ *
610
+ * paginated.pageCount
611
+ * // 4
612
+ *
613
+ * paginated.currentPage
614
+ * // 2
615
+ * ```
616
+ *
617
+ * @param opts.page - the page number that you want to fetch results for
618
+ * @param opts.pageSize - the number of results per page (optional)
619
+ * @returns results.recordCount - A number representing the total number of records matching your query
620
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
621
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
622
+ * @returns results.results - An array of records matching the current record
623
+ */
624
+ static async paginate(opts) {
625
+ return await this.query().paginate(opts);
626
+ }
597
627
  /**
598
628
  * Forces use of a database connection (e.g. 'primary') during the query.
599
629
  *
@@ -36,6 +36,38 @@ export default class DreamClassTransactionBuilder {
36
36
  async all(options = {}) {
37
37
  return this.queryInstance().all(options);
38
38
  }
39
+ /**
40
+ * Paginates the results of your query, accepting a pageSize and page argument,
41
+ * which it uses to segment your query into pages, leveraging limit and offset
42
+ * to deliver your query to you in pages.
43
+ *
44
+ * ```ts
45
+ * await ApplicationModel.transaction(async txn => {
46
+ * const paginated = await User.txn(txn).paginate({ pageSize: 100, page: 2 })
47
+ * paginated.results
48
+ * // [ { User{id: 101}, User{id: 102}, ...}]
49
+ *
50
+ * paginated.recordCount
51
+ * // 350
52
+ *
53
+ * paginated.pageCount
54
+ * // 4
55
+ *
56
+ * paginated.currentPage
57
+ * // 2
58
+ * })
59
+ * ```
60
+ *
61
+ * @param opts.page - the page number that you want to fetch results for
62
+ * @param opts.pageSize - the number of results per page (optional)
63
+ * @returns results.recordCount - A number representing the total number of records matching your query
64
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
65
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
66
+ * @returns results.results - An array of records matching the current record
67
+ */
68
+ async paginate(opts) {
69
+ return await this.queryInstance().paginate(opts);
70
+ }
39
71
  /**
40
72
  * Retrieves the number of records corresponding
41
73
  * to this model.
@@ -45,6 +45,10 @@ import orderByDirection from './internal/orderByDirection.js';
45
45
  import shouldBypassDefaultScope from './internal/shouldBypassDefaultScope.js';
46
46
  import SimilarityBuilder from './internal/similarity/SimilarityBuilder.js';
47
47
  import sqlResultToDreamInstance from './internal/sqlResultToDreamInstance.js';
48
+ import DreamApp from '../dream-app/index.js';
49
+ import CannotPaginateWithLimit from '../errors/pagination/CannotPaginateWithLimit.js';
50
+ import CannotPaginateWithOffset from '../errors/pagination/CannotPaginateWithOffset.js';
51
+ import computedPaginatePage from './internal/computedPaginatePage.js';
48
52
  export default class Query extends ConnectedToDB {
49
53
  /**
50
54
  * @internal
@@ -1412,6 +1416,52 @@ export default class Query extends ConnectedToDB {
1412
1416
  await this.applyPreload(this.preloadStatements, this.preloadOnStatements, theAll);
1413
1417
  return theAll;
1414
1418
  }
1419
+ /**
1420
+ * Paginates the results of your query, accepting a pageSize and page argument,
1421
+ * which it uses to segment your query into pages, leveraging limit and offset
1422
+ * to deliver your query to you in pages.
1423
+ *
1424
+ * ```ts
1425
+ * const paginated = await User.order('email').paginate({ pageSize: 100, page: 2 })
1426
+ * paginated.results
1427
+ * // [ { User{id: 101}, User{id: 102}, ...}]
1428
+ *
1429
+ * paginated.recordCount
1430
+ * // 350
1431
+ *
1432
+ * paginated.pageCount
1433
+ * // 4
1434
+ *
1435
+ * paginated.currentPage
1436
+ * // 2
1437
+ * ```
1438
+ *
1439
+ * @param opts.page - the page number that you want to fetch results for
1440
+ * @param opts.pageSize - the number of results per page (optional)
1441
+ * @returns results.recordCount - A number representing the total number of records matching your query
1442
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
1443
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
1444
+ * @returns results.results - An array of records matching the current record
1445
+ */
1446
+ async paginate(opts) {
1447
+ if (this.limitStatement)
1448
+ throw new CannotPaginateWithLimit();
1449
+ if (this.offsetStatement)
1450
+ throw new CannotPaginateWithOffset();
1451
+ const page = computedPaginatePage(opts.page);
1452
+ const recordCount = await this.count();
1453
+ const pageSize = opts.pageSize || DreamApp.getOrFail().paginationPageSize;
1454
+ const pageCount = Math.ceil(recordCount / pageSize);
1455
+ const results = await this.limit(pageSize)
1456
+ .offset((page - 1) * pageSize)
1457
+ .all();
1458
+ return {
1459
+ recordCount,
1460
+ pageCount,
1461
+ currentPage: page,
1462
+ results,
1463
+ };
1464
+ }
1415
1465
  /**
1416
1466
  * Forces use of a database connection (e.g. 'primary') during the query.
1417
1467
  *
@@ -0,0 +1,7 @@
1
+ export default function computedPaginatePage(page) {
2
+ if (page === null)
3
+ return 1;
4
+ if (page === undefined)
5
+ return 1;
6
+ return page <= 1 ? 1 : Math.floor(page);
7
+ }
@@ -177,6 +177,10 @@ Try setting it to something valid, like:
177
177
  get unicodeNormalization() {
178
178
  return this._unicodeNormalization;
179
179
  }
180
+ _paginationPageSize = 25;
181
+ get paginationPageSize() {
182
+ return this._paginationPageSize;
183
+ }
180
184
  _primaryKeyType = 'bigserial';
181
185
  get primaryKeyType() {
182
186
  return this._primaryKeyType;
@@ -308,6 +312,9 @@ Try setting it to something valid, like:
308
312
  case 'unicodeNormalization':
309
313
  this._unicodeNormalization = options;
310
314
  break;
315
+ case 'paginationPageSize':
316
+ this._paginationPageSize = options;
317
+ break;
311
318
  default:
312
319
  throw new Error(`Unhandled applyOption encountered in Dreamconf: ${applyOption}`);
313
320
  }
@@ -0,0 +1,14 @@
1
+ export default class CannotPaginateWithLimit extends Error {
2
+ get message() {
3
+ return `\
4
+ Cannot call paginate on a query which has a limit applied.
5
+
6
+ Limit statements are automatically generated by the paginate method,
7
+ and adding custom limits interferes with paginate's ability to provide
8
+ a total count.
9
+
10
+ fix:
11
+ remove the limit statement from your query
12
+ `;
13
+ }
14
+ }
@@ -0,0 +1,14 @@
1
+ export default class CannotPaginateWithOffset extends Error {
2
+ get message() {
3
+ return `\
4
+ Cannot call paginate on a query which has an offset applied.
5
+
6
+ Offset statements are automatically generated by the paginate method,
7
+ and adding custom offsets interferes with paginate's ability to provide
8
+ a total count.
9
+
10
+ fix:
11
+ remove the offset statement from your query
12
+ `;
13
+ }
14
+ }
@@ -13,7 +13,7 @@ import { AssociationStatementsMap, PassthroughOnClause, WhereStatement } from '.
13
13
  import { AssociationTableNames, DbConnectionType } from './types/db.js';
14
14
  import { AllDefaultScopeNames, AssociationNameToDream, AttributeKeys, CreateOrFindByExtraOpts, DefaultOrNamedScopeName, DreamAssociationNames, DreamAssociationNamesWithoutRequiredOnClauses, DreamAttributes, DreamColumnNames, DreamParamSafeColumnNames, DreamSerializeOptions, IdType, JoinAndStatements, NextPreloadArgumentType, OrderDir, PassthroughColumnNames, PluckEachArgs, PrimaryKeyForFind, TableColumnNames, UpdateableAssociationProperties, UpdateableProperties, UpdateablePropertiesForClass, UpdateOrCreateByExtraOpts } from './types/dream.js';
15
15
  import { HookStatement, HookStatementMap } from './types/lifecycle.js';
16
- import { BaseModelColumnTypes, DefaultQueryTypeOptions, FindEachOpts, QueryWithJoinedAssociationsType, QueryWithJoinedAssociationsTypeAndNoPreload } from './types/query.js';
16
+ import { BaseModelColumnTypes, DefaultQueryTypeOptions, FindEachOpts, PaginatedDreamQueryOptions, PaginatedDreamQueryResult, QueryWithJoinedAssociationsType, QueryWithJoinedAssociationsTypeAndNoPreload } from './types/query.js';
17
17
  import { ValidationStatement, ValidationType } from './types/validation.js';
18
18
  import { JoinedAssociation, JoinedAssociationsTypeFromAssociations, RequiredOnClauseKeys, VariadicJoinsArgs, VariadicLeftJoinLoadArgs, VariadicLoadArgs } from './types/variadic.js';
19
19
  export default class Dream {
@@ -434,6 +434,34 @@ export default class Dream {
434
434
  static all<T extends typeof Dream>(this: T, options?: {
435
435
  columns?: DreamColumnNames<InstanceType<T>>[];
436
436
  }): Promise<InstanceType<T>[]>;
437
+ /**
438
+ * Paginates the results of your query, accepting a pageSize and page argument,
439
+ * which it uses to segment your query into pages, leveraging limit and offset
440
+ * to deliver your query to you in pages.
441
+ *
442
+ * ```ts
443
+ * const paginated = await User.paginate({ pageSize: 100, page: 2 })
444
+ * paginated.results
445
+ * // [ { User{id: 101}, User{id: 102}, ...}]
446
+ *
447
+ * paginated.recordCount
448
+ * // 350
449
+ *
450
+ * paginated.pageCount
451
+ * // 4
452
+ *
453
+ * paginated.currentPage
454
+ * // 2
455
+ * ```
456
+ *
457
+ * @param opts.page - the page number that you want to fetch results for
458
+ * @param opts.pageSize - the number of results per page (optional)
459
+ * @returns results.recordCount - A number representing the total number of records matching your query
460
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
461
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
462
+ * @returns results.results - An array of records matching the current record
463
+ */
464
+ static paginate<T extends typeof Dream>(this: T, opts: PaginatedDreamQueryOptions): Promise<PaginatedDreamQueryResult<InstanceType<T>>>;
437
465
  /**
438
466
  * Forces use of a database connection (e.g. 'primary') during the query.
439
467
  *
@@ -3,7 +3,7 @@ import Dream from '../Dream.js';
3
3
  import { PassthroughOnClause, WhereStatement } from '../types/associations/shared.js';
4
4
  import { AssociationTableNames } from '../types/db.js';
5
5
  import { CreateOrFindByExtraOpts, DefaultScopeName, DreamColumnNames, OrderDir, PassthroughColumnNames, PluckEachArgs, PrimaryKeyForFind, TableColumnNames, UpdateableProperties, UpdateablePropertiesForClass, UpdateOrCreateByExtraOpts } from '../types/dream.js';
6
- import { BaseModelColumnTypes, FindEachOpts, QueryWithJoinedAssociationsType, QueryWithJoinedAssociationsTypeAndNoPreload } from '../types/query.js';
6
+ import { BaseModelColumnTypes, FindEachOpts, PaginatedDreamQueryOptions, PaginatedDreamQueryResult, QueryWithJoinedAssociationsType, QueryWithJoinedAssociationsTypeAndNoPreload } from '../types/query.js';
7
7
  import { JoinedAssociation, JoinedAssociationsTypeFromAssociations, VariadicJoinsArgs, VariadicLeftJoinLoadArgs, VariadicLoadArgs } from '../types/variadic.js';
8
8
  import DreamTransaction from './DreamTransaction.js';
9
9
  import Query from './Query.js';
@@ -37,6 +37,36 @@ export default class DreamClassTransactionBuilder<DreamClass extends typeof Drea
37
37
  all<I extends DreamClassTransactionBuilder<DreamClass, DreamInstance>>(this: I, options?: {
38
38
  columns?: DreamColumnNames<DreamInstance>[];
39
39
  }): Promise<DreamInstance[]>;
40
+ /**
41
+ * Paginates the results of your query, accepting a pageSize and page argument,
42
+ * which it uses to segment your query into pages, leveraging limit and offset
43
+ * to deliver your query to you in pages.
44
+ *
45
+ * ```ts
46
+ * await ApplicationModel.transaction(async txn => {
47
+ * const paginated = await User.txn(txn).paginate({ pageSize: 100, page: 2 })
48
+ * paginated.results
49
+ * // [ { User{id: 101}, User{id: 102}, ...}]
50
+ *
51
+ * paginated.recordCount
52
+ * // 350
53
+ *
54
+ * paginated.pageCount
55
+ * // 4
56
+ *
57
+ * paginated.currentPage
58
+ * // 2
59
+ * })
60
+ * ```
61
+ *
62
+ * @param opts.page - the page number that you want to fetch results for
63
+ * @param opts.pageSize - the number of results per page (optional)
64
+ * @returns results.recordCount - A number representing the total number of records matching your query
65
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
66
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
67
+ * @returns results.results - An array of records matching the current record
68
+ */
69
+ paginate<I extends DreamClassTransactionBuilder<DreamClass, DreamInstance>>(this: I, opts: PaginatedDreamQueryOptions): Promise<PaginatedDreamQueryResult<DreamInstance>>;
40
70
  /**
41
71
  * Retrieves the number of records corresponding
42
72
  * to this model.
@@ -4,7 +4,7 @@ import Dream from '../Dream.js';
4
4
  import { ColumnNamesAccountingForJoinedAssociations, LimitStatement, OffsetStatement, OrderQueryStatement, PassthroughOnClause, WhereStatement, WhereStatementForJoinedAssociation } from '../types/associations/shared.js';
5
5
  import { DbConnectionType } from '../types/db.js';
6
6
  import { AllDefaultScopeNames, DefaultScopeName, DreamColumnNames, DreamTableSchema, OrderDir, PassthroughColumnNames, PluckEachArgs, PrimaryKeyForFind, RelaxedJoinAndStatement, RelaxedJoinStatement, RelaxedPreloadOnStatement, RelaxedPreloadStatement, TableColumnNames, TableOrAssociationName } from '../types/dream.js';
7
- import { DefaultQueryTypeOptions, ExtendQueryType, NamespacedOrBaseModelColumnTypes, QueryToKyselyDBType, QueryToKyselyTableNamesType } from '../types/query.js';
7
+ import { DefaultQueryTypeOptions, ExtendQueryType, NamespacedOrBaseModelColumnTypes, PaginatedDreamQueryOptions, PaginatedDreamQueryResult, QueryToKyselyDBType, QueryToKyselyTableNamesType } from '../types/query.js';
8
8
  import { JoinedAssociation, JoinedAssociationsTypeFromAssociations, QueryTypeOptions, VariadicJoinsArgs, VariadicLeftJoinLoadArgs, VariadicLoadArgs } from '../types/variadic.js';
9
9
  import DreamTransaction from './DreamTransaction.js';
10
10
  export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Readonly<QueryTypeOptions> = DefaultQueryTypeOptions<DreamInstance>> extends ConnectedToDB<DreamInstance> {
@@ -774,6 +774,34 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
774
774
  all(options?: {
775
775
  columns?: DreamColumnNames<DreamInstance>[];
776
776
  }): Promise<DreamInstance[]>;
777
+ /**
778
+ * Paginates the results of your query, accepting a pageSize and page argument,
779
+ * which it uses to segment your query into pages, leveraging limit and offset
780
+ * to deliver your query to you in pages.
781
+ *
782
+ * ```ts
783
+ * const paginated = await User.order('email').paginate({ pageSize: 100, page: 2 })
784
+ * paginated.results
785
+ * // [ { User{id: 101}, User{id: 102}, ...}]
786
+ *
787
+ * paginated.recordCount
788
+ * // 350
789
+ *
790
+ * paginated.pageCount
791
+ * // 4
792
+ *
793
+ * paginated.currentPage
794
+ * // 2
795
+ * ```
796
+ *
797
+ * @param opts.page - the page number that you want to fetch results for
798
+ * @param opts.pageSize - the number of results per page (optional)
799
+ * @returns results.recordCount - A number representing the total number of records matching your query
800
+ * @returns results.pageCount - The number of pages needed to encapsulate all the matching records
801
+ * @returns results.currentPage - The current page (same as what is provided in the paginate args)
802
+ * @returns results.results - An array of records matching the current record
803
+ */
804
+ paginate(opts: PaginatedDreamQueryOptions): Promise<PaginatedDreamQueryResult<DreamInstance>>;
777
805
  /**
778
806
  * Forces use of a database connection (e.g. 'primary') during the query.
779
807
  *
@@ -0,0 +1 @@
1
+ export default function computedPaginatePage(page: number | undefined | null): number;
@@ -64,6 +64,8 @@ export default class DreamApp {
64
64
  get parallelTests(): number | undefined;
65
65
  private _unicodeNormalization;
66
66
  get unicodeNormalization(): UnicodeNormalizationForm;
67
+ private _paginationPageSize;
68
+ get paginationPageSize(): number;
67
69
  private _primaryKeyType;
68
70
  get primaryKeyType(): "bigint" | "integer" | "bigserial" | "uuid";
69
71
  private _projectRoot;
@@ -88,7 +90,7 @@ export default class DreamApp {
88
90
  get parallelDatabasesEnabled(): boolean;
89
91
  load<RT extends 'models' | 'serializers'>(resourceType: RT, resourcePath: string, importCb: (path: string) => Promise<any>): Promise<void>;
90
92
  plugin(cb: (app: DreamApp) => void | Promise<void>): void;
91
- set<ApplyOpt extends DreamAppSetOption>(applyOption: ApplyOpt, options: ApplyOpt extends 'db' ? DreamDbCredentialOptions : ApplyOpt extends 'encryption' ? DreamAppEncryptionOptions : ApplyOpt extends 'primaryKeyType' ? (typeof primaryKeyTypes)[number] : ApplyOpt extends 'logger' ? DreamLogger : ApplyOpt extends 'projectRoot' ? string : ApplyOpt extends 'inflections' ? () => void | Promise<void> : ApplyOpt extends 'paths' ? DreamDirectoryPaths : ApplyOpt extends 'parallelTests' ? number : ApplyOpt extends 'unicodeNormalization' ? UnicodeNormalizationForm : never): void;
93
+ set<ApplyOpt extends DreamAppSetOption>(applyOption: ApplyOpt, options: ApplyOpt extends 'db' ? DreamDbCredentialOptions : ApplyOpt extends 'encryption' ? DreamAppEncryptionOptions : ApplyOpt extends 'primaryKeyType' ? (typeof primaryKeyTypes)[number] : ApplyOpt extends 'logger' ? DreamLogger : ApplyOpt extends 'projectRoot' ? string : ApplyOpt extends 'inflections' ? () => void | Promise<void> : ApplyOpt extends 'paths' ? DreamDirectoryPaths : ApplyOpt extends 'parallelTests' ? number : ApplyOpt extends 'unicodeNormalization' ? UnicodeNormalizationForm : ApplyOpt extends 'paginationPageSize' ? number : never): void;
92
94
  on<T extends DreamHookEventType>(hookEventType: T, cb: T extends 'db:log' ? (event: KyselyLogEvent) => void : T extends 'repl:start' ? (context: Context) => void | Promise<void> : never): void;
93
95
  }
94
96
  export type DreamHookEventType = 'db:log' | 'repl:start';
@@ -101,7 +103,7 @@ export interface DreamAppOpts {
101
103
  serializerCasing?: DreamSerializerCasing;
102
104
  parallelTests: number | undefined;
103
105
  }
104
- export type DreamAppSetOption = 'db' | 'encryption' | 'inflections' | 'logger' | 'paths' | 'primaryKeyType' | 'projectRoot' | 'serializerCasing' | 'parallelTests' | 'unicodeNormalization';
106
+ export type DreamAppSetOption = 'db' | 'encryption' | 'inflections' | 'logger' | 'paths' | 'primaryKeyType' | 'projectRoot' | 'serializerCasing' | 'parallelTests' | 'unicodeNormalization' | 'paginationPageSize';
105
107
  export interface DreamDirectoryPaths {
106
108
  models?: string;
107
109
  serializers?: string;
@@ -0,0 +1,3 @@
1
+ export default class CannotPaginateWithLimit extends Error {
2
+ get message(): string;
3
+ }
@@ -0,0 +1,3 @@
1
+ export default class CannotPaginateWithOffset extends Error {
2
+ get message(): string;
3
+ }
@@ -54,4 +54,32 @@ export type QueryToKyselyAliasMap<Q extends Query<any, any>, DreamInstance exten
54
54
  alias: Key;
55
55
  }>['table']]>;
56
56
  } : null> = AliasToDbMaps;
57
+ export interface PaginatedDreamQueryOptions {
58
+ /**
59
+ * the number of records you would like to be returned in each page
60
+ */
61
+ pageSize?: number;
62
+ /**
63
+ * the current page
64
+ */
65
+ page: number | null | undefined;
66
+ }
67
+ export interface PaginatedDreamQueryResult<T extends Dream> {
68
+ /**
69
+ * the total number of records in the DB matching the query
70
+ */
71
+ recordCount: number;
72
+ /**
73
+ * The number of pages that are needed to encapsulate these results
74
+ */
75
+ pageCount: number;
76
+ /**
77
+ * The current page
78
+ */
79
+ currentPage: number;
80
+ /**
81
+ * The results for the current page
82
+ */
83
+ results: T[];
84
+ }
57
85
  export {};