@snteam/amplify-angular-core 1.0.37 → 1.0.38
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.
|
@@ -647,6 +647,8 @@ class ConfigurationAnalyzerService {
|
|
|
647
647
|
selectors.push('id');
|
|
648
648
|
// Convert target model to camelCase for field access
|
|
649
649
|
const fieldName = this.toCamelCase(targetModel);
|
|
650
|
+
// Add the relationship field itself (this is important for validation)
|
|
651
|
+
selectors.push(fieldName);
|
|
650
652
|
// Add the relationship field with its ID
|
|
651
653
|
selectors.push(`${fieldName}.id`);
|
|
652
654
|
// Add common display fields for the relationship
|
|
@@ -726,7 +728,7 @@ class ConfigurationAnalyzerService {
|
|
|
726
728
|
return selectors;
|
|
727
729
|
}
|
|
728
730
|
/**
|
|
729
|
-
* Enhanced field selector determination that supports nested paths
|
|
731
|
+
* Enhanced field selector determination that supports nested paths and handles different relationship types
|
|
730
732
|
*/
|
|
731
733
|
determineFieldSelectorsEnhanced(targetModel, fieldName) {
|
|
732
734
|
if (!targetModel) {
|
|
@@ -738,8 +740,28 @@ class ConfigurationAnalyzerService {
|
|
|
738
740
|
if (effectiveFieldName.includes('.')) {
|
|
739
741
|
return this.generateNestedFieldSelectors(effectiveFieldName, targetModel);
|
|
740
742
|
}
|
|
741
|
-
//
|
|
742
|
-
|
|
743
|
+
// Generate selectors for the relationship
|
|
744
|
+
const selectors = [];
|
|
745
|
+
// Always include the base record ID
|
|
746
|
+
selectors.push('id');
|
|
747
|
+
// For the relationship field, we need to be more flexible about how we include it
|
|
748
|
+
// Some relationships might need the field itself, others might need nested access
|
|
749
|
+
// Strategy 1: Include the relationship field directly
|
|
750
|
+
selectors.push(effectiveFieldName);
|
|
751
|
+
// Strategy 2: Include nested access to common fields
|
|
752
|
+
selectors.push(`${effectiveFieldName}.id`);
|
|
753
|
+
// Add common display fields for the relationship
|
|
754
|
+
for (const displayField of this.COMMON_DISPLAY_FIELDS) {
|
|
755
|
+
selectors.push(`${effectiveFieldName}.${displayField}`);
|
|
756
|
+
}
|
|
757
|
+
// Strategy 3: For some relationship types, we might need to include additional metadata
|
|
758
|
+
// Add some common relationship metadata fields
|
|
759
|
+
const metadataFields = ['createdAt', 'updatedAt'];
|
|
760
|
+
for (const metadataField of metadataFields) {
|
|
761
|
+
selectors.push(`${effectiveFieldName}.${metadataField}`);
|
|
762
|
+
}
|
|
763
|
+
console.log(`ConfigurationAnalyzer: Generated ${selectors.length} field selectors for ${targetModel} with field ${effectiveFieldName}:`, selectors);
|
|
764
|
+
return selectors;
|
|
743
765
|
}
|
|
744
766
|
/**
|
|
745
767
|
* Convert a string to PascalCase (first letter uppercase, rest camelCase)
|
|
@@ -1559,16 +1581,33 @@ class SelectionSetGeneratorService {
|
|
|
1559
1581
|
*/
|
|
1560
1582
|
generateConfigurationBasedSelectionSet(config, analysisResult) {
|
|
1561
1583
|
const selectionSet = ['id'];
|
|
1584
|
+
console.log('SelectionSetGenerator: Generating configuration-based selection set:', {
|
|
1585
|
+
config: {
|
|
1586
|
+
relationshipModelName: config.relationshipModelName,
|
|
1587
|
+
fieldName: config.fieldName,
|
|
1588
|
+
baseModelName: config.baseModelName,
|
|
1589
|
+
associatedWith: config.associatedWith
|
|
1590
|
+
},
|
|
1591
|
+
analysisResult: {
|
|
1592
|
+
targetModelName: analysisResult.targetModelName,
|
|
1593
|
+
fieldSelectorsCount: analysisResult.fieldSelectors?.length || 0,
|
|
1594
|
+
fieldSelectors: analysisResult.fieldSelectors
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1562
1597
|
// Use the field selectors from configuration analysis
|
|
1563
1598
|
for (const selector of analysisResult.fieldSelectors) {
|
|
1564
1599
|
if (!selectionSet.includes(selector)) {
|
|
1565
1600
|
selectionSet.push(selector);
|
|
1566
1601
|
}
|
|
1567
1602
|
}
|
|
1603
|
+
console.log('SelectionSetGenerator: Configuration-based selection set before optimization:', selectionSet);
|
|
1568
1604
|
// Apply display optimization if enabled
|
|
1569
1605
|
const optimizedSet = this.applyDisplayOptimization(selectionSet, config);
|
|
1606
|
+
console.log('SelectionSetGenerator: Selection set after display optimization:', optimizedSet);
|
|
1570
1607
|
// Apply complexity limits
|
|
1571
|
-
|
|
1608
|
+
const finalSet = this.applyComplexityLimits(optimizedSet);
|
|
1609
|
+
console.log('SelectionSetGenerator: Final configuration-based selection set:', finalSet);
|
|
1610
|
+
return finalSet;
|
|
1572
1611
|
}
|
|
1573
1612
|
/**
|
|
1574
1613
|
* Apply display optimization to prioritize display-relevant fields
|
|
@@ -2709,7 +2748,7 @@ class AmplifyModelService {
|
|
|
2709
2748
|
}
|
|
2710
2749
|
/**
|
|
2711
2750
|
* Validate that relationship field data is populated in query results
|
|
2712
|
-
* Enhanced with comprehensive error logging
|
|
2751
|
+
* Enhanced with comprehensive error logging and flexible validation
|
|
2713
2752
|
*/
|
|
2714
2753
|
validateRelationshipFieldPopulation(result, config) {
|
|
2715
2754
|
try {
|
|
@@ -2724,28 +2763,56 @@ class AmplifyModelService {
|
|
|
2724
2763
|
// Check if any records have the relationship field populated
|
|
2725
2764
|
const records = Array.isArray(result.data) ? result.data : [result.data];
|
|
2726
2765
|
let populatedCount = 0;
|
|
2766
|
+
let partiallyPopulatedCount = 0;
|
|
2727
2767
|
for (const record of records) {
|
|
2728
|
-
if (record
|
|
2768
|
+
if (!record)
|
|
2769
|
+
continue;
|
|
2770
|
+
const relationshipData = record[config.fieldName];
|
|
2771
|
+
// Check for fully populated relationship (object with data)
|
|
2772
|
+
if (relationshipData !== undefined && relationshipData !== null) {
|
|
2773
|
+
// If it's an object with properties, consider it populated
|
|
2774
|
+
if (typeof relationshipData === 'object' && Object.keys(relationshipData).length > 0) {
|
|
2775
|
+
populatedCount++;
|
|
2776
|
+
}
|
|
2777
|
+
// If it's a non-null primitive value, also consider it populated
|
|
2778
|
+
else if (typeof relationshipData !== 'object') {
|
|
2779
|
+
populatedCount++;
|
|
2780
|
+
}
|
|
2781
|
+
// If it's an empty object or array, consider it partially populated
|
|
2782
|
+
else {
|
|
2783
|
+
partiallyPopulatedCount++;
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
// Also check if the record has any nested relationship data
|
|
2787
|
+
// This handles cases where the selection set includes nested fields like "table.id", "table.name"
|
|
2788
|
+
const hasNestedRelationshipData = this.hasNestedRelationshipData(record, config.fieldName);
|
|
2789
|
+
if (hasNestedRelationshipData) {
|
|
2729
2790
|
populatedCount++;
|
|
2730
2791
|
}
|
|
2731
2792
|
}
|
|
2732
|
-
if
|
|
2733
|
-
|
|
2793
|
+
// Consider the validation successful if we have any populated or partially populated records
|
|
2794
|
+
const totalValidRecords = populatedCount + partiallyPopulatedCount;
|
|
2795
|
+
if (totalValidRecords === 0) {
|
|
2796
|
+
// Log detailed information about what we found
|
|
2734
2797
|
this.errorHandler.logSelectionSetError(SelectionSetErrorType.FIELD_NOT_FOUND, `No records have relationship field '${config.fieldName}' populated`, config, undefined, {
|
|
2735
2798
|
method: 'validateRelationshipFieldPopulation',
|
|
2736
2799
|
recordCount: records.length,
|
|
2737
2800
|
populatedCount,
|
|
2801
|
+
partiallyPopulatedCount,
|
|
2738
2802
|
sampleRecord: records[0] ? Object.keys(records[0]) : [],
|
|
2739
|
-
|
|
2803
|
+
sampleRecordData: records[0] ? records[0] : null,
|
|
2804
|
+
fieldName: config.fieldName,
|
|
2805
|
+
relationshipFieldValue: records[0] ? records[0][config.fieldName] : undefined
|
|
2740
2806
|
});
|
|
2741
2807
|
console.warn(`AmplifyModelService: No records have relationship field '${config.fieldName}' populated`, {
|
|
2742
2808
|
config,
|
|
2743
2809
|
recordCount: records.length,
|
|
2744
|
-
sampleRecord: records[0]
|
|
2810
|
+
sampleRecord: records[0],
|
|
2811
|
+
sampleRelationshipValue: records[0] ? records[0][config.fieldName] : undefined
|
|
2745
2812
|
});
|
|
2746
2813
|
return false;
|
|
2747
2814
|
}
|
|
2748
|
-
console.log(`AmplifyModelService: Relationship field validation successful: ${populatedCount}/${records.length} records
|
|
2815
|
+
console.log(`AmplifyModelService: Relationship field validation successful: ${populatedCount}/${records.length} records fully populated, ${partiallyPopulatedCount} partially populated for '${config.fieldName}' field`);
|
|
2749
2816
|
return true;
|
|
2750
2817
|
}
|
|
2751
2818
|
catch (error) {
|
|
@@ -2760,6 +2827,26 @@ class AmplifyModelService {
|
|
|
2760
2827
|
return false;
|
|
2761
2828
|
}
|
|
2762
2829
|
}
|
|
2830
|
+
/**
|
|
2831
|
+
* Check if a record has nested relationship data based on field patterns
|
|
2832
|
+
* This helps validate cases where selection sets use nested field access like "table.id", "table.name"
|
|
2833
|
+
*/
|
|
2834
|
+
hasNestedRelationshipData(record, fieldName) {
|
|
2835
|
+
if (!record || typeof record !== 'object') {
|
|
2836
|
+
return false;
|
|
2837
|
+
}
|
|
2838
|
+
// Look for any fields that start with the relationship field name followed by a dot
|
|
2839
|
+
const nestedFieldPattern = `${fieldName}.`;
|
|
2840
|
+
for (const key of Object.keys(record)) {
|
|
2841
|
+
if (key.startsWith(nestedFieldPattern)) {
|
|
2842
|
+
const value = record[key];
|
|
2843
|
+
if (value !== undefined && value !== null) {
|
|
2844
|
+
return true;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
return false;
|
|
2849
|
+
}
|
|
2763
2850
|
/**
|
|
2764
2851
|
* Log query attempt details
|
|
2765
2852
|
*/
|