Skip to content

Commit a18d977

Browse files
committed
EOD: 7-10-24 -> Added Discriminated Unions. Converted clients to lazy loaded singletons. Need to make the combination of discriminated unions and objects generically interpretable
1 parent b365f83 commit a18d977

25 files changed

+106
-142
lines changed

package.json

+6-5
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,26 @@
5151
"@tanstack/react-query": "^5.49.2",
5252
"@thinairthings/utilities": "^0.2.2",
5353
"bundle-n-require": "^1.1.1",
54+
"bundle-require": "^5.0.0",
5455
"dedent": "^1.5.3",
5556
"dotenv": "^16.4.5",
5657
"escalade": "^3.1.2",
5758
"file-type": "^19.0.0",
58-
"immer": "^10.1.1",
5959
"ink": "^5.0.1",
6060
"ink-big-text": "^2.0.0",
6161
"ink-gradient": "^3.0.0",
6262
"ink-spinner": "^5.0.0",
63-
"neo4j-driver": "^5.21.0",
6463
"package-up": "^5.0.0",
6564
"pastel": "^3.0.0",
6665
"react": "^18.3.1",
6766
"uuid": "^10.0.0",
6867
"znv": "^0.4.0",
69-
"zustand": "^4.5.2",
70-
"zod": "^3.23.8"
68+
"zod": "^3.23.8",
69+
"zustand": "^4.5.2"
7170
},
7271
"peerDependencies": {
73-
"openai": "^4.49.0"
72+
"neo4j-driver": "^5.21.0",
73+
"openai": "^4.49.0",
74+
"immer": "^10.1.1"
7475
}
7576
}

