dynamo-query-engine 1.0.6 → 1.0.7

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": "dynamo-query-engine",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Type-safe DynamoDB query builder for GraphQL with support for filtering, sorting, pagination, and relation expansion",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -76,30 +76,78 @@ export async function resolveExpand({
76
76
  // Resolve relations for each parent item
77
77
  const expandPromises = parentItems.map(async (parent) => {
78
78
  try {
79
- // For MANY relations, we need a partition key value
80
- // This should be either parent.pk or a specific field based on the relation
79
+ // Get partition key value from parent
80
+ // This should be either parent.pk or the first field (usually tenantId)
81
81
  const partitionKeyValue = parent.pk || parent[Object.keys(parent)[0]];
82
82
 
83
83
  if (!partitionKeyValue) {
84
84
  console.warn(
85
85
  `Cannot expand '${field}' for parent: missing partition key value`
86
86
  );
87
- parent[expandPropertyName] = [];
87
+ parent[expandPropertyName] = policy.relation === "ONE" ? null : [];
88
88
  return;
89
89
  }
90
90
 
91
- // Build query for expanded items
92
- const { query } = buildGridQuery({
93
- model: targetModel,
94
- partitionKeyValue,
95
- filterModel: args.filter,
96
- sortModel: args.sort,
97
- paginationModel: { pageSize: limit },
98
- // No cursor for nested expands
99
- });
91
+ let results;
92
+
93
+ // For ONE relations with a foreignKey, we can optimize by directly querying for that specific item
94
+ if (policy.relation === "ONE" && policy.foreignKey) {
95
+ const foreignKeyValue = parent[policy.foreignKey];
96
+
97
+ if (!foreignKeyValue) {
98
+ console.warn(
99
+ `Cannot expand '${field}' for parent: missing foreign key value '${policy.foreignKey}'`
100
+ );
101
+ parent[expandPropertyName] = null;
102
+ return;
103
+ }
104
+
105
+ // Build a query that filters for the specific range key value
106
+ const targetAttributes = targetModel.schema.getAttributes();
107
+ const rangeKeyName = Object.keys(targetAttributes).find(
108
+ (key) => targetAttributes[key].rangeKey === true
109
+ );
100
110
 
101
- // Execute query
102
- const results = await query.exec();
111
+ if (!rangeKeyName) {
112
+ console.warn(
113
+ `Cannot expand '${field}': target model '${policy.type}' has no range key defined`
114
+ );
115
+ parent[expandPropertyName] = null;
116
+ return;
117
+ }
118
+
119
+ // Build query with range key filter
120
+ const filterModel = JSON.stringify({
121
+ items: [
122
+ {
123
+ field: rangeKeyName,
124
+ operator: "equals",
125
+ value: foreignKeyValue,
126
+ },
127
+ ],
128
+ });
129
+
130
+ const { query } = buildGridQuery({
131
+ model: targetModel,
132
+ partitionKeyValue,
133
+ filterModel,
134
+ limit: 1,
135
+ });
136
+
137
+ results = await query.exec();
138
+ } else {
139
+ // For MANY relations or ONE without foreignKey, use standard query
140
+ const { query } = buildGridQuery({
141
+ model: targetModel,
142
+ partitionKeyValue,
143
+ filterModel: args.filter,
144
+ sortModel: args.sort,
145
+ paginationModel: { pageSize: limit },
146
+ // No cursor for nested expands
147
+ });
148
+
149
+ results = await query.exec();
150
+ }
103
151
 
104
152
  // Add __typename to each result
105
153
  const resultsWithTypename = results.map((item) => ({
@@ -33,6 +33,7 @@ describe("ExpandResolver", () => {
33
33
  expand: {
34
34
  type: "Unit",
35
35
  relation: "ONE",
36
+ foreignKey: "unitId", // Field in parent that references the child
36
37
  defaultLimit: 1,
37
38
  maxLimit: 1,
38
39
  },
@@ -177,6 +178,22 @@ describe("ExpandResolver", () => {
177
178
  expect(parentItems[0].Units[1].__typename).toBe("Units");
178
179
  });
179
180
 
181
+ it("should use foreignKey to filter for specific item in ONE relation", async () => {
182
+ await resolveExpand({
183
+ parentItems,
184
+ parentModel,
185
+ field: "unitId",
186
+ });
187
+
188
+ // Should have expanded exactly one unit
189
+ expect(parentItems[0].Unit).toBeDefined();
190
+ expect(parentItems[0].Unit.unitId).toBe("unit-1");
191
+ expect(parentItems[0].Unit.name).toBe("Unit A");
192
+
193
+ // Verify that buildGridQuery was called with a filterModel
194
+ // (This would require spy/mock inspection in a more detailed test)
195
+ });
196
+
180
197
  it("should fallback to field name when graphql.type is not defined", async () => {
181
198
  // Clear and re-register with different config
182
199
  modelRegistry.clear();