@contentrain/query 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,9 +1,25 @@
1
1
  import { readFile, readdir } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { lru } from 'tiny-lru';
4
+ import { env } from 'node:process';
4
5
 
5
6
  var __defProp = Object.defineProperty;
6
7
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ var isDevelopment = env.NODE_ENV === "development";
9
+ var logger = {
10
+ debug: /* @__PURE__ */ __name((...args) => {
11
+ if (isDevelopment) {
12
+ console.log(...args);
13
+ }
14
+ }, "debug"),
15
+ error: /* @__PURE__ */ __name((...args) => {
16
+ if (isDevelopment) {
17
+ console.error(...args);
18
+ }
19
+ }, "error")
20
+ };
21
+
22
+ // src/cache/memory.ts
7
23
  var _MemoryCache = class _MemoryCache {
8
24
  constructor(options = {}) {
9
25
  this.stats = {
@@ -27,6 +43,10 @@ var _MemoryCache = class _MemoryCache {
27
43
  return new TextEncoder().encode(str).length;
28
44
  }
29
45
  async set(key, data, ttl) {
46
+ logger.debug("Saving data to cache:", {
47
+ key,
48
+ ttl
49
+ });
30
50
  await this.cleanupCache();
31
51
  const size = this.calculateSize(data);
32
52
  const now = Date.now();
@@ -49,6 +69,10 @@ var _MemoryCache = class _MemoryCache {
49
69
  }
50
70
  this.cache.set(key, entry);
51
71
  this.stats.size += size;
72
+ logger.debug("Data saved to cache:", {
73
+ key,
74
+ expiry: expireAt ? new Date(expireAt).toISOString() : "no expiry"
75
+ });
52
76
  }
53
77
  findOldestKey() {
54
78
  let oldestKey = null;
@@ -63,8 +87,10 @@ var _MemoryCache = class _MemoryCache {
63
87
  return oldestKey;
64
88
  }
65
89
  async get(key) {
90
+ logger.debug("Getting data from cache:", { key });
66
91
  const entry = this.cache.get(key);
67
92
  if (!entry) {
93
+ logger.debug("Data not found in cache:", { key });
68
94
  this.stats.misses++;
69
95
  return null;
70
96
  }
@@ -73,17 +99,24 @@ var _MemoryCache = class _MemoryCache {
73
99
  this.stats.misses++;
74
100
  return null;
75
101
  }
102
+ logger.debug("Data retrieved from cache:", {
103
+ key,
104
+ expiry: entry.expireAt ? new Date(entry.expireAt).toISOString() : "no expiry"
105
+ });
76
106
  this.stats.hits++;
77
107
  return entry.data;
78
108
  }
79
109
  async delete(key) {
110
+ logger.debug("Deleting data from cache:", { key });
80
111
  const entry = this.cache.get(key);
81
112
  if (entry) {
82
113
  this.stats.size -= entry.size;
83
114
  this.cache.delete(key);
84
115
  }
116
+ logger.debug("Data deleted from cache:", { key });
85
117
  }
86
118
  async clear() {
119
+ logger.debug("Clearing cache");
87
120
  this.cache.clear();
88
121
  this.stats = {
89
122
  hits: 0,
@@ -91,6 +124,7 @@ var _MemoryCache = class _MemoryCache {
91
124
  size: 0,
92
125
  lastCleanup: Date.now()
93
126
  };
127
+ logger.debug("Cache cleared");
94
128
  }
95
129
  async cleanupCache() {
96
130
  const now = Date.now();
@@ -133,7 +167,7 @@ var _ContentLoader = class _ContentLoader {
133
167
  defaultLocale: "en",
134
168
  cache: true,
135
169
  ttl: 60 * 1e3,
136
- // 1 dakika
170
+ // 1 minute
137
171
  maxCacheSize: 100,
138
172
  // 100 MB
139
173
  ...options
@@ -167,6 +201,10 @@ var _ContentLoader = class _ContentLoader {
167
201
  const allMetadata = JSON.parse(metadataContent);
168
202
  const modelMetadata = allMetadata.find((m) => m.modelId === model);
169
203
  if (!modelMetadata) {
204
+ logger.error("Model metadata not found:", {
205
+ model,
206
+ metadataPath
207
+ });
170
208
  throw new Error(`Model metadata not found for ${model}`);
171
209
  }
172
210
  const modelPath = join(this.options.contentDir, "models", `${model}.json`);
@@ -177,6 +215,10 @@ var _ContentLoader = class _ContentLoader {
177
215
  fields: modelFields
178
216
  };
179
217
  } catch (error) {
218
+ logger.error("Failed to load model config:", {
219
+ model,
220
+ error: error?.message || "Unknown error"
221
+ });
180
222
  throw new Error(`Failed to load model config for ${model}: ${error?.message || "Unknown error"}`);
181
223
  }
182
224
  }
@@ -187,6 +229,9 @@ var _ContentLoader = class _ContentLoader {
187
229
  if (modelConfig.metadata.localization) {
188
230
  if (!locale || locale === "default") {
189
231
  if (!this.options.defaultLocale) {
232
+ logger.error("Default locale is required for localized model:", {
233
+ model
234
+ });
190
235
  throw new Error(`Default locale is required for localized model "${model}"`);
191
236
  }
192
237
  locale = this.options.defaultLocale;
@@ -207,10 +252,19 @@ var _ContentLoader = class _ContentLoader {
207
252
  data
208
253
  };
209
254
  } catch {
255
+ logger.error("Failed to load content:", {
256
+ model,
257
+ locale,
258
+ contentPath
259
+ });
210
260
  throw new Error(`Failed to load content: Invalid JSON format in ${contentPath}`);
211
261
  }
212
262
  } catch (error) {
213
263
  if (error.message.includes("Invalid JSON format")) {
264
+ logger.error("Failed to load content:", {
265
+ model,
266
+ locale
267
+ });
214
268
  throw error;
215
269
  }
216
270
  throw new Error(
@@ -295,7 +349,7 @@ var _ContentLoader = class _ContentLoader {
295
349
  const file = await this.loadContentFile(model);
296
350
  content.default = file.data;
297
351
  }
298
- let assets;
352
+ let assets = [];
299
353
  try {
300
354
  const assetsPath = join(this.options.contentDir, "assets.json");
301
355
  const assetsContent = await readFile(assetsPath, "utf-8");
@@ -316,19 +370,65 @@ var _ContentLoader = class _ContentLoader {
316
370
  }
317
371
  async resolveRelation(model, relationField, data, locale) {
318
372
  try {
373
+ logger.debug("Debug - Starting relation resolution:", {
374
+ model,
375
+ relationField,
376
+ dataLength: data.length,
377
+ locale
378
+ });
319
379
  const relations = this.relations.get(model);
380
+ logger.debug("Debug - Relations:", relations);
320
381
  if (!relations)
321
382
  throw new Error(`No relations found for model: ${model}`);
322
383
  const relation = relations.find((r) => r.foreignKey === relationField);
384
+ logger.debug("Debug - Found relation:", relation);
323
385
  if (!relation)
324
386
  throw new Error(`No relation found for field: ${String(relationField)}`);
387
+ logger.debug("Debug - Related model loading:", relation.model);
325
388
  const relatedContent = await this.load(relation.model);
326
- const relatedData = locale ? relatedContent.content[locale] : relatedContent.content.en;
389
+ logger.debug("Debug - \u0130li\u015Fkili model y\xFCklendi:", {
390
+ model: relation.model,
391
+ metadata: relatedContent.model.metadata,
392
+ contentKeys: Object.keys(relatedContent.content)
393
+ });
394
+ let relatedData;
395
+ if (relatedContent.model.metadata.localization) {
396
+ logger.debug("Debug - Processing localized model");
397
+ const localizedContent = locale ? relatedContent.content[locale] : relatedContent.content.en;
398
+ logger.debug("Debug - Localized content:", {
399
+ locale: locale || "en",
400
+ contentType: typeof localizedContent,
401
+ isArray: Array.isArray(localizedContent)
402
+ });
403
+ if (!Array.isArray(localizedContent)) {
404
+ throw new TypeError(`Invalid content format for localized model ${relation.model}`);
405
+ }
406
+ relatedData = localizedContent;
407
+ } else {
408
+ logger.debug("Debug - Processing non-localized model");
409
+ const nonLocalizedContent = relatedContent.content.default;
410
+ logger.debug("Debug - Raw content:", {
411
+ contentType: typeof nonLocalizedContent,
412
+ isArray: Array.isArray(nonLocalizedContent),
413
+ content: nonLocalizedContent
414
+ });
415
+ if (!Array.isArray(nonLocalizedContent)) {
416
+ throw new TypeError(`Invalid content format for non-localized model ${relation.model}`);
417
+ }
418
+ relatedData = nonLocalizedContent;
419
+ }
420
+ logger.debug("Debug - Related data ready:", {
421
+ dataLength: relatedData.length,
422
+ firstItem: relatedData[0]
423
+ });
327
424
  if (!relatedData) {
328
425
  throw new Error(`Failed to resolve relation: No data found for model ${relation.model}`);
329
426
  }
330
427
  if (relation.type === "one-to-one") {
331
- return data.map((item) => {
428
+ logger.debug("Debug - Processing one-to-one relation");
429
+ const itemsWithRelation = data.filter((item) => item[relationField] !== void 0);
430
+ logger.debug("Debug - Items with relations:", itemsWithRelation.length);
431
+ return itemsWithRelation.map((item) => {
332
432
  const relatedItem = relatedData.find((r) => r.ID === item[relationField]);
333
433
  if (!relatedItem) {
334
434
  throw new Error(`Failed to resolve relation: No matching item found for ID ${String(item[relationField])}`);
@@ -336,18 +436,22 @@ var _ContentLoader = class _ContentLoader {
336
436
  return relatedItem;
337
437
  });
338
438
  } else {
439
+ logger.debug("Debug - Processing one-to-many relation");
339
440
  const uniqueIds = new Set(
340
441
  data.flatMap(
341
- (item) => Array.isArray(item[relationField]) ? item[relationField] : [item[relationField]]
442
+ (item) => item[relationField] !== void 0 ? Array.isArray(item[relationField]) ? item[relationField] : [item[relationField]] : []
342
443
  )
343
444
  );
445
+ logger.debug("Debug - Unique IDs:", Array.from(uniqueIds));
344
446
  const items = Array.from(uniqueIds).map((id) => relatedData.find((r) => r.ID === id)).filter(Boolean);
447
+ logger.debug("Debug - Matching items:", items.length);
345
448
  if (items.length !== uniqueIds.size) {
346
449
  throw new Error("Failed to resolve relation: Some related items not found");
347
450
  }
348
451
  return items;
349
452
  }
350
453
  } catch (error) {
454
+ logger.error("Debug - Error occurred:", error);
351
455
  throw new Error(`Failed to resolve relation: ${error.message}`);
352
456
  }
353
457
  }
@@ -368,6 +472,11 @@ var _ContentrainQueryBuilder = class _ContentrainQueryBuilder {
368
472
  this.loader = loader;
369
473
  }
370
474
  where(field, operator, value) {
475
+ logger.debug("Adding filter:", {
476
+ field,
477
+ operator,
478
+ value
479
+ });
371
480
  this.filters.push({
372
481
  field,
373
482
  operator,
@@ -376,6 +485,7 @@ var _ContentrainQueryBuilder = class _ContentrainQueryBuilder {
376
485
  return this;
377
486
  }
378
487
  include(relation) {
488
+ logger.debug("Adding relation:", relation);
379
489
  if (typeof relation === "string") {
380
490
  this.includes[relation] = {};
381
491
  } else if (Array.isArray(relation)) {
@@ -386,6 +496,10 @@ var _ContentrainQueryBuilder = class _ContentrainQueryBuilder {
386
496
  return this;
387
497
  }
388
498
  orderBy(field, direction = "asc") {
499
+ logger.debug("Adding sorting:", {
500
+ field,
501
+ direction
502
+ });
389
503
  this.sorting.push({
390
504
  field,
391
505
  direction
@@ -393,28 +507,37 @@ var _ContentrainQueryBuilder = class _ContentrainQueryBuilder {
393
507
  return this;
394
508
  }
395
509
  limit(count) {
510
+ logger.debug("Adding limit:", count);
396
511
  this.pagination.limit = count;
397
512
  return this;
398
513
  }
399
514
  offset(count) {
515
+ logger.debug("Adding offset:", count);
400
516
  this.pagination.offset = count;
401
517
  return this;
402
518
  }
403
519
  locale(code) {
520
+ logger.debug("Setting locale:", code);
404
521
  this.options.locale = code;
405
522
  return this;
406
523
  }
407
524
  cache(ttl) {
525
+ logger.debug("Setting cache:", {
526
+ enabled: true,
527
+ ttl
528
+ });
408
529
  this.options.cache = true;
409
530
  if (ttl)
410
531
  this.options.ttl = ttl;
411
532
  return this;
412
533
  }
413
534
  noCache() {
535
+ logger.debug("Disabling cache");
414
536
  this.options.cache = false;
415
537
  return this;
416
538
  }
417
539
  bypassCache() {
540
+ logger.debug("Bypassing cache");
418
541
  this.options.cache = false;
419
542
  this.options.ttl = 0;
420
543
  return this;
@@ -430,21 +553,56 @@ var _ContentrainQueryBuilder = class _ContentrainQueryBuilder {
430
553
  };
431
554
  }
432
555
  async get() {
556
+ logger.debug("Starting query:", {
557
+ model: this.model,
558
+ filterCount: this.filters.length,
559
+ includeCount: Object.keys(this.includes).length,
560
+ sortingCount: this.sorting.length,
561
+ pagination: this.pagination,
562
+ options: this.options
563
+ });
433
564
  const result = await this.loader.load(this.model);
434
565
  const modelConfig = result.model;
566
+ logger.debug("Model loaded:", {
567
+ model: this.model,
568
+ metadata: modelConfig.metadata,
569
+ contentKeys: Object.keys(result.content)
570
+ });
435
571
  let data;
436
572
  if (modelConfig.metadata.localization) {
437
573
  const locale = this.options.locale || "en";
574
+ logger.debug("Selecting content for localized model:", {
575
+ model: this.model,
576
+ requestedLocale: locale,
577
+ availableLocales: Object.keys(result.content)
578
+ });
438
579
  data = result.content[locale];
439
580
  if (!data) {
581
+ logger.error("Content not found:", {
582
+ model: this.model,
583
+ locale,
584
+ availableLocales: Object.keys(result.content)
585
+ });
440
586
  throw new Error(`Content not found for locale: ${locale}`);
441
587
  }
442
588
  } else {
589
+ logger.debug("Selecting content for non-localized model:", {
590
+ model: this.model,
591
+ contentKeys: Object.keys(result.content)
592
+ });
443
593
  if (!result.content.default) {
594
+ logger.error("Content not found:", {
595
+ model: this.model,
596
+ contentKeys: Object.keys(result.content)
597
+ });
444
598
  throw new Error(`Content not found for model: ${this.model}`);
445
599
  }
446
600
  data = result.content.default;
447
601
  }
602
+ logger.debug("Executing query:", {
603
+ model: this.model,
604
+ dataLength: data.length
605
+ });
448
606
  return this.executor.execute({
449
607
  model: this.model,
450
608
  data,
@@ -473,11 +631,16 @@ var _QueryExecutor = class _QueryExecutor {
473
631
  this.loader = loader;
474
632
  }
475
633
  applyFilters(data, filters) {
476
- return data.filter((item) => {
634
+ logger.debug("Starting to apply filters:", {
635
+ dataLength: data.length,
636
+ filters
637
+ });
638
+ const result = data.filter((item) => {
477
639
  return filters.every(({ field, operator, value }) => {
478
640
  const itemValue = item[field];
479
641
  const validOperators = ["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin", "contains", "startsWith", "endsWith"];
480
642
  if (!validOperators.includes(operator)) {
643
+ logger.error("Invalid operator:", operator);
481
644
  throw new Error(`Invalid operator: ${operator}`);
482
645
  }
483
646
  if (typeof itemValue === "string" && typeof value === "string") {
@@ -490,6 +653,7 @@ var _QueryExecutor = class _QueryExecutor {
490
653
  case "nin":
491
654
  return !value.includes(itemValue);
492
655
  default:
656
+ logger.error("Invalid array operator:", operator);
493
657
  throw new Error(`Invalid array operator: ${operator}`);
494
658
  }
495
659
  }
@@ -500,6 +664,7 @@ var _QueryExecutor = class _QueryExecutor {
500
664
  case "nin":
501
665
  return !value.some((v) => itemValue.includes(v));
502
666
  default:
667
+ logger.error("Invalid array operator:", operator);
503
668
  throw new Error(`Invalid array operator: ${operator}`);
504
669
  }
505
670
  }
@@ -522,6 +687,11 @@ var _QueryExecutor = class _QueryExecutor {
522
687
  return false;
523
688
  });
524
689
  });
690
+ logger.debug("Filter application completed:", {
691
+ initialCount: data.length,
692
+ resultCount: result.length
693
+ });
694
+ return result;
525
695
  }
526
696
  applySorting(data, sorting) {
527
697
  return [...data].sort((a, b) => {
@@ -545,15 +715,26 @@ var _QueryExecutor = class _QueryExecutor {
545
715
  return data.slice(offset, offset + limit);
546
716
  }
547
717
  async resolveIncludes(model, data, includes, options) {
718
+ logger.debug("Starting to resolve relations:", {
719
+ model,
720
+ dataLength: data.length,
721
+ includes,
722
+ options
723
+ });
548
724
  const result = [...data];
549
725
  for (const [field, config] of Object.entries(includes)) {
726
+ logger.debug(`Resolving relation "${field}"`);
550
727
  const relations = await this.loader.resolveRelation(
551
728
  model,
552
729
  field,
553
730
  result,
554
731
  options.locale
555
732
  );
733
+ logger.debug(`Relation "${field}" resolved:`, {
734
+ foundRelationsCount: relations.length
735
+ });
556
736
  if (config.include && relations.length) {
737
+ logger.debug(`Resolving nested relations for "${field}":`, config.include);
557
738
  await this.resolveIncludes(
558
739
  field,
559
740
  relations,
@@ -574,6 +755,7 @@ var _QueryExecutor = class _QueryExecutor {
574
755
  }
575
756
  item._relations[field] = Array.isArray(value) ? relatedItems : relatedItems[0];
576
757
  });
758
+ logger.debug(`Data added for relation "${field}"`);
577
759
  }
578
760
  return result;
579
761
  }
@@ -604,17 +786,37 @@ var _QueryExecutor = class _QueryExecutor {
604
786
  pagination = {},
605
787
  options = {}
606
788
  }) {
789
+ logger.debug("Starting execution:", {
790
+ model,
791
+ dataLength: data.length,
792
+ filterCount: filters.length,
793
+ includeCount: Object.keys(includes).length,
794
+ sortingCount: sorting.length,
795
+ pagination,
796
+ options
797
+ });
607
798
  let result = [...data];
608
799
  if (filters.length) {
800
+ logger.debug("Applying filters:", filters);
609
801
  result = this.applyFilters(result, filters);
802
+ logger.debug("Remaining items after filtering:", result.length);
610
803
  }
611
804
  if (Object.keys(includes).length) {
805
+ logger.debug("Resolving relations:", includes);
612
806
  result = await this.resolveIncludes(model, result, includes, options);
807
+ logger.debug("Items after relation resolution:", result.length);
613
808
  }
614
809
  if (sorting.length) {
810
+ logger.debug("Applying sorting:", sorting);
615
811
  result = this.applySorting(result, sorting);
616
812
  }
617
813
  const paginatedData = this.applyPagination(result, pagination.limit, pagination.offset);
814
+ logger.debug("After pagination:", {
815
+ totalCount: result.length,
816
+ pageSize: paginatedData.length,
817
+ offset: pagination.offset || 0,
818
+ hasMore: (pagination.offset || 0) + paginatedData.length < result.length
819
+ });
618
820
  return {
619
821
  data: paginatedData,
620
822
  total: result.length,
@@ -658,6 +860,6 @@ var _ContentrainSDK = class _ContentrainSDK {
658
860
  __name(_ContentrainSDK, "ContentrainSDK");
659
861
  var ContentrainSDK = _ContentrainSDK;
660
862
 
661
- export { ContentLoader, ContentrainQueryBuilder, ContentrainSDK, MemoryCache, QueryExecutor };
863
+ export { ContentLoader, ContentrainQueryBuilder, ContentrainSDK, MemoryCache, QueryExecutor, logger };
662
864
  //# sourceMappingURL=index.mjs.map
663
865
  //# sourceMappingURL=index.mjs.map