src/app/(components)/CommandEnvironment.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { GenericUixConfig, GenericUixConfigDefinition, GenericUixConfigWithoutPa
88
import { applicationStore } from '../(stores)/applicationStore';
99
import { UixErr, UixErrSubtype } from '../../types/Result';
1010
import { Loading } from './Loading';
11-
import { bundleNRequire } from 'bundle-n-require'
11+
import { bundleRequire } from 'bundle-require'
1212
import { findConfig } from '../../utilities/findConfig';
1313
import { GraphType } from '../../types/GraphType';
1414
import path from 'path';
@@ -29,8 +29,8 @@ export const CommandEnvironment: FC<{
2929
operationKey: 'uixConfig',
3030
tryOp: async () => {
3131
const pathToConfig = findConfig({ relativePathToConfig })
32-
const { mod } = await bundleNRequire(pathToConfig, {
33-
interopDefault: true
32+
const { mod } = await bundleRequire({
33+
filepath: pathToConfig,
3434
})
3535
const uixConfigDefinition = mod?.default ?? mod as GenericUixConfigDefinition
3636
const uixConfig = ({

src/clients/neo4j.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import neo4j from 'neo4j-driver';
1+
import neo4j, { Driver } from 'neo4j-driver';
22
import { Neo4jError } from "neo4j-driver"
33
import { AnyErrType, Err, ErrType, Result } from '../types/Result';
44
import { Action } from '../types/Action';
@@ -32,6 +32,17 @@ export enum Neo4jErrorSubtype {
3232
UNKNOWN = 'UNKNOWN',
3333
}
3434

35+
let _neo4jDriver: Driver | null = null
36+
export const neo4jDriver = () => {
37+
if (_neo4jDriver) return _neo4jDriver
38+
_neo4jDriver = createNeo4jClient({
39+
uri: process.env.NEO4J_URI!,
40+
username: process.env.NEO4J_USERNAME!,
41+
password: process.env.NEO4J_PASSWORD!
42+
}, { disableLosslessIntegers: true })
43+
return _neo4jDriver
44+
}
45+
3546
export const neo4jAction = <
3647
Input extends any[],
3748
T,

src/clients/openai.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ export const OpenAIErr = (
2323
export enum OpenAIErrorSubtype {
2424
UNKNOWN = 'UNKNOWN',
2525
}
26-
26+
let _openaiClient: OpenAI | null = null
27+
export const openaiClient = () => {
28+
if (_openaiClient) return _openaiClient
29+
_openaiClient = createOpenAIClient({
30+
apiKey: process.env.OPENAI_API_KEY!
31+
})
32+
return _openaiClient
33+
}
2734

2835
export const openAIAction = <
2936
Input extends any[],

src/config/defineConfig.ts

-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { AnyNodeTypeSet, GenericNodeTypeSet } from "../types/NodeType";
22
import { GraphType } from "../types/GraphType";
3-
import path from 'path';
4-
import { getCallerFile } from "../app/(utilities)/getCallerFile";
53

64
/**
75
* Represents the configuration for the Uix library.
@@ -69,15 +67,3 @@ export const defineConfig = <
6967
): UixConfigDefinition<Type, NodeTypeSet> => ({
7068
...options
7169
})
72-
73-
74-
// {
75-
// return {
76-
// outdir: options.outdir ?? path.join('uix', 'output'),
77-
// graph: new GraphType(
78-
// options.type,
79-
// options.nodeTypeSet,
80-
// ),
81-
// envPath: options.envPath ?? '.env',
82-
// };
83-
// };

src/fns/createNodeFactory.ts

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Driver, EagerResult, Integer, Node } from "neo4j-driver"
22
import { v4 as uuid } from 'uuid'
3-
import { TypeOf, z, ZodDiscriminatedUnion, ZodObject } from "zod"
4-
import { neo4jAction } from "../clients/neo4j"
3+
import { AnyZodObject, TypeOf, z, ZodDiscriminatedUnion, ZodObject } from "zod"
4+
import { neo4jAction, neo4jDriver } from "../clients/neo4j"
55
import { AnyNodeTypeMap, GenericNodeType, GenericNodeTypeMap, Neo4jNodeShape, NodeSetChildNodeTypes, NodeSetParentTypes, NodeShape } from "../types/NodeType"
66
import { ParentOfNodeSetTypes, SetNodeTypes } from "../types/types"
77
import { UixErr, Ok, UixErrSubtype, AnyErrType } from "../types/Result"
@@ -26,9 +26,7 @@ export type GenericCreateNodeAction = Action<
2626
export const createNodeFactory = <
2727
NodeTypeMap extends AnyNodeTypeMap,
2828
>(
29-
neo4jDriver: Driver,
30-
openaiClient: OpenAI,
31-
nodeTypeMap: NodeTypeMap,
29+
nodeTypeMap: NodeTypeMap
3230
) => neo4jAction(async <
3331
ParentOfNodeSetType extends ParentOfNodeSetTypes<NodeTypeMap>,
3432
SetNodeType extends SetNodeTypes<NodeTypeMap, ParentOfNodeSetType>,
@@ -47,10 +45,10 @@ export const createNodeFactory = <
4745
// Check Schema
4846
const stateSchema = (<GenericNodeType>nodeTypeMap[childNodeType]!)['stateSchema']
4947
const newNodeStructure = isZodDiscriminatedUnion(stateSchema)
50-
? z.union(stateSchema.options.map((option: ZodObject<any>) => option.extend({
48+
? z.union(stateSchema.options.map((option: AnyZodObject) => option.merge(z.object({
5149
nodeId: z.string(),
5250
nodeType: z.string()
53-
}))).parse({
51+
}))) as [AnyZodObject, AnyZodObject, ...AnyZodObject[]]).parse({
5452
...initialState,
5553
nodeId: providedNodeId ?? uuid(),
5654
nodeType: childNodeType
@@ -64,7 +62,7 @@ export const createNodeFactory = <
6462
nodeType: childNodeType
6563
})
6664
console.log("Creating", parentNodeKeys, childNodeType, newNodeStructure)
67-
const node = await neo4jDriver.executeQuery<EagerResult<{
65+
const node = await neo4jDriver().executeQuery<EagerResult<{
6866
childNode: Node<Integer, NodeShape<NodeTypeMap[SetNodeType]>>
6967
}>>(/* cypher */ `
7068
merge (childNode:Node:${childNodeType} {nodeId: $childNode.nodeId})
@@ -93,6 +91,6 @@ export const createNodeFactory = <
9391
data: { parentNodeKeys, childNodeType, initialState }
9492
});
9593
// Triggers
96-
await upsertVectorNode(neo4jDriver, openaiClient, node, nodeTypeMap);
94+
await upsertVectorNode(node, nodeTypeMap as GenericNodeTypeMap);
9795
return Ok(node)
9896
})

src/fns/deleteNodeFactory.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Driver, EagerResult } from "neo4j-driver"
2-
import { neo4jAction } from "../clients/neo4j"
2+
import { neo4jAction, neo4jDriver } from "../clients/neo4j"
33
import { AnyNodeTypeMap } from "../types/NodeType"
44
import { UixErr, Ok, UixErrSubtype } from "../types/Result"
55
import { NodeKey } from "../types/NodeKey"
@@ -16,7 +16,6 @@ import { NodeKey } from "../types/NodeKey"
1616
export const deleteNodeFactory = <
1717
NodeTypeMap extends AnyNodeTypeMap,
1818
>(
19-
neo4jDriver: Driver,
2019
nodeTypeMap: NodeTypeMap
2120
) => neo4jAction(async ({
2221
nodeKey
@@ -25,7 +24,7 @@ export const deleteNodeFactory = <
2524
}) => {
2625
console.log("Deleting", nodeKey)
2726
// First, retrieve parent node information
28-
const parentNodeKeys = await neo4jDriver.executeQuery<EagerResult<{
27+
const parentNodeKeys = await neo4jDriver().executeQuery<EagerResult<{
2928
parentNodeId: string,
3029
parentNodeType: string
3130
}>>(/*cypher*/ `
@@ -40,7 +39,7 @@ export const deleteNodeFactory = <
4039

4140
// Step 2: If parentNodeKeys retrieved successfully, then delete childNode
4241
if (parentNodeKeys.length > 0) {
43-
await neo4jDriver.executeQuery(/*cypher*/`
42+
await neo4jDriver().executeQuery(/*cypher*/`
4443
match (childNode:Node {nodeId: $nodeId})<-[:CHILD_TO|UNIQUE_TO|VECTOR_TO*0..]-(recursiveChildNode)
4544
detach delete childNode
4645
detach delete recursiveChildNode

src/fns/getAllOfNodeTypeFactory.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Driver, EagerResult, Integer, Node } from "neo4j-driver"
2-
import { neo4jAction } from "../clients/neo4j"
2+
import { neo4jAction, neo4jDriver } from "../clients/neo4j"
33
import { AnyNodeTypeMap, NodeShape } from "../types/NodeType"
44
import { Ok } from "../types/Result"
55
import neo4j from 'neo4j-driver'
@@ -11,7 +11,6 @@ import neo4j from 'neo4j-driver'
1111
export const getAllOfNodeTypeFactory = <
1212
NodeTypeMap extends AnyNodeTypeMap,
1313
>(
14-
neo4jDriver: Driver,
1514
nodeTypeMap: NodeTypeMap,
1615
) => neo4jAction(async <
1716
NodeType extends keyof NodeTypeMap,
@@ -35,7 +34,7 @@ export const getAllOfNodeTypeFactory = <
3534
const orderBy = options?.orderBy ?? 'updatedAt';
3635
const orderDirection = options?.orderDirection ?? 'ASC';
3736

38-
const nodes = await neo4jDriver.executeQuery<EagerResult<{
37+
const nodes = await neo4jDriver().executeQuery<EagerResult<{
3938
node: Node<Integer, NodeShape<NodeTypeMap[NodeType]>>
4039
}>>(/*cypher*/`
4140
match (node:${nodeType as string})

src/fns/getChildNodeSetFactory.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Driver, EagerResult, Integer, Node } from "neo4j-driver";
2-
import { neo4jAction } from "../clients/neo4j";
2+
import { neo4jAction, neo4jDriver } from "../clients/neo4j";
33
import { AnyNodeTypeMap, NodeSetParentTypes, NodeShape, NodeSetChildNodeTypes } from "../types/NodeType";
44
import { Ok } from "../types/Result";
55
import { NodeKey } from "../types/NodeKey";
@@ -10,7 +10,6 @@ import { NodeKey } from "../types/NodeKey";
1010
export const getChildNodeSetFactory = <
1111
NodeTypeMap extends AnyNodeTypeMap,
1212
>(
13-
neo4jDriver: Driver,
1413
nodeTypeMap: NodeTypeMap,
1514
) => neo4jAction(async <
1615
ParentNodeType extends NodeSetParentTypes<NodeTypeMap>,
@@ -23,7 +22,7 @@ export const getChildNodeSetFactory = <
2322
childNodeType: `${ChildNodeType}`
2423
}) => {
2524
console.log("Getting child nodes of type", childNodeType, "for node of type", parentNodeKey.nodeType, "with id", parentNodeKey.nodeId)
26-
const result = await neo4jDriver.executeQuery<EagerResult<{
25+
const result = await neo4jDriver().executeQuery<EagerResult<{
2726
childNode: Node<Integer, NodeShape<NodeTypeMap[ChildNodeType extends keyof NodeTypeMap ? ChildNodeType : never]>>
2827
}>>(/*cypher*/`
2928
match (parentNode:${parentNodeKey.nodeType as string} {nodeId: $parentNodeId})<-[:CHILD_TO]-(childNode:${childNodeType as string})

src/fns/getNodeByIndexFactory.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Driver, EagerResult, Integer, Node } from "neo4j-driver"
2-
import { neo4jAction } from "../clients/neo4j"
2+
import { neo4jAction, neo4jDriver } from "../clients/neo4j"
33
import { AnyNodeTypeMap, NodeShape } from "../types/NodeType"
44
import { Ok, UixErr, UixErrSubtype } from "../types/Result"
55

@@ -9,7 +9,6 @@ import { Ok, UixErr, UixErrSubtype } from "../types/Result"
99
export const getNodeByIndexFactory = <
1010
NodeTypeMap extends AnyNodeTypeMap,
1111
>(
12-
neo4jDriver: Driver,
1312
nodeTypeMap: NodeTypeMap,
1413
) => neo4jAction(async <
1514
NodeType extends keyof NodeTypeMap,
@@ -24,7 +23,7 @@ export const getNodeByIndexFactory = <
2423
indexValue: string
2524
}) => {
2625
console.log(`Getting node of type ${nodeType as string} with index ${indexKey} = ${indexValue}`);
27-
const node = await neo4jDriver.executeQuery<EagerResult<{
26+
const node = await neo4jDriver().executeQuery<EagerResult<{
2827
node: Node<Integer, NodeShape<NodeTypeMap[NodeType]>>
2928
}>>(/*cypher*/`
3029
match (node:${nodeType as string})

src/fns/getNodeByKeyFactory.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Driver, EagerResult, Integer, Node } from "neo4j-driver";
2-
import { neo4jAction } from "../clients/neo4j";
2+
import { neo4jAction, neo4jDriver } from "../clients/neo4j";
33
import { AnyNodeTypeMap, NodeShape } from "../types/NodeType";
44
import { UixErr, Ok, UixErrSubtype } from "../types/Result";
55
import { NodeKey } from "../types/NodeKey";
@@ -16,7 +16,6 @@ import { NodeKey } from "../types/NodeKey";
1616
export const getNodeByKeyFactory = <
1717
NodeTypeMap extends AnyNodeTypeMap,
1818
>(
19-
neo4jDriver: Driver,
2019
nodeTypeMap: NodeTypeMap,
2120
) => neo4jAction(async <
2221
NodeType extends keyof NodeTypeMap,
@@ -25,7 +24,7 @@ export const getNodeByKeyFactory = <
2524
}: {
2625
nodeKey: NodeKey<NodeTypeMap, NodeType>
2726
}) => {
28-
const node = await neo4jDriver.executeQuery<EagerResult<{
27+
const node = await neo4jDriver().executeQuery<EagerResult<{
2928
node: Node<Integer, NodeShape<NodeTypeMap[NodeType]>>
3029
}>>(/*cypher*/`
3130
match (node:${nodeKey.nodeType as string} {nodeId: $nodeId})

src/fns/getUniqueChildNodeFactory.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Driver, EagerResult, Integer, Node } from "neo4j-driver";
22
import { AnyNodeTypeMap, NodeShape, NodeState, UniqueChildNodeTypes, UniqueParentTypes } from "../types/NodeType";
3-
import { neo4jAction } from "../clients/neo4j";
3+
import { neo4jAction, neo4jDriver } from "../clients/neo4j";
44
import { Ok, Result, UixErr, UixErrSubtype } from "../types/Result";
55
import { v4 as uuid } from 'uuid'
66
import { NodeKey } from "../types/NodeKey";
@@ -9,7 +9,6 @@ import { NodeKey } from "../types/NodeKey";
99
export const getUniqueChildNodeFactory = <
1010
NodeTypeMap extends AnyNodeTypeMap,
1111
>(
12-
neo4jDriver: Driver,
1312
nodeTypeMap: NodeTypeMap,
1413
) => neo4jAction(async <
1514
ParentNodeType extends UniqueParentTypes<NodeTypeMap>,
@@ -22,7 +21,7 @@ export const getUniqueChildNodeFactory = <
2221
childNodeType: `${ChildNodeType}`
2322
}) => {
2423
console.log("Getting child nodes of type", childNodeType, "for node of type", parentNodeKey.nodeType, "with id", parentNodeKey.nodeId)
25-
const node = await neo4jDriver.executeQuery<EagerResult<{
24+
const node = await neo4jDriver().executeQuery<EagerResult<{
2625
childNode: Node<Integer, NodeShape<NodeTypeMap[ChildNodeType]>>
2726
}>>(/*cypher*/`
2827
merge (parentNode:${parentNodeKey.nodeType as string} {nodeId: $parentNodeId})

src/fns/getVectorNodeByKeyFactory.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Driver, EagerResult, Integer, Node } from "neo4j-driver";
22
import { AnyNodeTypeMap, VectorNodeShape } from "../types/NodeType";
3-
import { neo4jAction } from "../clients/neo4j";
3+
import { neo4jAction, neo4jDriver } from "../clients/neo4j";
44
import { Ok, UixErr, UixErrSubtype } from "../types/Result";
55
import { NodeKey, TypeFromVectorType, VectorKeys } from "../types/NodeKey";
66

@@ -11,7 +11,6 @@ import { NodeKey, TypeFromVectorType, VectorKeys } from "../types/NodeKey";
1111
export const getVectorNodeByKeyFactory = <
1212
NodeTypeMap extends AnyNodeTypeMap
1313
>(
14-
neo4jDriver: Driver,
1514
nodeTypeMap: NodeTypeMap,
1615
) => neo4jAction(async <
1716
NodeType extends VectorKeys<NodeTypeMap>,
@@ -20,7 +19,7 @@ export const getVectorNodeByKeyFactory = <
2019
}: {
2120
nodeKey: NodeKey<NodeTypeMap, NodeType>
2221
}) => {
23-
const node = await neo4jDriver.executeQuery<EagerResult<{
22+
const node = await neo4jDriver().executeQuery<EagerResult<{
2423
node: Node<Integer, VectorNodeShape<NodeTypeMap[TypeFromVectorType<NodeTypeMap, NodeType>]>>
2524
}>>(/*cypher*/`
2625
match (node:${nodeKey.nodeType as string} {nodeId: $nodeId})

src/fns/updateNodeFactory.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import { Driver, EagerResult, error, Integer, Node } from "neo4j-driver"
44
import { AnyNodeTypeMap, GenericNodeType, NodeShape, NodeState } from "../types/NodeType"
5-
import { neo4jAction } from "../clients/neo4j"
5+
import { neo4jAction, neo4jDriver } from "../clients/neo4j"
66
import { UixErr, Ok, UixErrSubtype } from "../types/Result"
77
import OpenAI from "openai"
88
import { openAIAction } from "../clients/openai"
99
import { NodeKey } from "../types/NodeKey"
1010
import { upsertVectorNode } from "../vectors/upsertVectorNode"
11-
import { z, ZodDiscriminatedUnion, ZodObject } from "zod"
11+
import { AnyZodObject, z, ZodDiscriminatedUnion, ZodObject } from "zod"
1212
import { isZodDiscriminatedUnion } from "../utilities/isZodDiscriminatedUnion"
1313

1414

@@ -21,8 +21,6 @@ import { isZodDiscriminatedUnion } from "../utilities/isZodDiscriminatedUnion"
2121
export const updateNodeFactory = <
2222
NodeTypeMap extends AnyNodeTypeMap
2323
>(
24-
neo4jDriver: Driver,
25-
openaiClient: OpenAI,
2624
nodeTypeMap: NodeTypeMap
2725
) => neo4jAction(openAIAction(async <
2826
NodeType extends NodeTypeMap[keyof NodeTypeMap]['type']
@@ -37,10 +35,10 @@ export const updateNodeFactory = <
3735
const stateSchema = (<GenericNodeType>nodeTypeMap[nodeKey.nodeType]!)['stateSchema']
3836
// Strip out any properties that are not in the schema
3937
const strippedNodeState = isZodDiscriminatedUnion(stateSchema)
40-
? z.union(stateSchema.options.map((option: ZodObject<any>) => option.partial())).parse(inputState)
38+
? z.union(stateSchema.options.map((option: AnyZodObject) => option.partial()) as [AnyZodObject, AnyZodObject, ...AnyZodObject[]]).parse(inputState)
4139
: stateSchema.partial().parse(inputState)
4240

43-
const node = await neo4jDriver.executeQuery<EagerResult<{
41+
const node = await neo4jDriver().executeQuery<EagerResult<{
4442
node: Node<Integer, NodeShape<NodeTypeMap[NodeType]>>
4543
}>>(/*cypher*/`
4644
match (node:${nodeKey.nodeType} {nodeId: $nodeId})
@@ -66,6 +64,6 @@ export const updateNodeFactory = <
6664
// Note: This should really be broken out into an SQS event to prevent blocking the main thread
6765
// Arguably, optimistic updates with react-query also solves this.
6866
// NOTE: You should check what actually changes using immer here. You can probably have neo return the prevNode and currentNode
69-
await upsertVectorNode(neo4jDriver, openaiClient, node, nodeTypeMap)
67+
await upsertVectorNode(node, nodeTypeMap)
7068
return Ok(node)
7169
}))

0 commit comments

Comments
 (0)