Skip to content

Commit 2c771bc

Browse files
committed
Add property and properties methods to ValueTraversal for enhanced value selection
- Introduced property() method to select a single property from graph elements and plain objects. - Added properties() method to select multiple properties, supporting both graph elements and plain objects. - Implemented tests to validate the functionality of the new methods, ensuring correct extraction of properties from elements and objects.
1 parent 7389394 commit 2c771bc

2 files changed

Lines changed: 142 additions & 0 deletions

File tree

packages/graph/src/Traversals.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,93 @@ export class ValueTraversal<const TSchema extends GraphSchema, const TValue> ext
11961196
]);
11971197
}
11981198

1199+
/**
1200+
* Select a single property of the values in the traversal.
1201+
* Supports both graph elements and plain object values.
1202+
* @param propertyName The name of the property to select.
1203+
*/
1204+
public property<const TPropertyName extends keyof GetValueTraversalProperties<TValue>>(
1205+
propertyName: TPropertyName,
1206+
) {
1207+
return new ValueTraversal<TSchema, GetValueTraversalProperties<TValue>[TPropertyName]>(
1208+
this.graph,
1209+
[
1210+
...this.steps,
1211+
new MapElementsStep<TValue>({
1212+
mapper: (value) => {
1213+
if (value instanceof Element) {
1214+
return value.get(propertyName as never);
1215+
}
1216+
if (typeof value === "object" && value !== null) {
1217+
return value[propertyName as keyof typeof value];
1218+
}
1219+
return undefined as GetValueTraversalProperties<TValue>[TPropertyName];
1220+
},
1221+
}),
1222+
],
1223+
);
1224+
}
1225+
1226+
/**
1227+
* Select specific properties of the values in the traversal.
1228+
* Supports both graph elements and plain object values.
1229+
* @param propertyNames The names of the properties to select.
1230+
*/
1231+
public properties(): ValueTraversal<TSchema, GetValueTraversalProperties<TValue>>;
1232+
public properties<
1233+
const TPropertyNames extends readonly (keyof GetValueTraversalProperties<TValue>)[],
1234+
>(
1235+
...propertyNames: TPropertyNames
1236+
): ValueTraversal<TSchema, Pick<GetValueTraversalProperties<TValue>, TPropertyNames[number]>>;
1237+
public properties<
1238+
const TPropertyNames extends readonly (keyof GetValueTraversalProperties<TValue>)[],
1239+
>(...propertyNames: TPropertyNames): ValueTraversal<TSchema, any> {
1240+
return new ValueTraversal<
1241+
TSchema,
1242+
Pick<GetValueTraversalProperties<TValue>, TPropertyNames[number]>
1243+
>(this.graph, [
1244+
...this.steps,
1245+
new MapElementsStep<TValue>({
1246+
mapper: (value) => {
1247+
if (value instanceof Element) {
1248+
const storedProps = value[$StoredElement].properties;
1249+
if (propertyNames.length === 0) {
1250+
return storedProps as Pick<
1251+
GetValueTraversalProperties<TValue>,
1252+
TPropertyNames[number]
1253+
>;
1254+
}
1255+
const properties = {} as Pick<
1256+
GetValueTraversalProperties<TValue>,
1257+
TPropertyNames[number]
1258+
>;
1259+
for (const propertyName of propertyNames) {
1260+
properties[propertyName] = value.get(propertyName as never);
1261+
}
1262+
return properties;
1263+
}
1264+
if (typeof value === "object" && value !== null) {
1265+
if (propertyNames.length === 0) {
1266+
return value as Pick<GetValueTraversalProperties<TValue>, TPropertyNames[number]>;
1267+
}
1268+
const properties = {} as Pick<
1269+
GetValueTraversalProperties<TValue>,
1270+
TPropertyNames[number]
1271+
>;
1272+
for (const propertyName of propertyNames) {
1273+
properties[propertyName] = value[propertyName as keyof typeof value] as Pick<
1274+
GetValueTraversalProperties<TValue>,
1275+
TPropertyNames[number]
1276+
>[typeof propertyName];
1277+
}
1278+
return properties;
1279+
}
1280+
return {} as Pick<GetValueTraversalProperties<TValue>, TPropertyNames[number]>;
1281+
},
1282+
}),
1283+
]);
1284+
}
1285+
11991286
/**
12001287
* Order the values in the traversal.
12011288
*/

packages/graph/src/test/ValueTraversal.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,61 @@ test("ValueTraversal Operations - order() operation - order().by(property) sorts
194194
expect(keys).toEqual([...keys].sort());
195195
});
196196

197+
test("ValueTraversal Operations - property() operation - property() after values() extracts element properties", () => {
198+
const names = Array.from(
199+
g
200+
.V()
201+
.hasLabel("Person")
202+
.order()
203+
.by("name")
204+
.values()
205+
.property("name"),
206+
);
207+
208+
expect(names).toEqual(["Alice", "Bob", "Charlie", "Dave", "Erin", "Fiona", "George"]);
209+
});
210+
211+
test("ValueTraversal Operations - property() operation - property() extracts object properties", () => {
212+
const names = Array.from(
213+
g
214+
.V(alice.id)
215+
.map((path) => ({
216+
name: path.value.get("name"),
217+
age: path.value.get("age"),
218+
}))
219+
.property("name"),
220+
);
221+
222+
expect(names).toEqual(["Alice"]);
223+
});
224+
225+
test("ValueTraversal Operations - properties() operation - properties() after values() extracts all element properties", () => {
226+
const results = Array.from(g.V(alice.id).values().properties());
227+
228+
expect(results).toHaveLength(1);
229+
expect(results[0]).toMatchObject({ name: "Alice", age: 30 });
230+
});
231+
232+
test("ValueTraversal Operations - properties() operation - properties() extracts selected object properties", () => {
233+
const results = Array.from(
234+
g
235+
.V()
236+
.hasLabel("Person")
237+
.limit(2)
238+
.map((path) => ({
239+
bucket: path.value.get("age") >= 30 ? "older" : "younger",
240+
name: path.value.get("name"),
241+
age: path.value.get("age"),
242+
}))
243+
.properties("bucket", "name"),
244+
);
245+
246+
expect(results).toEqual([
247+
{ bucket: "older", name: "Alice" },
248+
{ bucket: "younger", name: "Bob" },
249+
]);
250+
});
251+
197252
test("ValueTraversal Operations - values() extraction - values() on edge traversal", () => {
198253
const edges = Array.from(g.E().values());
199254

0 commit comments

Comments
 (0)