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