Skip to content

Add Vertex support#373

Merged
em3s merged 6 commits into
mainfrom
feature/add-vertex-support
Jun 4, 2026
Merged

Add Vertex support#373
em3s merged 6 commits into
mainfrom
feature/add-vertex-support

Conversation

@em3s

@em3s em3s commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Add Vertex as a first-class entity type alongside Edge and MultiEdge. Vertex reuses the existing EdgeState encoding with source=key, target="-" (VERTEX_MARKER), so existing storage format and encoding pipeline are shared.

Key design decisions:

  • LabelType.VERTEX added to codec-java so Vertex is identified by type.
  • EdgeMutationStrategy.Vertex suppresses all EdgeCount writes (producesCount = false)

Closes #361

Changes

  • codec-java: LabelType.VERTEX, BulkEdgeEncoder encodes State only (no index, no counter)
  • core: ModelSchema.Vertex, TableDescriptor.Vertex, EdgeMutationStrategy.Vertex, VertexBulkMutationRequest, VertexMutationResponse, DataFrameVertexPayload
  • engine: V3TableDescriptor.create() restores LabelType.VERTEX → V3TableDescriptor.Vertex on reload; V2BackedTableBinding routes Vertex to buildForVertex()
  • server: VertexMutationController (POST /vertices, POST /vertices/sync), VertexQueryController (GET /vertices/get), schema/DDL wiring in TableCreateRequest, V3CompatService, V3MetadataConverter

How to Test

./gradlew test

New test coverage:

  • VertexBulkMutationRequestTest: createEvent — source=id, target=VERTEX_MARKER, nullability validation, reserved id guard
  • EdgeMutationStrategyTest / EdgeMutationBuilderTest: Vertex strategy — producesCount=false, no count records on CREATED/UPDATED/DELETED
  • BulkEdgeEncoderTests: active/inactive Vertex → State only, no counter rows
  • V3MetadataConverterTest: LabelType.VERTEXTableDescriptor.Vertex round-trip
  • MutationServiceSpec: Vertex insert/update/delete/get engine-level flow
  • VertexIntegrationTest: full E2E — table create, mutation, get, update, delete

AI Assistance

  • This PR was written largely with AI assistance.
    • Tool / model: Claude Code (claude-sonnet-4-6)

Closes #361

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request labels Jun 3, 2026
em3s and others added 2 commits June 3, 2026 23:11
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@em3s

em3s commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

Usage Examples

0. Setup: Create database and table

# Create database
curl -X POST "http://localhost:8080/graph/v3/databases"   -H "Content-Type: application/json"   -d '{"database": "mydb", "comment": "my database"}'

# Create vertex table
curl -X POST "http://localhost:8080/graph/v3/databases/mydb/tables"   -H "Content-Type: application/json"   -d '{
    "table": "users",
    "schema": {
      "type": "VERTEX",
      "id": {"type": "string", "comment": "user id"},
      "properties": [
        {"name": "name", "type": "string", "comment": "display name"},
        {"name": "age",  "type": "long",   "comment": "age", "nullable": true}
      ]
    },
    "storage": "datastore://my_namespace/users",
    "mode": "SYNC",
    "comment": "user vertex table"
  }'

1. Insert vertices

curl -X POST "http://localhost:8080/graph/v3/databases/mydb/tables/users/vertices"   -H "Content-Type: application/json"   -d '{
    "mutations": [
      {"type": "INSERT", "vertex": {"version": 1, "id": "user1", "properties": {"name": "Alice", "age": 30}}},
      {"type": "INSERT", "vertex": {"version": 1, "id": "user2", "properties": {"name": "Bob"}}}
    ]
  }'
{
  "results": [
    {"id": "user1", "status": "CREATED", "count": 1},
    {"id": "user2", "status": "CREATED", "count": 1}
  ]
}

2. Update a vertex

