-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into string-nodes
- Loading branch information
Showing
10 changed files
with
319 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@tokens-studio/graph-engine": minor | ||
"@tokens-studio/graph-engine-ui": minor | ||
--- | ||
|
||
Add find First and linear search nodes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { | ||
BooleanSchema, | ||
NumberSchema, | ||
StringSchema | ||
} from '../../schemas/index.js'; | ||
import { INodeDefinition, ToInput, ToOutput } from '../../index.js'; | ||
import { Node } from '../../programmatic/node.js'; | ||
import { Operator } from '../../schemas/operators.js'; | ||
import { arrayOf } from '../../schemas/utils.js'; | ||
|
||
export default class NodeDefinition extends Node { | ||
static title = 'Find First Match'; | ||
static type = 'studio.tokens.search.findFirst'; | ||
static description = | ||
'Finds the first array element that matches a comparison condition with a target value'; | ||
|
||
declare inputs: ToInput<{ | ||
array: any[]; | ||
target: number; | ||
operator: Operator.GREATER_THAN | Operator.LESS_THAN; | ||
}>; | ||
|
||
declare outputs: ToOutput<{ | ||
value: any; | ||
index: number; | ||
found: boolean; | ||
}>; | ||
|
||
constructor(props: INodeDefinition) { | ||
super(props); | ||
|
||
this.addInput('array', { | ||
type: { | ||
...arrayOf(NumberSchema), | ||
description: 'Array of numbers to search through' | ||
} | ||
}); | ||
|
||
this.addInput('target', { | ||
type: { | ||
...NumberSchema, | ||
description: 'Target value to compare against' | ||
} | ||
}); | ||
|
||
this.addInput('operator', { | ||
type: { | ||
...StringSchema, | ||
enum: [Operator.GREATER_THAN, Operator.LESS_THAN], | ||
default: Operator.GREATER_THAN, | ||
description: 'Comparison operator to use (greater than or less than)' | ||
} | ||
}); | ||
|
||
this.addOutput('value', { | ||
type: { | ||
...NumberSchema, | ||
description: 'The first matching value found (null if no match)' | ||
} | ||
}); | ||
|
||
this.addOutput('index', { | ||
type: { | ||
...NumberSchema, | ||
description: 'Index of the first matching value (-1 if no match)' | ||
} | ||
}); | ||
|
||
this.addOutput('found', { | ||
type: { | ||
...BooleanSchema, | ||
description: 'Whether a matching value was found' | ||
} | ||
}); | ||
} | ||
|
||
execute(): void { | ||
const { array, target, operator } = this.getAllInputs(); | ||
|
||
const comparisonFn = | ||
operator === Operator.GREATER_THAN | ||
? (value: number) => value > target | ||
: (value: number) => value < target; | ||
|
||
const index = array.findIndex(comparisonFn); | ||
const found = index !== -1; | ||
const value = found ? array[index] : undefined; | ||
|
||
this.outputs.value.set(value); | ||
this.outputs.index.set(index); | ||
this.outputs.found.set(found); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import findFirst from './findFirst.js'; | ||
import linear from './linear.js'; | ||
|
||
export const nodes = [linear, findFirst]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { | ||
AnyArraySchema, | ||
AnySchema, | ||
BooleanSchema, | ||
NumberSchema | ||
} from '../../schemas/index.js'; | ||
import { INodeDefinition, ToInput, ToOutput } from '../../index.js'; | ||
import { Node } from '../../programmatic/node.js'; | ||
|
||
export default class NodeDefinition<T> extends Node { | ||
static title = 'Linear Search'; | ||
static type = 'studio.tokens.search.linear'; | ||
static description = | ||
'Performs a linear search on an array to find the index of a target value'; | ||
|
||
declare inputs: ToInput<{ | ||
array: T[]; | ||
target: T; | ||
}>; | ||
|
||
declare outputs: ToOutput<{ | ||
index: number; | ||
found: boolean; | ||
}>; | ||
|
||
constructor(props: INodeDefinition) { | ||
super(props); | ||
|
||
this.addInput('array', { | ||
type: { | ||
...AnyArraySchema, | ||
description: 'The array to search through' | ||
} | ||
}); | ||
|
||
this.addInput('target', { | ||
type: { | ||
...AnySchema, | ||
description: 'The value to search for' | ||
} | ||
}); | ||
|
||
this.addOutput('index', { | ||
type: { | ||
...NumberSchema, | ||
description: 'The index of the target value (-1 if not found)' | ||
} | ||
}); | ||
|
||
this.addOutput('found', { | ||
type: { | ||
...BooleanSchema, | ||
description: 'Whether the target value was found' | ||
} | ||
}); | ||
} | ||
|
||
execute(): void | Promise<void> { | ||
const { array, target } = this.getAllInputs(); | ||
|
||
if (!Array.isArray(array)) { | ||
throw new Error('Input must be an array'); | ||
} | ||
|
||
const index = array.findIndex( | ||
item => JSON.stringify(item) === JSON.stringify(target) | ||
); | ||
|
||
this.outputs.index.set(index); | ||
this.outputs.found.set(index !== -1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export enum Operator { | ||
EQUAL = '==', | ||
NOT_EQUAL = '!=', | ||
GREATER_THAN = '>', | ||
LESS_THAN = '<', | ||
GREATER_THAN_OR_EQUAL = '>=', | ||
LESS_THAN_OR_EQUAL = '<=' | ||
} |
66 changes: 66 additions & 0 deletions
66
packages/graph-engine/tests/suites/nodes/search/findFirst.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { Graph } from '../../../../src/graph/graph.js'; | ||
import { Operator } from '../../../../src/schemas/operators.js'; | ||
import { describe, expect, test } from 'vitest'; | ||
import Node from '../../../../src/nodes/search/findFirst.js'; | ||
|
||
describe('search/findFirst', () => { | ||
test('finds first number greater than target', async () => { | ||
const graph = new Graph(); | ||
const node = new Node({ graph }); | ||
|
||
node.inputs.array.setValue([1, 3, 5, 7, 9]); | ||
node.inputs.target.setValue(4); | ||
node.inputs.operator.setValue(Operator.GREATER_THAN); | ||
|
||
await node.execute(); | ||
|
||
expect(node.outputs.value.value).toBe(5); | ||
expect(node.outputs.index.value).toBe(2); | ||
expect(node.outputs.found.value).toBe(true); | ||
}); | ||
|
||
test('finds first number less than target', async () => { | ||
const graph = new Graph(); | ||
const node = new Node({ graph }); | ||
|
||
node.inputs.array.setValue([9, 7, 5, 3, 1]); | ||
node.inputs.target.setValue(6); | ||
node.inputs.operator.setValue(Operator.LESS_THAN); | ||
|
||
await node.execute(); | ||
|
||
expect(node.outputs.value.value).toBe(5); | ||
expect(node.outputs.index.value).toBe(2); | ||
expect(node.outputs.found.value).toBe(true); | ||
}); | ||
|
||
test('handles no match found', async () => { | ||
const graph = new Graph(); | ||
const node = new Node({ graph }); | ||
|
||
node.inputs.array.setValue([1, 2, 3, 4, 5]); | ||
node.inputs.target.setValue(10); | ||
node.inputs.operator.setValue(Operator.GREATER_THAN); | ||
|
||
await node.execute(); | ||
|
||
expect(node.outputs.value.value).toBe(undefined); | ||
expect(node.outputs.index.value).toBe(-1); | ||
expect(node.outputs.found.value).toBe(false); | ||
}); | ||
|
||
test('works with empty array', async () => { | ||
const graph = new Graph(); | ||
const node = new Node({ graph }); | ||
|
||
node.inputs.array.setValue([]); | ||
node.inputs.target.setValue(5); | ||
node.inputs.operator.setValue(Operator.GREATER_THAN); | ||
|
||
await node.execute(); | ||
|
||
expect(node.outputs.value.value).toBe(undefined); | ||
expect(node.outputs.index.value).toBe(-1); | ||
expect(node.outputs.found.value).toBe(false); | ||
}); | ||
}); |
63 changes: 63 additions & 0 deletions
63
packages/graph-engine/tests/suites/nodes/search/linear.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { Graph } from '../../../../src/graph/graph.js'; | ||
import { describe, expect, test } from 'vitest'; | ||
import Node from '../../../../src/nodes/search/linear.js'; | ||
|
||
describe('search/linear', () => { | ||
test('finds exact match in array of numbers', async () => { | ||
const graph = new Graph(); | ||
const node = new Node({ graph }); | ||
|
||
node.inputs.array.setValue([1, 2, 3, 4, 5]); | ||
node.inputs.target.setValue(3); | ||
|
||
await node.execute(); | ||
|
||
expect(node.outputs.index.value).toBe(2); | ||
expect(node.outputs.found.value).toBe(true); | ||
}); | ||
|
||
test('finds exact match in array of objects', async () => { | ||
const graph = new Graph(); | ||
const node = new Node({ graph }); | ||
|
||
const array = [ | ||
{ id: 1, value: 'a' }, | ||
{ id: 2, value: 'b' }, | ||
{ id: 3, value: 'c' } | ||
]; | ||
|
||
node.inputs.array.setValue(array); | ||
node.inputs.target.setValue({ id: 2, value: 'b' }); | ||
|
||
await node.execute(); | ||
|
||
expect(node.outputs.index.value).toBe(1); | ||
expect(node.outputs.found.value).toBe(true); | ||
}); | ||
|
||
test('handles no match found', async () => { | ||
const graph = new Graph(); | ||
const node = new Node({ graph }); | ||
|
||
node.inputs.array.setValue([1, 2, 3, 4, 5]); | ||
node.inputs.target.setValue(6); | ||
|
||
await node.execute(); | ||
|
||
expect(node.outputs.index.value).toBe(-1); | ||
expect(node.outputs.found.value).toBe(false); | ||
}); | ||
|
||
test('handles empty array', async () => { | ||
const graph = new Graph(); | ||
const node = new Node({ graph }); | ||
|
||
node.inputs.array.setValue([]); | ||
node.inputs.target.setValue(1); | ||
|
||
await node.execute(); | ||
|
||
expect(node.outputs.index.value).toBe(-1); | ||
expect(node.outputs.found.value).toBe(false); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters