@dcupl/common 1.11.10 → 2.0.0-beta.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/esm/attribute-dependency-graph.d.ts +119 -0
- package/dist/esm/cache.controller.d.ts +56 -1
- package/dist/esm/changeDetection.d.ts +1 -1
- package/dist/esm/date-utils.d.ts +50 -0
- package/dist/esm/deep-query.service.d.ts +133 -0
- package/dist/esm/dependency-graph.d.ts +102 -3
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +3096 -19
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/indices.controller.d.ts +92 -0
- package/dist/esm/logger/index.d.ts +2 -0
- package/dist/esm/logger/logger.d.ts +101 -0
- package/dist/esm/pivot.d.ts +2 -1
- package/dist/esm/query-builder.d.ts +435 -2
- package/dist/esm/queryData.d.ts +9 -4
- package/dist/esm/types/dcupl.types.d.ts +80 -0
- package/dist/esm/types/internal.types.d.ts +1 -1
- package/dist/esm/types/list.types.d.ts +10 -0
- package/dist/esm/types/model.types.d.ts +49 -12
- package/dist/esm/types/query.types.d.ts +500 -2
- package/dist/node/index.cjs +5 -0
- package/dist/node/index.cjs.map +1 -0
- package/package.json +7 -8
- package/dist/browser/common.umd.js +0 -2
- package/dist/browser/common.umd.js.map +0 -1
- package/dist/esm/analytics.controller.js +0 -105
- package/dist/esm/analytics.controller.js.map +0 -1
- package/dist/esm/cache.controller.js +0 -40
- package/dist/esm/cache.controller.js.map +0 -1
- package/dist/esm/changeDetection.js +0 -179
- package/dist/esm/changeDetection.js.map +0 -1
- package/dist/esm/computeSuggestions.js +0 -38
- package/dist/esm/computeSuggestions.js.map +0 -1
- package/dist/esm/dependency-graph.js +0 -136
- package/dist/esm/dependency-graph.js.map +0 -1
- package/dist/esm/getAggregation.js +0 -170
- package/dist/esm/getAggregation.js.map +0 -1
- package/dist/esm/getFacets.js +0 -67
- package/dist/esm/getFacets.js.map +0 -1
- package/dist/esm/helper.js +0 -102
- package/dist/esm/helper.js.map +0 -1
- package/dist/esm/indices.controller.js +0 -97
- package/dist/esm/indices.controller.js.map +0 -1
- package/dist/esm/object-hash.js +0 -33
- package/dist/esm/object-hash.js.map +0 -1
- package/dist/esm/performance.js +0 -33
- package/dist/esm/performance.js.map +0 -1
- package/dist/esm/pivot.js +0 -132
- package/dist/esm/pivot.js.map +0 -1
- package/dist/esm/property-parser.js +0 -57
- package/dist/esm/property-parser.js.map +0 -1
- package/dist/esm/query-builder.js +0 -233
- package/dist/esm/query-builder.js.map +0 -1
- package/dist/esm/query.helper.js +0 -172
- package/dist/esm/query.helper.js.map +0 -1
- package/dist/esm/queryData.js +0 -360
- package/dist/esm/queryData.js.map +0 -1
- package/dist/esm/script.controller.js +0 -54
- package/dist/esm/script.controller.js.map +0 -1
- package/dist/esm/template-parser.js +0 -22
- package/dist/esm/template-parser.js.map +0 -1
- package/dist/esm/types/aggregation.types.js +0 -2
- package/dist/esm/types/aggregation.types.js.map +0 -1
- package/dist/esm/types/app-loader.types.js +0 -2
- package/dist/esm/types/app-loader.types.js.map +0 -1
- package/dist/esm/types/data.types.js +0 -2
- package/dist/esm/types/data.types.js.map +0 -1
- package/dist/esm/types/dcupl.types.js +0 -2
- package/dist/esm/types/dcupl.types.js.map +0 -1
- package/dist/esm/types/facets.types.js +0 -2
- package/dist/esm/types/facets.types.js.map +0 -1
- package/dist/esm/types/filter.types.js +0 -2
- package/dist/esm/types/filter.types.js.map +0 -1
- package/dist/esm/types/group-by.types.js +0 -2
- package/dist/esm/types/group-by.types.js.map +0 -1
- package/dist/esm/types/index.js +0 -17
- package/dist/esm/types/index.js.map +0 -1
- package/dist/esm/types/internal.types.js +0 -2
- package/dist/esm/types/internal.types.js.map +0 -1
- package/dist/esm/types/list.types.js +0 -2
- package/dist/esm/types/list.types.js.map +0 -1
- package/dist/esm/types/model.types.js +0 -16
- package/dist/esm/types/model.types.js.map +0 -1
- package/dist/esm/types/projection.types.js +0 -2
- package/dist/esm/types/projection.types.js.map +0 -1
- package/dist/esm/types/quality.types.js +0 -2
- package/dist/esm/types/quality.types.js.map +0 -1
- package/dist/esm/types/query.types.js +0 -12
- package/dist/esm/types/query.types.js.map +0 -1
- package/dist/esm/types/section.types.js +0 -2
- package/dist/esm/types/section.types.js.map +0 -1
- package/dist/esm/types/suggestion.types.js +0 -2
- package/dist/esm/types/suggestion.types.js.map +0 -1
- package/dist/esm/types/testing.types.js +0 -2
- package/dist/esm/types/testing.types.js.map +0 -1
- package/dist/node/index.cjs.js +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export type AttributeNode = {
|
|
2
|
+
modelKey: string;
|
|
3
|
+
attributeKey: string;
|
|
4
|
+
type: 'property' | 'reference';
|
|
5
|
+
processingStep: 1 | 2 | 3 | 4;
|
|
6
|
+
};
|
|
7
|
+
export type AttributeNodeId = string;
|
|
8
|
+
export type ProcessingPlan = Map<string, Map<number, Set<string>>>;
|
|
9
|
+
/**
|
|
10
|
+
* AttributeDependencyGraph tracks attribute-level dependencies between models.
|
|
11
|
+
*
|
|
12
|
+
* This graph is item-agnostic: when ModelA.price depends on ModelB.cost,
|
|
13
|
+
* any change to ModelB.cost triggers reprocessing of ALL ModelA items
|
|
14
|
+
* that have the price derivation.
|
|
15
|
+
*
|
|
16
|
+
* The graph ensures:
|
|
17
|
+
* - Correct processing order based on dependencies
|
|
18
|
+
* - Impact analysis when attributes change
|
|
19
|
+
* - Efficient batch processing by grouping attributes by model and step
|
|
20
|
+
*/
|
|
21
|
+
export declare class AttributeDependencyGraph {
|
|
22
|
+
private graph;
|
|
23
|
+
private nodeIndex;
|
|
24
|
+
constructor();
|
|
25
|
+
/**
|
|
26
|
+
* Creates a unique ID for an attribute node
|
|
27
|
+
*/
|
|
28
|
+
private getNodeId;
|
|
29
|
+
/**
|
|
30
|
+
* Parses a node ID back into components
|
|
31
|
+
*/
|
|
32
|
+
private parseNodeId;
|
|
33
|
+
/**
|
|
34
|
+
* Adds an attribute node to the graph
|
|
35
|
+
*/
|
|
36
|
+
addAttribute(node: AttributeNode): void;
|
|
37
|
+
/**
|
|
38
|
+
* Adds a dependency between two attributes
|
|
39
|
+
* @param from - The dependent attribute (e.g., ModelA.derivedPrice)
|
|
40
|
+
* @param to - The source attribute it depends on (e.g., ModelB.baseCost)
|
|
41
|
+
*/
|
|
42
|
+
addAttributeDependency(from: AttributeNode, to: AttributeNode): void;
|
|
43
|
+
/**
|
|
44
|
+
* Gets all attributes impacted by changes to the given attributes
|
|
45
|
+
* @param changed - Array of changed attribute nodes
|
|
46
|
+
* @returns Array of all impacted attribute nodes (including the changed ones)
|
|
47
|
+
*/
|
|
48
|
+
getImpactedAttributes(changed: AttributeNode[]): AttributeNode[];
|
|
49
|
+
/**
|
|
50
|
+
* Generates a processing plan for the given attributes
|
|
51
|
+
* Groups attributes by model and processing step for efficient batch processing
|
|
52
|
+
*
|
|
53
|
+
* @param attributes - Array of attributes to process
|
|
54
|
+
* @returns Map<modelKey, Map<processingStep, Set<attributeKeys>>>
|
|
55
|
+
*/
|
|
56
|
+
getProcessingOrder(attributes: AttributeNode[]): ProcessingPlan;
|
|
57
|
+
/**
|
|
58
|
+
* Gets all attributes for a specific model
|
|
59
|
+
*/
|
|
60
|
+
getAttributesForModel(modelKey: string): AttributeNode[];
|
|
61
|
+
/**
|
|
62
|
+
* Gets dependencies for a specific attribute
|
|
63
|
+
*/
|
|
64
|
+
getDependencies(node: AttributeNode): AttributeNode[];
|
|
65
|
+
/**
|
|
66
|
+
* Gets dependents for a specific attribute (attributes that depend on this one)
|
|
67
|
+
*/
|
|
68
|
+
getDependents(node: AttributeNode): AttributeNode[];
|
|
69
|
+
/**
|
|
70
|
+
* Checks if an attribute has any dependencies
|
|
71
|
+
*/
|
|
72
|
+
hasDependencies(node: AttributeNode): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Checks if a node exists in the graph
|
|
75
|
+
*/
|
|
76
|
+
hasNode(nodeId: AttributeNodeId): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Gets all attribute nodes in the graph
|
|
79
|
+
*/
|
|
80
|
+
getAllAttributes(): AttributeNode[];
|
|
81
|
+
/**
|
|
82
|
+
* Gets the maximum dependency depth in the graph
|
|
83
|
+
* Useful for determining if full update might be more efficient
|
|
84
|
+
*/
|
|
85
|
+
getMaxDepth(): number;
|
|
86
|
+
/**
|
|
87
|
+
* Validates that all expected attributes are present in the graph.
|
|
88
|
+
* This helps catch silent failures during graph building where attributes
|
|
89
|
+
* with expressions or derivations might not be properly added.
|
|
90
|
+
*
|
|
91
|
+
* @param expectedAttributes - Map of modelKey to array of attribute keys that should exist
|
|
92
|
+
* @returns Object with validation result and any missing attributes
|
|
93
|
+
*/
|
|
94
|
+
validateCompleteness(expectedAttributes: Map<string, string[]>): {
|
|
95
|
+
isComplete: boolean;
|
|
96
|
+
missing: Array<{
|
|
97
|
+
modelKey: string;
|
|
98
|
+
attributeKey: string;
|
|
99
|
+
}>;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Clears the entire graph
|
|
103
|
+
*/
|
|
104
|
+
clear(): void;
|
|
105
|
+
/**
|
|
106
|
+
* Gets statistics about the graph
|
|
107
|
+
*/
|
|
108
|
+
getStats(): {
|
|
109
|
+
totalAttributes: number;
|
|
110
|
+
totalDependencies: number;
|
|
111
|
+
maxDepth: number;
|
|
112
|
+
attributesByModel: Map<string, number>;
|
|
113
|
+
attributesByStep: Map<number, number>;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Exports the graph to JSON for debugging
|
|
117
|
+
*/
|
|
118
|
+
toJSON(): any;
|
|
119
|
+
}
|
|
@@ -1,11 +1,66 @@
|
|
|
1
1
|
export declare class CacheController {
|
|
2
2
|
enabled: boolean;
|
|
3
3
|
private cache;
|
|
4
|
+
private cacheDependencies;
|
|
5
|
+
private hitCount;
|
|
6
|
+
private missCount;
|
|
7
|
+
private log;
|
|
4
8
|
constructor(enabled: boolean);
|
|
5
9
|
get(key: string, context: any): any;
|
|
6
|
-
set(key: string, context: any, value: any): void;
|
|
10
|
+
set(key: string, context: any, value: any, dependencies?: CacheDependencyInfo): void;
|
|
7
11
|
has(key: string, context: any): boolean;
|
|
8
12
|
clear(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Invalidates cache entries that depend on the specified models and attributes
|
|
15
|
+
* @param changedModels - Map of modelKey → Set of changed attributeKeys
|
|
16
|
+
*/
|
|
17
|
+
invalidateByDependencies(changedModels: Map<string, Set<string>>): void;
|
|
18
|
+
/**
|
|
19
|
+
* Invalidates all cache entries for specific models
|
|
20
|
+
* @param modelKeys - Array of model keys to invalidate
|
|
21
|
+
*/
|
|
22
|
+
invalidateByModels(modelKeys: string[]): void;
|
|
23
|
+
/**
|
|
24
|
+
* Invalidates cache entries by key prefix (e.g., 'query', 'facets')
|
|
25
|
+
* @param keyPrefix - The key prefix to match
|
|
26
|
+
*/
|
|
27
|
+
invalidateByKeyPrefix(keyPrefix: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Invalidates all cache entries for a specific model
|
|
30
|
+
* @param modelKey - The model key to invalidate
|
|
31
|
+
*/
|
|
32
|
+
invalidateForModel(modelKey: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Invalidates cache entries that depend on a specific attribute of a model
|
|
35
|
+
* @param modelKey - The model key
|
|
36
|
+
* @param attributeKey - The attribute key to invalidate
|
|
37
|
+
*/
|
|
38
|
+
invalidateForAttribute(modelKey: string, attributeKey: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Invalidates cache entries matching a custom predicate
|
|
41
|
+
* @param predicate - Function that returns true for cache keys to invalidate
|
|
42
|
+
*/
|
|
43
|
+
invalidateMatching(predicate: (key: string) => boolean): void;
|
|
9
44
|
generateContext(constext: any): any;
|
|
10
45
|
getCacheName(key: string, context: any): string;
|
|
46
|
+
/**
|
|
47
|
+
* Gets cache statistics including hit rate
|
|
48
|
+
*/
|
|
49
|
+
getStats(): {
|
|
50
|
+
size: number;
|
|
51
|
+
hitRate: number;
|
|
52
|
+
totalEntries: number;
|
|
53
|
+
entriesWithDependencies: number;
|
|
54
|
+
hits: number;
|
|
55
|
+
misses: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Information about which models and attributes a cache entry depends on
|
|
60
|
+
*/
|
|
61
|
+
export interface CacheDependencyInfo {
|
|
62
|
+
/** Set of model keys this cache entry depends on */
|
|
63
|
+
models: Set<string>;
|
|
64
|
+
/** Map of modelKey → Set of attribute keys (if specific attributes matter) */
|
|
65
|
+
modelAttributes: Map<string, Set<string>>;
|
|
11
66
|
}
|
|
@@ -2,7 +2,7 @@ import { CallbackFunction, DcuplInitOptions } from './types';
|
|
|
2
2
|
import { AnalyticsController } from './analytics.controller';
|
|
3
3
|
export type DcuplUpdateScope = 'all' | 'global' | 'list' | 'list$';
|
|
4
4
|
export type DcuplUpdateTrigger = 'user' | 'loader';
|
|
5
|
-
export type DcuplUpdateType = 'data_change' | 'dcupl_destroyed' | 'dcupl_handle_datacontainer' | 'dcupl_initialized' | 'dcupl_updated_manually' | 'filter_many' | 'filter_one' | 'fn_aggregate' | 'fn_facets' | 'fn_groupBy' | 'fn_metadata' | 'fn_pivot' | 'fn_suggest' | 'list_created' | 'list_destroyed' | 'list_updated' | 'loader_added' | 'loader_config_fetched' | 'loader_data_fetched' | 'loader_models_fetched' | 'loader_scripts_fetched' | 'loader_processed' | 'loader_removed' | 'model_add' | 'query_apply_options' | 'query_apply' | 'query_execute' | 'query_get' | 'query_has' | 'query_many' | 'query_one' | 'query_remove' | 'query_reset' | 'result_updated' | 'view_add';
|
|
5
|
+
export type DcuplUpdateType = 'data_change' | 'dcupl_destroyed' | 'dcupl_handle_datacontainer' | 'dcupl_initialized' | 'dcupl_updated_manually' | 'dcupl_partial_update' | 'filter_many' | 'filter_one' | 'fn_aggregate' | 'fn_facets' | 'fn_groupBy' | 'fn_metadata' | 'fn_pivot' | 'fn_suggest' | 'list_created' | 'list_destroyed' | 'list_updated' | 'loader_added' | 'loader_config_fetched' | 'loader_data_fetched' | 'loader_models_fetched' | 'loader_scripts_fetched' | 'loader_processed' | 'loader_removed' | 'model_add' | 'query_apply_options' | 'query_apply' | 'query_execute' | 'query_get' | 'query_has' | 'query_many' | 'query_one' | 'query_remove' | 'query_reset' | 'result_updated' | 'view_add';
|
|
6
6
|
export type DcuplUpdateAction = 'update';
|
|
7
7
|
export type DcuplUpdateMessage = {
|
|
8
8
|
key?: number;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom date utilities to replace date-fns
|
|
3
|
+
* Supports custom format patterns for date parsing
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check if a value is a Date instance
|
|
7
|
+
* @param value - Value to check
|
|
8
|
+
* @returns true if value is a Date instance (valid or invalid), false otherwise
|
|
9
|
+
*/
|
|
10
|
+
export declare function isDateInstance(value: any): value is Date;
|
|
11
|
+
/**
|
|
12
|
+
* Check if a Date object represents a valid date
|
|
13
|
+
* @param date - Date object to validate
|
|
14
|
+
* @returns true if date is valid, false otherwise
|
|
15
|
+
*/
|
|
16
|
+
export declare function isValidDate(date: Date): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Parse a date string according to a format pattern
|
|
19
|
+
*
|
|
20
|
+
* Supported format tokens:
|
|
21
|
+
* - yyyy: 4-digit year
|
|
22
|
+
* - yy: 2-digit year (00-99 → 2000-2099)
|
|
23
|
+
* - MM: 2-digit month (01-12)
|
|
24
|
+
* - M: 1-2 digit month (1-12)
|
|
25
|
+
* - dd: 2-digit day (01-31)
|
|
26
|
+
* - d: 1-2 digit day (1-31)
|
|
27
|
+
* - HH: 2-digit hour (00-23)
|
|
28
|
+
* - H: 1-2 digit hour (0-23)
|
|
29
|
+
* - mm: 2-digit minute (00-59)
|
|
30
|
+
* - m: 1-2 digit minute (0-59)
|
|
31
|
+
* - ss: 2-digit second (00-59)
|
|
32
|
+
* - s: 1-2 digit second (0-59)
|
|
33
|
+
* - SSS: 3-digit millisecond (000-999)
|
|
34
|
+
*
|
|
35
|
+
* Special formats:
|
|
36
|
+
* - 't': Unix timestamp in seconds
|
|
37
|
+
* - 'T': Unix timestamp in milliseconds
|
|
38
|
+
*
|
|
39
|
+
* @param value - The date string to parse
|
|
40
|
+
* @param format - Format pattern (e.g., 'yyyy-MM-dd', 'dd.MM.yyyy', 't', 'T')
|
|
41
|
+
* @param referenceDate - Optional reference date (reserved for future use, currently unused)
|
|
42
|
+
* @returns Parsed Date object or Invalid Date (NaN)
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* parseDate('2023-12-25', 'yyyy-MM-dd') // Dec 25, 2023
|
|
46
|
+
* parseDate('25.12.2023', 'dd.MM.yyyy') // Dec 25, 2023
|
|
47
|
+
* parseDate('1640000000', 't') // Unix seconds
|
|
48
|
+
* parseDate('2023-02-31', 'yyyy-MM-dd') // Invalid Date (Feb only has 28/29 days)
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseDate(value: string, format: string, _referenceDate?: Date): Date;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { QueryAttributeEntry } from './query-builder';
|
|
2
|
+
/**
|
|
3
|
+
* Result of path validation
|
|
4
|
+
*/
|
|
5
|
+
export interface ValidationResult {
|
|
6
|
+
valid: boolean;
|
|
7
|
+
errors?: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* DeepQueryService - Centralized service for parsing, validating, and caching deep query attributes
|
|
11
|
+
*
|
|
12
|
+
* This service provides:
|
|
13
|
+
* - LRU caching for parsed attribute paths (1000 entries, targeting >80% hit rate)
|
|
14
|
+
* - Circular reference detection
|
|
15
|
+
* - Multi-level nesting support (3+ levels)
|
|
16
|
+
* - Path validation with descriptive errors
|
|
17
|
+
*/
|
|
18
|
+
export declare class DeepQueryService {
|
|
19
|
+
private parseCache;
|
|
20
|
+
private circularRefDetector;
|
|
21
|
+
private cacheHits;
|
|
22
|
+
private cacheMisses;
|
|
23
|
+
constructor(cacheSize?: number);
|
|
24
|
+
/**
|
|
25
|
+
* Parse an attribute string into its components
|
|
26
|
+
*
|
|
27
|
+
* Supports:
|
|
28
|
+
* - Dot notation: `customer.name`
|
|
29
|
+
* - Bracket notation: `items[0].price`, `items[*].price`
|
|
30
|
+
* - Multi-level: `order.customer.address.city`
|
|
31
|
+
*
|
|
32
|
+
* @param attribute - The attribute path to parse
|
|
33
|
+
* @returns QueryAttributeEntry with isDeepQuery, reference, referenceAttribute
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const service = new DeepQueryService();
|
|
38
|
+
* const entry = service.parse('customer.name');
|
|
39
|
+
* // Returns: { attribute: 'customer.name', isDeepQuery: true, reference: 'customer', referenceAttribute: 'name' }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
parse(attribute: string): QueryAttributeEntry;
|
|
43
|
+
/**
|
|
44
|
+
* Detect circular references in a path
|
|
45
|
+
*
|
|
46
|
+
* Checks for:
|
|
47
|
+
* - Direct circular: A→B→A
|
|
48
|
+
* - Indirect circular: A→B→C→A
|
|
49
|
+
* - Self-referential: A→A
|
|
50
|
+
*
|
|
51
|
+
* @param path - Array of model/reference keys in the dependency chain
|
|
52
|
+
* @returns true if circular reference detected
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const service = new DeepQueryService();
|
|
57
|
+
* const hasCircular = service.detectCircular(['Order', 'Customer', 'Order']);
|
|
58
|
+
* // Returns: true
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
detectCircular(path: string[]): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Validate attribute path syntax
|
|
64
|
+
*
|
|
65
|
+
* Checks for:
|
|
66
|
+
* - Empty strings
|
|
67
|
+
* - Malformed bracket notation
|
|
68
|
+
* - Invalid characters
|
|
69
|
+
* - Excessive nesting depth
|
|
70
|
+
*
|
|
71
|
+
* @param attribute - The attribute path to validate
|
|
72
|
+
* @param maxDepth - Maximum allowed nesting depth (default: 10)
|
|
73
|
+
* @returns ValidationResult with errors if invalid
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const service = new DeepQueryService();
|
|
78
|
+
* const result = service.validatePath('customer.name');
|
|
79
|
+
* // Returns: { valid: true }
|
|
80
|
+
*
|
|
81
|
+
* const badResult = service.validatePath('customer.[invalid]');
|
|
82
|
+
* // Returns: { valid: false, errors: ['Invalid bracket notation: customer.[invalid]'] }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
validatePath(attribute: string, maxDepth?: number): ValidationResult;
|
|
86
|
+
/**
|
|
87
|
+
* Clear the parse cache
|
|
88
|
+
* Should be called when models are updated or removed
|
|
89
|
+
*/
|
|
90
|
+
clearCache(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Clear the circular reference detector
|
|
93
|
+
*/
|
|
94
|
+
clearCircularDetector(): void;
|
|
95
|
+
/**
|
|
96
|
+
* Get cache statistics for monitoring and debugging
|
|
97
|
+
*
|
|
98
|
+
* @returns Object containing cache size, hit rate, and other metrics
|
|
99
|
+
*/
|
|
100
|
+
getCacheStats(): {
|
|
101
|
+
size: number;
|
|
102
|
+
maxSize: number;
|
|
103
|
+
hits: number;
|
|
104
|
+
misses: number;
|
|
105
|
+
hitRate: number;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Extract path segments from an attribute string
|
|
109
|
+
* Useful for analyzing deep query structure
|
|
110
|
+
*
|
|
111
|
+
* @param attribute - The attribute path
|
|
112
|
+
* @returns Array of path segments
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const service = new DeepQueryService();
|
|
117
|
+
* const segments = service.getPathSegments('order.customer.name');
|
|
118
|
+
* // Returns: ['order', 'customer', 'name']
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
getPathSegments(attribute: string): string[];
|
|
122
|
+
/**
|
|
123
|
+
* Get the depth of a deep query path
|
|
124
|
+
*
|
|
125
|
+
* @param attribute - The attribute path
|
|
126
|
+
* @returns Depth of the path (1 for shallow, 2+ for deep)
|
|
127
|
+
*/
|
|
128
|
+
getPathDepth(attribute: string): number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Singleton instance for global use
|
|
132
|
+
*/
|
|
133
|
+
export declare const deepQueryService: DeepQueryService;
|
|
@@ -1,9 +1,31 @@
|
|
|
1
|
-
export declare class DependencyGraph {
|
|
1
|
+
export declare class DependencyGraph<K extends string = string, M = any> {
|
|
2
2
|
private nodes;
|
|
3
3
|
private edges;
|
|
4
|
+
private nodeKinds;
|
|
5
|
+
private nodeMeta;
|
|
6
|
+
private edgePolicy?;
|
|
4
7
|
constructor();
|
|
5
|
-
addNode(name: string
|
|
8
|
+
addNode(name: string, options?: {
|
|
9
|
+
kind?: K;
|
|
10
|
+
meta?: M;
|
|
11
|
+
}): void;
|
|
6
12
|
addDependency(from: string, to: string): void;
|
|
13
|
+
/** Configure an optional policy to validate edges before they are added */
|
|
14
|
+
setEdgePolicy(policy?: (from: {
|
|
15
|
+
name: string;
|
|
16
|
+
kind?: K;
|
|
17
|
+
}, to: {
|
|
18
|
+
name: string;
|
|
19
|
+
kind?: K;
|
|
20
|
+
}) => boolean): void;
|
|
21
|
+
/** Assign or change a node's kind */
|
|
22
|
+
setNodeKind(name: string, kind?: K): void;
|
|
23
|
+
/** Get a node's kind */
|
|
24
|
+
getNodeKind(name: string): K | undefined;
|
|
25
|
+
/** Set arbitrary metadata for a node */
|
|
26
|
+
setNodeMeta(name: string, meta: M): void;
|
|
27
|
+
/** Get metadata for a node */
|
|
28
|
+
getNodeMeta<T = M>(name: string): T | undefined;
|
|
7
29
|
removeNode(name: string): void;
|
|
8
30
|
removeDependency(from: string, to: string): void;
|
|
9
31
|
hasNode(name: string): boolean;
|
|
@@ -11,8 +33,85 @@ export declare class DependencyGraph {
|
|
|
11
33
|
getDependencies(name: string): string[];
|
|
12
34
|
getDependents(name: string): string[];
|
|
13
35
|
isCyclic(): boolean;
|
|
14
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Validates that the graph has no cycles.
|
|
38
|
+
* Returns an object with hasCycle boolean and the cycle path if found.
|
|
39
|
+
* @returns {hasCycle: boolean, path?: string[]} - hasCycle is true if a cycle exists, path contains the cycle nodes
|
|
40
|
+
*/
|
|
41
|
+
validateNoCycles(): {
|
|
42
|
+
hasCycle: boolean;
|
|
43
|
+
path?: string[];
|
|
44
|
+
};
|
|
45
|
+
order(options?: {
|
|
46
|
+
allowCycles?: boolean;
|
|
47
|
+
}): string[];
|
|
15
48
|
clear(): void;
|
|
16
49
|
getNodes(): string[];
|
|
17
50
|
getAllEdges(): [string, string][];
|
|
51
|
+
/**
|
|
52
|
+
* Returns all nodes that have no dependants (i.e., no other node depends on them).
|
|
53
|
+
* In graph terms, nodes with zero incoming edges.
|
|
54
|
+
*/
|
|
55
|
+
getNodesWithNoDependants(): string[];
|
|
56
|
+
/** Return nodes filtered by kind */
|
|
57
|
+
getNodesByKind(kind: K): string[];
|
|
58
|
+
/** Roots by kind (zero incoming) */
|
|
59
|
+
getRootsByKind(kind?: K): string[];
|
|
60
|
+
/** Leaves by kind (zero outgoing) */
|
|
61
|
+
getLeavesByKind(kind?: K): string[];
|
|
62
|
+
/** Filter dependencies of a node by kind */
|
|
63
|
+
getDependenciesOfKind(name: string, kind: K): string[];
|
|
64
|
+
/** Filter dependents of a node by kind */
|
|
65
|
+
getDependentsOfKind(name: string, kind: K): string[];
|
|
66
|
+
/**
|
|
67
|
+
* Create execution batches (topological levels). Throws if the graph has a cycle.
|
|
68
|
+
* If filterKinds is provided, batches contain only nodes of these kinds, but readiness
|
|
69
|
+
* is evaluated against the complete graph.
|
|
70
|
+
*/
|
|
71
|
+
plan(options?: {
|
|
72
|
+
filterKinds?: K[];
|
|
73
|
+
}): {
|
|
74
|
+
batches: string[][];
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Impact analysis: return nodes impacted by a set of changed nodes.
|
|
78
|
+
* direction:
|
|
79
|
+
* - 'downstream': nodes that depend (directly/indirectly) on changed
|
|
80
|
+
* - 'upstream': nodes that changed depends on
|
|
81
|
+
* - 'both': union of upstream and downstream
|
|
82
|
+
*/
|
|
83
|
+
getImpactedNodes(changed: string[] | Set<string>, direction?: 'downstream' | 'upstream' | 'both', filterKinds?: K[]): string[];
|
|
84
|
+
toJSON(): {
|
|
85
|
+
nodes: Array<{
|
|
86
|
+
name: string;
|
|
87
|
+
kind?: K;
|
|
88
|
+
meta?: M;
|
|
89
|
+
}>;
|
|
90
|
+
edges: Array<{
|
|
91
|
+
from: string;
|
|
92
|
+
to: string;
|
|
93
|
+
}>;
|
|
94
|
+
};
|
|
95
|
+
static fromJSON<KK extends string, MM = any>(data: {
|
|
96
|
+
nodes: Array<{
|
|
97
|
+
name: string;
|
|
98
|
+
kind?: KK;
|
|
99
|
+
meta?: MM;
|
|
100
|
+
}>;
|
|
101
|
+
edges: Array<{
|
|
102
|
+
from: string;
|
|
103
|
+
to: string;
|
|
104
|
+
}>;
|
|
105
|
+
}): DependencyGraph<KK, MM>;
|
|
106
|
+
diff(other: DependencyGraph<K, any>): {
|
|
107
|
+
addedNodes: string[];
|
|
108
|
+
removedNodes: string[];
|
|
109
|
+
addedEdges: [string, string][];
|
|
110
|
+
removedEdges: [string, string][];
|
|
111
|
+
kindChanges: Array<{
|
|
112
|
+
name: string;
|
|
113
|
+
from?: K;
|
|
114
|
+
to?: K;
|
|
115
|
+
}>;
|
|
116
|
+
};
|
|
18
117
|
}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
export * from './analytics.controller';
|
|
2
|
+
export * from './attribute-dependency-graph';
|
|
2
3
|
export * from './cache.controller';
|
|
3
4
|
export * from './changeDetection';
|
|
4
5
|
export * from './computeSuggestions';
|
|
6
|
+
export * from './date-utils';
|
|
7
|
+
export * from './deep-query.service';
|
|
5
8
|
export * from './dependency-graph';
|
|
6
9
|
export * from './getAggregation';
|
|
7
10
|
export * from './getFacets';
|
|
8
11
|
export * from './helper';
|
|
9
12
|
export * from './indices.controller';
|
|
13
|
+
export * from './logger';
|
|
10
14
|
export * from './performance';
|
|
11
15
|
export * from './pivot';
|
|
12
16
|
export * from './property-parser';
|