curl -X POST "http://localhost:8080/graph/v3/databases/mydb/tables/users/vertices"   -H "Content-Type: application/json"   -d '{
    "mutations": [
      {"type": "UPDATE", "vertex": {"version": 2, "id": "user1", "properties": {"name": "Alice Smith"}}}
    ]
  }'
{"results": [{"id": "user1", "status": "UPDATED", "count": 1}]}

3. Delete a vertex

curl -X POST "http://localhost:8080/graph/v3/databases/mydb/tables/users/vertices"   -H "Content-Type: application/json"   -d '{
    "mutations": [
      {"type": "DELETE", "vertex": {"version": 3, "id": "user2", "properties": {}}}
    ]
  }'
{"results": [{"id": "user2", "status": "DELETED", "count": 1}]}

4. Insert (sync) — wait for write to complete

curl -X POST "http://localhost:8080/graph/v3/databases/mydb/tables/users/vertices/sync"   -H "Content-Type: application/json"   -d '{
    "mutations": [
      {"type": "INSERT", "vertex": {"version": 1, "id": "user3", "properties": {"name": "Carol", "age": 25}}}
    ]
  }'

5. Get vertices (multi-get)

curl "http://localhost:8080/graph/v3/databases/mydb/tables/users/vertices/get?id=user1,user2,user3"
{
  "vertices": [
    {"version": 2, "id": "user1", "properties": {"name": "Alice Smith", "age": 30}, "context": {}},
    {"version": 1, "id": "user3", "properties": {"name": "Carol", "age": 25}, "context": {}}
  ],
  "count": 2,
  "total": 2,
  "context": {}
}

user2 was deleted and is excluded. Unknown IDs are silently skipped.

@em3s

em3s commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

Internal representation note

Vertex is stored as an Edge with source=id, target="-" (VERTEX_MARKER). The Edge API can reach the same row — this is not how you should use it, but it shows that the two types share the same storage format:

# Vertex API
curl "http://localhost:8080/graph/v3/databases/mydb/tables/users/vertices/get?id=user1"
# {"vertices": [{"version": 1, "id": "user1", "properties": {"name": "Alice"}, "context": {}}], ...}

# Edge API — same row, internal encoding exposed (do not use this way)
curl "http://localhost:8080/graph/v3/databases/mydb/tables/users/edges/get?source=user1&target=-"
# {"edges": [{"version": 1, "source": "user1", "target": "-", "properties": {"name": "Alice"}, "context": {}}], ...}

em3s and others added 3 commits June 4, 2026 08:53
Address review findings on the vertex feature branch before merging:

- VertexQueryController: accept `List<Any>` for id query param so LONG-typed
  vertex tables can multi-get by numeric id (matches MultiEdgeQueryController).
  Add a LONG-id integration test to lock in the regression.

- LabelEntity: vertex stores State only — indices, groups, caches, and
  IN/BOTH directions are silently dropped by BulkEdgeEncoder and the v3
  schema converter. Reject them at construction so inconsistent metadata
  never reaches storage. Cover each rejection in LabelEntitySpec.

- TableUpdateRequest: a vertex update returned `emptyList()` for indices,
  groups, and caches, which `LabelUpdateRequest.toNotNullMap()` would
  serialize and overwrite the existing list with. Return `null` instead so
  vertex updates are no-ops on those fields.

- MutationRequestValidator.checkNonNullableFields: revert visibility from
  public to internal. The vertex payload lives in the same `core` Gradle
  module, so internal access suffices and avoids broadening the contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the single @test case for VERTEX LabelEntity → V3TableDescriptor
with an @ObjectSourceParameterizedTest. Drives both STRING and LONG id
types from data and asserts against the parameter values, matching the
@ObjectSource convention used elsewhere in this file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@em3s

em3s commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

Verified locally — all curl examples in the comments above work as expected. Merging.

@em3s em3s merged commit 9d18d6c into main Jun 4, 2026
3 checks passed
@em3s em3s deleted the feature/add-vertex-support branch June 4, 2026 07:12
@em3s em3s mentioned this pull request Jun 11, 2026
1 task
@em3s em3s self-assigned this Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Vertex Support

1 participant