Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Prebuilt cstx-ffi static libraries are delivered by the cstx release
# pipeline (synced with git add -f into libcstx), never built in-tree.
lib/**/*.a
lib/**/*.lib
lib/**/*.so
lib/**/*.dylib
167 changes: 0 additions & 167 deletions go/cas.go

This file was deleted.

7 changes: 0 additions & 7 deletions go/cgo_darwin_amd64.go

This file was deleted.

7 changes: 0 additions & 7 deletions go/cgo_darwin_arm64.go

This file was deleted.

7 changes: 0 additions & 7 deletions go/cgo_linux_amd64.go

This file was deleted.

7 changes: 0 additions & 7 deletions go/cgo_linux_arm64.go

This file was deleted.

7 changes: 0 additions & 7 deletions go/cgo_windows_amd64.go

This file was deleted.

42 changes: 42 additions & 0 deletions go/contract_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cstx

import (
"reflect"
"sort"
"strings"
"testing"
)

// The transport contract is owned by cstx.core.elements (Node/Edge pydantic
// models) and mirrored by codegen/generate_transport_ts.py. These tests pin
// the Go structs to the same field sets so the three languages cannot drift.
func jsonFieldNames(t *testing.T, value any) []string {
t.Helper()
typ := reflect.TypeOf(value)
var names []string
for i := 0; i < typ.NumField(); i++ {
tag := typ.Field(i).Tag.Get("json")
if tag == "" || tag == "-" {
continue
}
names = append(names, strings.Split(tag, ",")[0])
}
sort.Strings(names)
return names
}

func TestNodeMatchesTransportContract(t *testing.T) {
got := jsonFieldNames(t, Node{})
want := []string{"extras", "id", "model", "sources", "type", "value"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("node fields drifted from transport contract: got %v want %v", got, want)
}
}

func TestEdgeMatchesTransportContract(t *testing.T) {
got := jsonFieldNames(t, Edge{})
want := []string{"attrs", "id", "relation_type", "source_id", "sources", "target_id"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("edge fields drifted from transport contract: got %v want %v", got, want)
}
}
97 changes: 97 additions & 0 deletions go/cstx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package cstx

import (
"context"
"errors"
"sync"
)

// Config configures an in-memory CSTX runtime.
type Config struct {
// ProjectID namespaces the runtime; defaults to "default".
ProjectID string
// CursorPageSize bounds incremental cursor materialization; defaults to
// DefaultCursorPageSize.
CursorPageSize int
}

func (c Config) normalize() Config {
if c.ProjectID == "" {
c.ProjectID = "default"
}
if c.CursorPageSize <= 0 {
c.CursorPageSize = DefaultCursorPageSize
}
return c
}

// CSTX is the single owner of shared schema, graph, and repository
// state. Create it with Open and release it with Close.
type CSTX struct {
eng engine
projectID string

// Schemas, Graph, and Repo are lightweight namespaces sharing
// this runtime's state.
Schemas *Schemas
Graph *Graph
Repo *Repository

mu sync.Mutex
closed bool
}

// Open creates an in-memory runtime. Without the cstx_native build tag it
// returns ErrNativeUnavailable.
func Open(ctx context.Context, config Config) (*CSTX, error) {
if err := contextError(ctx); err != nil {
return nil, err
}
config = config.normalize()
eng, err := newEngine(config)
if err != nil {
return nil, err
}
rt := &CSTX{eng: eng, projectID: config.ProjectID}
rt.Schemas = &Schemas{eng: eng}
rt.Graph = &Graph{eng: eng}
rt.Repo = &Repository{eng: eng}
return rt, nil
}

func contextError(ctx context.Context) error {
if ctx == nil {
return errors.New("cstx: nil context")
}
return ctx.Err()
}

// ProjectID returns the immutable project namespace supplied at Open.
func (c *CSTX) ProjectID() string { return c.projectID }

// Close releases shared state and invalidates retained services and cursors.
// Repeated calls are safe.
func (c *CSTX) Close() error {
c.mu.Lock()
defer c.mu.Unlock()
if c.closed {
return nil
}
c.closed = true
return c.eng.close()
}

// Closed reports whether Close has been called.
func (c *CSTX) Closed() bool {
c.mu.Lock()
defer c.mu.Unlock()
return c.closed
}

// LastChange returns the IDs changed by the most recent committed mutation.
func (c *CSTX) LastChange(ctx context.Context) (ChangeSet, error) {
if err := contextError(ctx); err != nil {
return ChangeSet{}, err
}
return c.eng.lastChange(ctx)
}
Loading
Loading