| Crates.io | kotoba |
| lib.rs | kotoba |
| version | 0.1.3 |
| created_at | 2025-09-14 07:25:07.058036+00 |
| updated_at | 2025-09-14 18:46:24.578158+00 |
| description | GP2-based Graph Rewriting Language - ISO GQL-compliant queries, MVCC+Merkle persistence, and distributed execution |
| homepage | https://github.com/jun784/kotoba |
| repository | https://github.com/jun784/kotoba |
| max_upload_size | |
| id | 1838428 |
| size | 2,427,956 |
Graph Processing System with Jsonnet Integration - A comprehensive graph processing platform featuring complete Jsonnet implementation, ISO GQL-compliant queries, and distributed execution.
Kotoba is a powerful graph processing system built on graph theory foundations. It combines a complete Jsonnet implementation with GP2-based graph rewriting, providing ISO GQL-compliant queries, MVCC+Merkle persistence, and distributed execution capabilities.
For a reproducible and stable development environment, use Nix with flakes:
# Install Nix (if not already installed)
curl -L https://nixos.org/nix/install | sh
# Enable flakes (add to ~/.config/nix/nix.conf)
experimental-features = nix-command flakes
# Clone and enter the project
git clone https://github.com/jun784/kotoba.git
cd kotoba
# Run setup script
./scripts/setup-nix.sh
# Enter development environment
nix develop
# Or use direnv for automatic activation
direnv allow # (if direnv is installed)
The Nix environment provides:
# Clone the repository
git clone https://github.com/jun784/kotoba.git
cd kotoba
# Install dependencies and build
cargo build
# Run comprehensive test suite (38/38 tests passing)
cargo test --workspace
# Build release version
cargo build --release
Kotoba includes a complete Jsonnet implementation supporting arrays, objects, functions, and string interpolation:
example.jsonnet
// Local variables and functions
local version = "1.0.0";
local add = function(x, y) x + y;
// Object with computed values
{
app: {
name: "Kotoba Demo",
version: version,
features: ["jsonnet", "graph", "gql"],
},
// Array operations
numbers: [1, 2, 3, 4, 5],
doubled: [x * 2 for x in self.numbers],
// String interpolation
greeting: "Hello, %(name)s!" % { name: "World" },
// Function calls
sum: add(10, 20),
// Conditional logic
status: if self.sum > 25 then "high" else "low",
}
Run with Kotoba:
# Evaluate Jsonnet file
cargo run --bin kotoba-jsonnet evaluate example.jsonnet
# Convert to JSON
cargo run --bin kotoba-jsonnet to-json example.jsonnet
Users create .kotoba files in Jsonnet format for graph processing:
graph.kotoba
{
// Graph data
graph: {
vertices: [
{ id: "alice", labels: ["Person"], properties: { name: "Alice", age: 30 } },
{ id: "bob", labels: ["Person"], properties: { name: "Bob", age: 25 } },
],
edges: [
{ id: "follows_1", src: "alice", dst: "bob", label: "FOLLOWS" },
],
},
// GQL queries
queries: [
{
name: "find_people",
gql: "MATCH (p:Person) RETURN p.name, p.age",
},
],
// 実行ロジック
handlers: [
{
name: "main",
function: "execute_queries",
metadata: { description: "Execute all defined queries" },
},
],
}
実行方法
# .kotobaファイルを実行
kotoba run app.kotoba
# またはサーバーモードで起動
kotoba server --config app.kotoba
Kotoba adopts a modular multi-crate architecture for maximum flexibility:
├── kotoba-core/ # Core types and IR definitions
├── kotoba-jsonnet/ # Complete Jsonnet implementation (38/38 tests passing)
├── kotoba-graph/ # Graph data structures and operations
├── kotoba-storage/ # High-performance RocksDB storage
├── kotoba-execution/ # Query execution and planner
├── kotoba-rewrite/ # Graph rewriting engine
├── kotoba-server/ # HTTP server and handlers
├── kotoba-kotobanet/ # Kotoba extensions for Jsonnet
├── kotoba2tsx/ # TypeScript/React code generation
└── kotoba/ # Main integration crate
Each crate can be used independently, allowing you to pick only the features you need.
kotoba-jsonnet - Complete Jsonnet Implementation"%(name)s" % { name: "World" }local x = 42; x + 1kotoba-graph - Graph Processing Corecargo test --workspace passes# .kotobaファイルで全て定義
kotoba run myapp.kotoba
# 開発時はウォッチモード
kotoba run myapp.kotoba --watch
Rust API(内部使用)
// Rust APIは主に内部実装で使用
use kotoba_core::types::*;
use kotoba_graph::prelude::*;
各crateは条件付きコンパイルによりWASMターゲットにも対応しています:
# WASMビルド
cargo build --target wasm32-unknown-unknown --features wasm
Kotoba is based on a Process Network Graph Model, where all components are centrally managed through dag.jsonnet.
┌─────────────────────────────────────────────────────────────┐
│ lib.rs │
│ (Main Library) │
├─────────────────────────────────────────────────────────────┤
│ execution/ │ rewrite/ │
│ (Query Executor) │ (DPO Rewriter) │
├─────────────────────────────────────────────────────────────┤
│ planner/ │ storage/ │
│ (Query Planner) │ (MVCC+Merkle) │
├─────────────────────────────────────────────────────────────┤
│ graph/ │ ir/ │
│ (Data Structures) │ (Core IR) │
├─────────────────────────────────────────────────────────────┤
│ types.rs │
│ (Common Types) │
└─────────────────────────────────────────────────────────────┘
// Get build order from dag.jsonnet
$ jsonnet eval dag.jsonnet | jq .topological_order
[
"types",
"ir_catalog",
"ir_rule",
"ir_query",
"ir_patch",
"graph_vertex",
"graph_edge",
"ir_strategy",
"graph_core",
"storage_mvcc",
"storage_merkle",
"storage_lsm", // RocksDB-based high-performance storage
"planner_logical",
"planner_physical",
"execution_parser",
"rewrite_matcher",
"rewrite_applier",
"planner_optimizer",
"rewrite_engine",
"execution_engine",
"lib"
]
queries.kotoba
{
config: {
type: "config",
name: "QueryExample",
},
// グラフデータ
graph: {
vertices: [
{ id: "alice", labels: ["Person"], properties: { name: "Alice", age: 30 } },
{ id: "bob", labels: ["Person"], properties: { name: "Bob", age: 25 } },
{ id: "charlie", labels: ["Person"], properties: { name: "Charlie", age: 35 } },
],
edges: [
{ id: "f1", src: "alice", dst: "bob", label: "FOLLOWS" },
{ id: "f2", src: "bob", dst: "charlie", label: "FOLLOWS" },
],
},
// GQLクエリ定義
queries: [
{
name: "follow_network",
gql: "MATCH (p:Person)-[:FOLLOWS]->(f:Person) WHERE p.age > 25 RETURN p.name, f.name",
description: "25歳以上の人がフォローしている人を取得",
},
],
handlers: [
{
name: "execute_query",
function: "run_gql_query",
parameters: { query_name: "follow_network" },
},
],
}
kotoba run queries.kotoba
rewrite.kotoba
{
config: {
type: "config",
name: "RewriteExample",
},
// グラフ書換えルール
rules: [
{
name: "triangle_collapse",
description: "三角形を折りたたむ",
lhs: {
nodes: [
{ id: "u", type: "Person" },
{ id: "v", type: "Person" },
{ id: "w", type: "Person" },
],
edges: [
{ id: "e1", src: "u", dst: "v", type: "FOLLOWS" },
{ id: "e2", src: "v", dst: "w", type: "FOLLOWS" },
],
},
rhs: {
nodes: [
{ id: "u", type: "Person" },
{ id: "w", type: "Person" },
],
edges: [
{ id: "e3", src: "u", dst: "w", type: "FOLLOWS" },
],
},
},
],
// 実行戦略
strategies: [
{
name: "exhaust_triangle_collapse",
rule: "triangle_collapse",
strategy: "exhaust",
order: "topdown",
},
],
handlers: [
{
name: "apply_rewrite",
function: "execute_rewrite",
parameters: { strategy_name: "exhaust_triangle_collapse" },
},
],
}
server.kotoba
{
config: {
type: "config",
name: "GraphServer",
server: { host: "127.0.0.1", port: 3000 },
},
// ルート定義
routes: [
{
method: "GET",
pattern: "/api/users",
handler: "list_users",
description: "ユーザー一覧を取得",
},
{
method: "POST",
pattern: "/api/users",
handler: "create_user",
description: "ユーザーを作成",
},
],
// グラフスキーマ
schema: {
node_types: ["User", "Post"],
edge_types: ["FOLLOWS", "LIKES"],
},
handlers: [
{
name: "list_users",
function: "execute_gql",
parameters: {
query: "MATCH (u:User) RETURN u.name, u.email",
format: "json",
},
},
{
name: "create_user",
function: "create_graph_node",
parameters: {
type: "User",
properties: ["name", "email", "age"],
},
},
],
}
Kotobaプロジェクトでは、設定ファイルやUI定義などに.kotobaファイル形式を使用します。これはJsonnet形式をベースとした構造化された設定フォーマットです。
.kotobaファイルは以下の特徴を持ちます:
// 設定ファイルの基本構造
{
// 設定セクション
config: {
type: "config",
name: "MyApp",
version: "1.0.0",
metadata: {
description: "アプリケーション設定",
},
},
// コンポーネント定義
components: [
// コンポーネントオブジェクト
],
// ユーティリティ関数
makeComponent: function(name, type, props={}) {
// コンポーネント生成関数
},
}
type (必須): オブジェクトの種類を指定name (推奨): オブジェクトの一意な識別子metadata (オプション): 追加情報(説明、バージョンなど)local変数: Jsonnetのローカル変数による設定の共通化関数: 設定生成のための再利用可能な関数::演算子: 計算プロパティによる動的設定生成config - 設定オブジェクトアプリケーション全体の設定を定義します。
local appVersion = "1.0.0";
config: {
type: "config",
name: "MyApp",
version: appVersion,
host: "127.0.0.1",
port: 8080,
theme: "light",
metadata: {
description: "アプリケーション設定",
environment: "development",
},
}
routes / middlewares - HTTP設定HTTPサーバーのルートとミドルウェアを構造化して定義します。
// ユーティリティ関数
local makeRoute = function(method, pattern, handler, desc) {
type: "route",
method: method,
pattern: pattern,
handler: handler,
metadata: { description: desc },
};
routes: [
makeRoute("GET", "/api/" + appVersion + "/users", "list_users", "List users"),
makeRoute("POST", "/api/" + appVersion + "/users", "create_user", "Create user"),
],
middlewares: [
{
type: "middleware",
name: "cors",
order: 10,
function: "cors_middleware",
metadata: {
description: "CORS handling middleware",
allowed_origins: ["*"],
},
},
],
components - UIコンポーネント定義Reactコンポーネントを構造化して定義します。
local styles = {
button: { primary: "button primary", secondary: "button secondary" },
layout: { header: "header", sidebar: "sidebar" },
};
local makeButton = function(name, text, style, onClick) {
type: "component",
name: name,
component_type: "button",
props: {
text: text,
className: style,
onClick: onClick,
},
metadata: { description: name + " button" },
};
components: [
makeButton("SaveButton", "Save", styles.button.primary, "handleSave"),
makeButton("CancelButton", "Cancel", styles.button.secondary, "handleCancel"),
],
handlers / states - イベントと状態管理イベントハンドラーと状態を定義します。
handlers: [
{
type: "handler",
name: "handleSave",
function: "handleSave",
metadata: { description: "Save form data" },
},
],
states: [
{
type: "state",
name: "user",
initial: null,
metadata: { description: "Current user state" },
},
{
type: "state",
name: "loading",
initial: false,
metadata: { description: "Loading state" },
},
],
Jsonnetの機能を活用した動的設定とバリデーション。
// 計算プロパティ
allRoutes:: [r.pattern for r in self.routes],
routeCount:: std.length(self.routes),
// バリデーション関数
validateRoutes:: function() {
local duplicates = [
pattern
for pattern in std.set([r.pattern for r in self.routes])
if std.count([r.pattern for r in self.routes], pattern) > 1
];
if std.length(duplicates) > 0 then
error "Duplicate route patterns: " + std.join(", ", duplicates)
else
"Routes validation passed";
},
// config.kotoba - HTTPサーバー設定
local apiVersion = "v1";
local defaultTimeout = 30000;
{
// サーバー設定
config: {
type: "config",
host: "127.0.0.1",
port: 8080,
max_connections: 1000,
timeout_ms: defaultTimeout,
metadata: {
description: "HTTP server configuration",
environment: "development",
},
},
// ユーティリティ関数
makeRoute: function(method, pattern, handler, desc) {
type: "route",
method: method,
pattern: pattern,
handler: handler,
metadata: { description: desc },
},
makeMiddleware: function(name, order, func, desc) {
type: "middleware",
name: name,
order: order,
function: func,
metadata: { description: desc },
},
// ルート定義
routes: [
$.makeRoute("GET", "/ping", "ping_handler", "Simple ping endpoint"),
$.makeRoute("GET", "/health", "health_check", "Health check endpoint"),
$.makeRoute("GET", "/api/" + apiVersion + "/users", "list_users", "List users"),
$.makeRoute("POST", "/api/" + apiVersion + "/users", "create_user", "Create user"),
],
// ミドルウェア定義
middlewares: [
$.makeMiddleware("cors", 10, "cors_middleware", "CORS handling"),
$.makeMiddleware("auth", 20, "auth_middleware", "Authentication"),
$.makeMiddleware("logger", 100, "request_logger", "Request logging"),
],
// 計算プロパティ
serverInfo:: {
host: $.config.host,
port: $.config.port,
routes_count: std.length($.routes),
middlewares_count: std.length($.middlewares),
},
}
// app.kotoba - React UI設定
local appName = "MyApp";
local appVersion = "1.0.0";
{
// アプリケーション設定
config: {
type: "config",
name: appName,
version: appVersion,
theme: "light",
title: "My App",
metadata: {
framework: "React",
description: "Sample React application",
},
},
// スタイル定数
styles: {
button: {
primary: "button primary",
secondary: "button secondary",
},
layout: {
header: "header",
main: "main-content",
},
},
// ユーティリティ関数
makeComponent: function(name, componentType, props={}, children=[], desc="") {
type: "component",
name: name,
component_type: componentType,
props: props,
children: children,
metadata: { description: desc },
},
makeButton: function(name, text, style, onClick, desc) {
$.makeComponent(name, "button", {
text: text,
className: style,
onClick: onClick,
}, [], desc),
},
// コンポーネント定義
components: [
$.makeComponent("App", "div", {}, ["Header", "Main"], "Root application component"),
$.makeComponent("Header", "header", {
title: $.config.title,
className: $.styles.layout.header,
}, ["Nav"], "Application header"),
$.makeButton("SaveBtn", "Save", $.styles.button.primary, "handleSave", "Save button"),
$.makeButton("CancelBtn", "Cancel", $.styles.button.secondary, "handleCancel", "Cancel button"),
],
// イベントハンドラー
handlers: [
{
type: "handler",
name: "handleSave",
function: "handleSave",
metadata: { description: "Handle save action" },
},
{
type: "handler",
name: "handleCancel",
function: "handleCancel",
metadata: { description: "Handle cancel action" },
},
],
// 状態管理
states: [
{
type: "state",
name: "user",
initial: null,
metadata: { description: "Current user state" },
},
{
type: "state",
name: "theme",
initial: $.config.theme,
metadata: { description: "Current theme state" },
},
],
}
Jsonnetファイルはjsonnetコマンドまたはプログラムによる評価が必要です:
# Jsonnetファイルを評価してJSONに変換
jsonnet eval config.kotoba
# またはプログラムで直接使用
jsonnet eval config.kotoba | jq .routes
// Rustでの使用例
use std::process::Command;
// Jsonnetファイルを評価
let output = Command::new("jsonnet")
.arg("eval")
.arg("config.kotoba")
.output()?;
let config_json: serde_json::Value = serde_json::from_slice(&output.stdout)?;
// 設定を使用
if let Some(routes) = config_json.get("routes") {
println!("Found {} routes", routes.as_array().unwrap().len());
}
local appVersion = "v1";
local defaultPort = 8080;
{
config: {
version: appVersion,
port: defaultPort,
},
routes: [
{ pattern: "/api/" + appVersion + "/users" },
],
}
local makeApiRoute = function(method, resource, action) {
type: "route",
method: method,
pattern: "/api/v1/" + resource + "/" + action,
handler: resource + "_" + action,
};
routes: [
makeApiRoute("GET", "users", "list"),
makeApiRoute("POST", "users", "create"),
],
{
components: [/* ... */],
// コンポーネント数の計算
componentCount:: std.length(self.components),
// コンポーネントタイプ別の集計
componentTypes:: std.set([c.component_type for c in self.components]),
}
local environment = "production";
{
config: {
debug: if environment == "development" then true else false,
port: if environment == "production" then 80 else 3000,
},
// バリデーション
validate:: function() {
if std.length(self.config.name) == 0 then
error "Application name is required"
else
"Configuration is valid";
},
}
local変数で定義してDRY原則を守る::演算子で動的な設定値を生成//コメントを活用して設定の意図を明確に.kotoba形式(Jsonnet)は非常に拡張性が高く、Jsonnetの全機能を活用できます:
// utils.libsonnet
{
// 汎用ユーティリティ関数
makeCrudRoutes(resource):: [
{
type: "route",
method: "GET",
pattern: "/api/v1/" + resource,
handler: resource + "_list",
},
{
type: "route",
method: "POST",
pattern: "/api/v1/" + resource,
handler: resource + "_create",
},
],
// スタイル定数
themes: {
light: { bg: "#ffffff", fg: "#000000" },
dark: { bg: "#000000", fg: "#ffffff" },
},
}
// 複数の設定ファイルを合成
local base = import "base.libsonnet";
local api = import "api.libsonnet";
base + api + {
// 追加設定
customRoutes: [
{ pattern: "/health", handler: "health_check" },
],
}
// 環境に応じた設定切り替え
local environment = std.extVar("ENVIRONMENT");
{
config: {
debug: environment != "production",
port: if environment == "production" then 80 else 3000,
database: {
host: if environment == "production"
then "prod-db.example.com"
else "localhost",
},
},
}
# 設定ファイルの検証
jsonnet eval config.kotoba
# 特定のセクションのみ取得
jsonnet eval -e "(import 'config.kotoba').routes"
# バリデーション実行
jsonnet eval -e "(import 'config.kotoba').validate()"
# 設定をJSONとして保存
jsonnet eval config.kotoba > config.json
# Check dependencies of specific component
jsonnet eval -e "local dag = import 'dag.jsonnet'; dag.get_dependencies('execution_engine')"
# Check components that depend on this component
jsonnet eval -e "local dag = import 'dag.jsonnet'; dag.get_dependents('types')"
# Get overall build order
jsonnet eval dag.jsonnet | jq .topological_order[]
# Check build order for specific node
jsonnet eval -e "local dag = import 'dag.jsonnet'; dag.get_build_order('graph_core')"
# Get investigation order when problems occur
jsonnet eval dag.jsonnet | jq .reverse_topological_order[]
# Get configuration for specific target
jsonnet eval -e "local lib = import 'lib.jsonnet'; lib.get_target_config('x86_64-apple-darwin')"
# Resolve component dependencies
jsonnet eval -e "local lib = import 'lib.jsonnet'; lib.resolve_dependencies('kotoba-core', ['full'])"
# Get Docker image configuration
jsonnet eval lib.jsonnet | jq .packaging.docker
# Get Debian package configuration
jsonnet eval lib.jsonnet | jq .packaging.debian
# 1. Make code changes
vim src/some_component.rs
# 2. Check dependencies
jsonnet eval -e "local dag = import 'dag.jsonnet'; dag.get_dependencies('some_component')"
# 3. Run tests
cargo test --package some_component
# 4. Check overall consistency
cargo check
# 5. Validate DAG
jsonnet eval -e "local dag = import 'dag.jsonnet'; dag.validate_dag()"
# 6. Commit
git add .
git commit -m "Update some_component"
Kotoba maintains high test coverage across all components, with particular emphasis on the storage layer achieving 95% coverage.
# Run all tests
cargo test
# Run storage tests (95% coverage)
cargo test -p kotoba-storage
# Run specific test
cargo test test_graph_operations
# Run documentation tests
cargo test --doc
# Generate coverage report (requires cargo-tarpaulin)
cargo tarpaulin -p kotoba-storage --out Html
# Run integration tests
cargo test --test integration
# Run benchmarks
cargo bench
# Run benchmark with LDBC-SNB dataset
cargo run --bin kotoba-bench -- --dataset ldbc-snb
# Build Docker image
docker build -t kotoba:latest .
# Run the image
docker run -p 8080:8080 kotoba:latest
# Create Debian package
cargo deb
# Install the package
sudo dpkg -i target/debian/kotoba_0.1.0_amd64.deb
# Install Homebrew Formula
brew install kotoba
Kotoba CLIはDeno CLIを参考にした使いやすいコマンドラインインターフェースを提供します。グラフ処理、クエリ実行、ファイル操作などをサポートしています。
# ビルドしてインストール
cargo build --release --features binary
cp target/release/kotoba ~/.local/bin/ # またはPATHの通った場所に
# ヘルプ表示
kotoba --help
# プロジェクト情報表示
kotoba info
kotoba info --detailed --json
# GQLクエリ実行
kotoba query "MATCH (n) RETURN n" --format json
# ファイル実行
kotoba run myfile.kotoba
# ファイル検証
kotoba check src/
kotoba check --all
# ファイルフォーマット
kotoba fmt src/
kotoba fmt --all --check
# サーバー起動
kotoba server --port 3000 --host 127.0.0.1
# 新規プロジェクト初期化
kotoba init my-project --template web
# ドキュメント生成
kotoba doc --output ./docs --format html
# バージョン表示
kotoba version
| コマンド | 説明 |
|---|---|
run <file.kotoba> |
.kotobaファイルを実行 |
server --config <file.kotoba> |
HTTPサーバーを起動 |
query "MATCH..." --graph <file> |
GQLクエリを直接実行 |
check <file.kotoba> |
.kotobaファイルを検証 |
fmt <file.kotoba> |
.kotobaファイルをフォーマット |
info |
プロジェクト情報を表示 |
repl |
インタラクティブGQL REPL |
init <project> |
新規.kotobaプロジェクトを初期化 |
version |
バージョン情報を表示 |
| オプション | 説明 |
|---|---|
-c, --config <CONFIG> |
設定ファイルパス |
-l, --log-level <LEVEL> |
ログレベル (info, debug, warn, error) |
-C, --cwd <DIR> |
作業ディレクトリ |
-h, --help |
ヘルプ表示 |
-V, --version |
バージョン表示 |
# .kotobaファイルを実行
kotoba run app.kotoba
# ウォッチモードで開発(ファイル変更時に自動再実行)
kotoba run app.kotoba --watch
# サーバーモードで起動
kotoba server --config server.kotoba --port 3000
# ファイルを検証
kotoba check app.kotoba
# ファイルをフォーマット
kotoba fmt app.kotoba
# インタラクティブREPLでクエリを実行
kotoba repl
# 新規プロジェクトを作成
kotoba init my-project --template web
# プロジェクト情報を表示
kotoba info --detailed
# Generate documentation
cargo doc --open
# Generate documentation including private items
cargo doc --document-private-items --open
feature/your-feature-name# Install development dependencies
cargo install cargo-edit cargo-watch cargo-deb
# Set up pre-commit hooks
cp pre-commit.sh .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
rustfmt and clippyThis project is licensed under the MIT License. See the LICENSE file for details.
Kotoba - Exploring the world of graphs through words