Skip to content

Commit 165fd6c

Browse files
authored
Merge pull request #1 from codemix/docs
Enhance README with detailed descriptions of type-safe TinkerPop/Gremlin traversal API and its integration in the @codemix/graph package. Update package descriptions for clarity and consistency.
2 parents 018bee4 + 048fe8d commit 165fd6c

324 files changed

Lines changed: 8820 additions & 18474 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, master]
6+
pull_request:
7+
workflow_dispatch:
8+
9+
concurrency:
10+
group: ci-${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions:
14+
contents: read
15+
16+
jobs:
17+
ci:
18+
runs-on: ubuntu-latest
19+
timeout-minutes: 30
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- uses: pnpm/action-setup@v4
24+
with:
25+
version: 10
26+
27+
- uses: actions/setup-node@v4
28+
with:
29+
node-version: 22
30+
cache: pnpm
31+
32+
- name: Install dependencies
33+
run: pnpm install --frozen-lockfile
34+
35+
- name: Lint
36+
run: pnpm run lint
37+
38+
- name: Format check
39+
run: pnpm run format:check
40+
41+
- name: Build
42+
run: pnpm run build
43+
44+
- name: Typecheck
45+
run: pnpm run typecheck
46+
47+
- name: Test
48+
run: pnpm exec vitest run

.oxfmtrc.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"$schema": "./node_modules/oxfmt/configuration_schema.json",
3+
"ignorePatterns": ["**/grammar.js", "**/grammar.d.ts"]
4+
}

README.md

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
# @codemix/graph
22

