s3db.js 11.2.0 → 11.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "s3db.js",
3
- "version": "11.2.0",
3
+ "version": "11.2.2",
4
4
  "description": "Use AWS S3, the world's most reliable document storage, as a database with this ORM.",
5
5
  "main": "dist/s3db.cjs.js",
6
6
  "module": "dist/s3db.es.js",
@@ -142,10 +142,7 @@
142
142
  "test:full": "pnpm run test:js && pnpm run test:ts",
143
143
  "benchmark": "node benchmark-compression.js",
144
144
  "benchmark:partitions": "node docs/benchmarks/partitions-matrix.js",
145
- "version": "echo 'Use pnpm run release v<version> instead of npm version'",
146
145
  "release:check": "./scripts/pre-release-check.sh",
147
- "release:prepare": "pnpm run build:binaries && echo 'Binaries ready for GitHub release'",
148
- "release": "./scripts/release.sh",
149
146
  "validate:types": "pnpm run test:ts && echo 'TypeScript definitions are valid!'",
150
147
  "test:ts:runtime": "tsx tests/typescript/types-runtime-simple.ts"
151
148
  }
@@ -47,9 +47,12 @@ export function createConfig(options, detectedTimezone) {
47
47
  autoConsolidate: consolidation.auto !== false,
48
48
  mode: consolidation.mode || 'async',
49
49
 
50
- // ✅ NOVO: Performance tuning - Mark applied concurrency (default 50, antes era 10 hardcoded)
50
+ // ✅ Performance tuning - Mark applied concurrency (default 50, up from 10)
51
51
  markAppliedConcurrency: consolidation.markAppliedConcurrency ?? 50,
52
52
 
53
+ // ✅ Performance tuning - Recalculate concurrency (default 50, up from 10)
54
+ recalculateConcurrency: consolidation.recalculateConcurrency ?? 50,
55
+
53
56
  // Late arrivals
54
57
  lateArrivalStrategy: lateArrivals.strategy || 'warn',
55
58
 
@@ -6,7 +6,7 @@
6
6
  import tryFn from "../../concerns/try-fn.js";
7
7
  import { PromisePool } from "@supercharge/promise-pool";
8
8
  import { idGenerator } from "../../concerns/id.js";
9
- import { getCohortInfo, createSyntheticSetTransaction } from "./utils.js";
9
+ import { getCohortInfo, createSyntheticSetTransaction, ensureCohortHour } from "./utils.js";
10
10
 
11
11
  /**
12
12
  * Start consolidation timer for a handler
@@ -612,12 +612,43 @@ export async function consolidateRecord(
612
612
  .for(transactionsToUpdate)
613
613
  .withConcurrency(markAppliedConcurrency) // ✅ Configurável e maior!
614
614
  .process(async (txn) => {
615
+ // ✅ FIX BUG #3: Ensure cohort fields exist before marking as applied
616
+ // This handles legacy transactions missing cohortHour, cohortDate, etc.
617
+ const txnWithCohorts = ensureCohortHour(txn, config.cohort.timezone, false);
618
+
619
+ // Build update data with applied flag
620
+ const updateData = { applied: true };
621
+
622
+ // Add missing cohort fields if they were calculated
623
+ if (txnWithCohorts.cohortHour && !txn.cohortHour) {
624
+ updateData.cohortHour = txnWithCohorts.cohortHour;
625
+ }
626
+ if (txnWithCohorts.cohortDate && !txn.cohortDate) {
627
+ updateData.cohortDate = txnWithCohorts.cohortDate;
628
+ }
629
+ if (txnWithCohorts.cohortWeek && !txn.cohortWeek) {
630
+ updateData.cohortWeek = txnWithCohorts.cohortWeek;
631
+ }
632
+ if (txnWithCohorts.cohortMonth && !txn.cohortMonth) {
633
+ updateData.cohortMonth = txnWithCohorts.cohortMonth;
634
+ }
635
+
636
+ // Handle null value field (legacy data might have null)
637
+ if (txn.value === null || txn.value === undefined) {
638
+ updateData.value = 1; // Default to 1 for backward compatibility
639
+ }
640
+
615
641
  const [ok, err] = await tryFn(() =>
616
- transactionResource.update(txn.id, { applied: true })
642
+ transactionResource.update(txn.id, updateData)
617
643
  );
618
644
 
619
645
  if (!ok && config.verbose) {
620
- console.warn(`[EventualConsistency] Failed to mark transaction ${txn.id} as applied:`, err?.message);
646
+ console.warn(
647
+ `[EventualConsistency] Failed to mark transaction ${txn.id} as applied:`,
648
+ err?.message,
649
+ 'Update data:',
650
+ updateData
651
+ );
621
652
  }
622
653
 
623
654
  return ok;
@@ -917,9 +948,12 @@ export async function recalculateRecord(
917
948
  // Exclude anchor transactions (they should always be applied)
918
949
  const transactionsToReset = allTransactions.filter(txn => txn.source !== 'anchor');
919
950
 
951
+ // ✅ OPTIMIZATION: Use higher concurrency for recalculate (default 50 vs 10)
952
+ const recalculateConcurrency = config.recalculateConcurrency || 50;
953
+
920
954
  const { results, errors } = await PromisePool
921
955
  .for(transactionsToReset)
922
- .withConcurrency(10)
956
+ .withConcurrency(recalculateConcurrency)
923
957
  .process(async (txn) => {
924
958
  const [ok, err] = await tryFn(() =>
925
959
  transactionResource.update(txn.id, { applied: false })
@@ -173,6 +173,28 @@ async function createAnalyticsResource(handler, database, resourceName, fieldNam
173
173
  },
174
174
  behavior: 'body-overflow',
175
175
  timestamps: false,
176
+ asyncPartitions: true,
177
+ // ✅ Multi-attribute partitions for optimal analytics query performance
178
+ partitions: {
179
+ // Query by period (hour/day/week/month)
180
+ byPeriod: {
181
+ fields: { period: 'string' }
182
+ },
183
+ // Query by period + cohort (e.g., all hour records for specific hours)
184
+ byPeriodCohort: {
185
+ fields: {
186
+ period: 'string',
187
+ cohort: 'string'
188
+ }
189
+ },
190
+ // Query by field + period (e.g., all daily analytics for clicks field)
191
+ byFieldPeriod: {
192
+ fields: {
193
+ field: 'string',
194
+ period: 'string'
195
+ }
196
+ }
197
+ },
176
198
  createdBy: 'EventualConsistencyPlugin'
177
199
  })
178
200
  );