3-
A full type safe,TypeScript-first in-memory property graph database with a Cypher query language parser, multiple index types, and pluggable storage adapters.
3+
A fully type-safe, TypeScript-first in-memory property graph database with a Cypher query language parser, a **type-safe [TinkerPop](https://tinkerpop.apache.org/) / [Gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin)-style traversal API** (`GraphTraversal`), multiple index types, and pluggable storage adapters including a [Yjs](https://yjs.dev/) CRDT-based adapter for collaborative/realtime/offline-first use.
4+
5+
This is the knowledge graph database for the [codemix](https://codemix.com/) product intelligence platform.
46

57
## Packages
68

7-
| Package | Version | Description |
8-
| -------------------------------------------------------- | ------- | -------------------------------------------------------------------------------- |
9-
| [`@codemix/graph`](./packages/graph) | 0.0.1 | Core graph database with Cypher query support |
10-
| [`@codemix/text-search`](./packages/text-search) | 0.0.1 | BM25-based full-text search with English stemming |
11-
| [`@codemix/y-graph-storage`](./packages/y-graph-storage) | 0.0.1 | [Yjs](https://yjs.dev/) CRDT storage adapter for collaborative/offline-first use |
9+
| Package | Version | Description |
10+
| -------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
11+
| [`@codemix/graph`](./packages/graph) | 0.0.1 | Core graph database: Cypher queries + type-safe Gremlin-style traversals (`GraphTraversal`) |
12+
| [`@codemix/text-search`](./packages/text-search) | 0.0.1 | BM25-based full-text search with English stemming |
13+
| [`@codemix/y-graph-storage`](./packages/y-graph-storage) | 0.0.1 | [Yjs](https://yjs.dev/) CRDT storage adapter for collaborative/offline-first use |
1214

1315
---
1416

1517
## `@codemix/graph`
1618

17-
A fully typed, in-memory graph database. Vertices and edges are strongly typed against a user-defined schema. Queries are written in a subset of [Cypher](https://neo4j.com/docs/cypher-manual/current/).
19+
A fully typed, in-memory graph database. Vertices and edges are strongly typed against a user-defined schema. You can query with a subset of [Cypher](https://neo4j.com/docs/cypher-manual/current/) **or** with a fluent, **type-safe [Apache TinkerPop](https://tinkerpop.apache.org/) / [Gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin)-style API** — see [`GraphTraversal`](./packages/graph/README.md#type-safe-tinkerpop--gremlin-traversal-api) in the package docs.
1820

1921
### Features
2022

23+
- **Type-safe TinkerPop / Gremlin traversals**`GraphTraversal` exposes familiar steps (`V()`, `E()`, `out()`, `in()`, `both()`, `hasLabel()`, `as()` / `select()`, `repeat()` …) with schema-derived typing on paths and properties; pairs with `AsyncGraph.query` for remote execution
2124
- **Cypher query language** — parsed via a PEG grammar, supporting `MATCH`, `WHERE`, `RETURN`, `CREATE`, `SET`, `DELETE`, `MERGE`, `UNWIND`, `UNION`, `WITH`, multi-statement queries, and more
2225
- **Strongly typed schema** — vertex/edge labels and their properties are defined once and inferred throughout
2326
- **Standard Schema validation** — property values are validated using [Standard Schema](https://standardschema.dev/) compatible validators (works with Zod, Valibot, etc.)
@@ -65,12 +68,25 @@ const bob = graph.addVertex("Person", { name: "Bob", age: 25 });
6568
graph.addEdge(alice, "knows", bob, {});
6669

6770
// 4. Query with Cypher
68-
const results = graph.query(
69-
"MATCH (a:Person)-[:knows]->(b:Person) RETURN a.name, b.name",
70-
);
71+
const results = graph.query("MATCH (a:Person)-[:knows]->(b:Person) RETURN a.name, b.name");
7172
// [{ a: { name: "Alice" }, b: { name: "Bob" } }]
7273
```
7374

75+
### Type-safe Gremlin-style traversals
76+
77+
The same graph is navigable with a fluent API modeled on [Apache TinkerPop Gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin); labels and properties stay typed end-to-end:
78+
79+
```typescript
80+
import { GraphTraversal } from "@codemix/graph";
81+
82+
const g = new GraphTraversal(graph);
83+
for (const path of g.V().hasLabel("Person").out("knows")) {
84+
console.log(path.value.get("name"));
85+
}
86+
```
87+
88+
See the [type-safe TinkerPop / Gremlin traversal API](./packages/graph/README.md#type-safe-tinkerpop--gremlin-traversal-api) section in `@codemix/graph` for the full step reference.
89+
7490
### Defining a Schema
7591

7692
```typescript
@@ -268,7 +284,7 @@ pnpm install
268284
| `pnpm typecheck` | Type-check all packages |
269285
| `pnpm lint` | Lint with oxlint |
270286
| `pnpm lint:fix` | Lint and auto-fix |
271-
| `pnpm format` | Format with Prettier |
287+
| `pnpm format` | Format with oxfmt |
272288
| `pnpm format:check` | Check formatting |
273289

274290
### Package-level commands

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
{
22
"name": "@codemix/graph-monorepo",
33
"version": "1.0.0",
4+
"private": true,
45
"description": "The codemix graph database monorepo",
6+
"keywords": [],
7+
"license": "MIT",
58
"workspaces": [
69
"packages/*"
710
],
@@ -12,16 +15,13 @@
1215
"test:coverage": "vitest run --coverage",
1316
"lint": "oxlint --ignore-pattern '**/grammar.js' .",
1417
"lint:fix": "pnpm run lint --fix",
15-
"format": "prettier --write .",
16-
"format:check": "prettier --check ."
18+
"format": "oxfmt --write .",
19+
"format:check": "oxfmt --check ."
1720
},
18-
"keywords": [],
19-
"license": "MIT",
20-
"private": true,
2121
"devDependencies": {
2222
"@vitest/coverage-istanbul": "catalog:",
23-
"oxlint": "^1.59.0",
2423
"oxfmt": "^0.44.0",
24+
"oxlint": "^1.59.0",
2525
"typescript": "catalog:",
2626
"vitest": "catalog:"
2727
}

packages/graph/README.md

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# @codemix/graph
22

3-
A fully type safe, TypeScript-first in-memory property graph database with a Cypher-compatible query language, a fluent traversal API, lazy indexes, and async transport support.
3+
A fully type-safe, TypeScript-first in-memory property graph database with a Cypher-compatible query language, a **type-safe [Apache TinkerPop](https://tinkerpop.apache.org/) / [Gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin)-style traversal API** (`GraphTraversal`), lazy indexes, and async transport support.
44

55
## Table of Contents
66

@@ -19,7 +19,7 @@ A fully type safe, TypeScript-first in-memory property graph database with a Cyp
1919
- [Supported Clauses](#supported-clauses)
2020
- [Supported Functions](#supported-functions)
2121
- [Supported Procedures](#supported-procedures)
22-
- [Traversal API](#traversal-api)
22+
- [Type-safe TinkerPop / Gremlin traversal API](#type-safe-tinkerpop--gremlin-traversal-api)
2323
- [Starting a Traversal](#starting-a-traversal)
2424
- [Navigation Steps](#navigation-steps)
2525
- [Filtering](#filtering)
@@ -44,7 +44,7 @@ A fully type safe, TypeScript-first in-memory property graph database with a Cyp
4444

4545
- **TypeScript-first** — schema-derived types flow through the entire API; vertex/edge properties are fully typed.
4646
- **Cypher-compatible query language** — parse and execute `MATCH … WHERE … RETURN` queries, `UNION`, multi-statement queries, `CREATE`, `SET`, `DELETE`, `MERGE`, `UNWIND`, `CALL`, `FOREACH`, and more.
47-
- **Fluent traversal API**a gremlin-inspired builder that produces strongly-typed `TraversalPath` chains (`V().out().hasLabel(…).as(…).select(…)`).
47+
- **Type-safe TinkerPop / Gremlin traversals**`GraphTraversal` mirrors familiar Gremlin steps (`V`, `E`, `out` / `in` / `both`, `hasLabel`, `as` / `select`, `repeat`, …) with **schema-derived TypeScript types** on `TraversalPath` and property access, not untyped strings at every hop.
4848
- **Lazy indexes** — hash, B-tree, and full-text indexes are built on first use and maintained incrementally on every mutation.
4949
- **Unique constraints** — enforce uniqueness on any indexed property.
5050
- **Standard Schema validation** — property types are validated via the [Standard Schema](https://github.com/standard-schema/standard-schema) spec (compatible with Zod, Valibot, ArkType, etc.).
@@ -66,12 +66,7 @@ pnpm add @codemix/graph
6666
## Quick Start
6767

6868
```ts
69-
import {
70-
Graph,
71-
GraphSchema,
72-
InMemoryGraphStorage,
73-
GraphTraversal,
74-
} from "@codemix/graph";
69+
import { Graph, GraphSchema, InMemoryGraphStorage, GraphTraversal } from "@codemix/graph";
7570
import * as v from "valibot"; // any Standard Schema library
7671

7772
const schema = {
@@ -229,12 +224,7 @@ graph.deleteEdge(edge);
229224
Use `parseQueryToSteps` to compile a Cypher string and get back executable steps plus a result mapper:
230225

231226
```ts
232-
import {
233-
Graph,
234-
InMemoryGraphStorage,
235-
parseQueryToSteps,
236-
GraphTraversal,
237-
} from "@codemix/graph";
227+
import { Graph, InMemoryGraphStorage, parseQueryToSteps, GraphTraversal } from "@codemix/graph";
238228

239229
const { steps, postprocess } = parseQueryToSteps(
240230
"MATCH (p:Person)-[:ACTED_IN]->(m:Movie) WHERE p.name = $name RETURN p.name, m.title",
@@ -330,7 +320,11 @@ procedureRegistry.register({
330320

331321
---
332322

333-
## Traversal API
323+
## Type-safe TinkerPop / Gremlin traversal API
324+
325+
`GraphTraversal` ([`src/Traversals.ts`](./src/Traversals.ts)) is the programmatic counterpart to Cypher: a **fluent, Gremlin-style** API in the spirit of [Apache TinkerPop](https://tinkerpop.apache.org/) — same mental model as `g.V().out('knows')` in Gremlin — but **fully typed** against your `GraphSchema` so labels, edge directions, and property keys are checked by TypeScript.
326+
327+
If you already know Gremlin, the step names and composition will feel familiar; the main difference is that paths carry typed vertices/edges from your schema instead of generic maps.
334328

335329
### Starting a Traversal
336330

@@ -373,12 +367,7 @@ g.V()
373367
### Labeling and Selection
374368

375369
```ts
376-
g.V()
377-
.hasLabel("Person")
378-
.as("actor")
379-
.out("ACTED_IN")
380-
.as("movie")
381-
.select("actor", "movie");
370+
g.V().hasLabel("Person").as("actor").out("ACTED_IN").as("movie").select("actor", "movie");
382371
// yields { actor: TraversalPath, movie: TraversalPath }
383372
```
384373

@@ -506,11 +495,7 @@ Duplicate inserts into a unique-indexed property throw `UniqueConstraintViolatio
506495
**Server side:**
507496

508497
```ts
509-
import {
510-
Graph,
511-
InMemoryGraphStorage,
512-
handleAsyncCommand,
513-
} from "@codemix/graph";
498+
import { Graph, InMemoryGraphStorage, handleAsyncCommand } from "@codemix/graph";
514499

515500
const graph = new Graph({ schema, storage: new InMemoryGraphStorage() });
516501

@@ -549,12 +534,7 @@ for await (const path of remote.query((g) => g.V().hasLabel("Person"))) {
549534
Implement the `GraphStorage` interface to plug in any backend:
550535

551536
```ts
552-
import {
553-
GraphStorage,
554-
StoredVertex,
555-
StoredEdge,
556-
ElementId,
557-
} from "@codemix/graph";
537+
import { GraphStorage, StoredVertex, StoredEdge, ElementId } from "@codemix/graph";
558538

559539
class MyStorage implements GraphStorage {
560540
getVertexById(id: ElementId): StoredVertex | undefined {
@@ -608,10 +588,7 @@ const graph = new Graph({ schema, storage: new MyStorage() });
608588
Generate a human (or LLM) readable description of the query language and your schema for use in prompts or documentation:
609589

610590
```ts
611-
import {
612-
generateGrammarDescription,
613-
generateSchemaGuide,
614-
} from "@codemix/graph";
591+
import { generateGrammarDescription, generateSchemaGuide } from "@codemix/graph";
615592

616593
// Language grammar description (schema-agnostic)
617594
const grammar = generateGrammarDescription();

packages/graph/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
"name": "@codemix/graph",
33
"version": "0.0.1",
44
"description": "The codemix graph database.",
5+
"license": "MIT",
56
"type": "module",
7+
"types": "./dist/index.d.ts",
68
"exports": {
79
".": {
810
"import": {
@@ -11,23 +13,21 @@
1113
}
1214
}
1315
},
14-
"types": "./dist/index.d.ts",
15-
"license": "MIT",
1616
"scripts": {
1717
"build": "pnpm run build:grammar && tsc",
1818
"build:grammar": "peggy --format es src/grammar.peggy -o src/grammar.js --dts --return-types '{\"MultiStatement\": \"import('\\''./AST.js'\\'').Query | import('\\''./AST.js'\\'').UnionQuery | import('\\''./AST.js'\\'').MultiStatement\", \"CypherStatement\": \"import('\\''./AST.js'\\'').Query | import('\\''./AST.js'\\'').UnionQuery\"}' && mkdir -p dist && cp src/grammar.* dist",
1919
"typecheck": "tsc --noEmit",
2020
"test": "vitest",
2121
"test:coverage": "vitest run --coverage"
2222
},
23-
"devDependencies": {
24-
"@vitest/coverage-istanbul": "catalog:",
25-
"vitest": "catalog:",
26-
"typescript": "catalog:",
27-
"peggy": "^5.1.0"
28-
},
2923
"dependencies": {
3024
"@codemix/text-search": "workspace:*",
3125
"@standard-schema/spec": "^1.1.0"
26+
},
27+
"devDependencies": {
28+
"@vitest/coverage-istanbul": "catalog:",
29+
"peggy": "^5.1.0",
30+
"typescript": "catalog:",
31+
"vitest": "catalog:"
3232
}
3333
}

0 commit comments

Comments
 (0)