refactor: extract omnigraph-api-types crate from omnigraph-server

Move api.rs (HTTP request/response DTOs + OpenAPI schemas) into omnigraph-api-types (deps: engine, compiler, queries, serde, serde_json, utoipa). Repoint crate::queries::StoredQuery -> omnigraph_queries. Relocate the two catalog-projection tests here, where query_catalog_entry lives, eliminating the queries<->api dev-dep cycle (no cycle, tests at their boundary). Server aliases via 'pub use omnigraph_api_types as api;'. openapi.json byte-identical (drift test passes; no regen). 2 api-types tests pass; server+cli compile. No behavior change.
This commit is contained in:
Ragnor Comerford 2026-06-03 11:14:19 +02:00
parent 628ecf428a
commit c51b9e1e20
No known key found for this signature in database
6 changed files with 118 additions and 2 deletions

13
Cargo.lock generated
View file

@ -4541,6 +4541,18 @@ dependencies = [
"tokio",
]
[[package]]
name = "omnigraph-api-types"
version = "0.6.1"
dependencies = [
"omnigraph-compiler",
"omnigraph-engine",
"omnigraph-queries",
"serde",
"serde_json",
"utoipa",
]
[[package]]
name = "omnigraph-cli"
version = "0.6.1"
@ -4673,6 +4685,7 @@ dependencies = [
"futures",
"lance",
"lance-index",
"omnigraph-api-types",
"omnigraph-compiler",
"omnigraph-config",
"omnigraph-engine",

View file

@ -8,6 +8,7 @@ members = [
"crates/omnigraph-server",
"crates/omnigraph-config",
"crates/omnigraph-queries",
"crates/omnigraph-api-types",
]
default-members = [
"crates/omnigraph",

View file

@ -0,0 +1,17 @@
[package]
name = "omnigraph-api-types"
version = "0.6.1"
edition = "2024"
description = "HTTP request/response types (OpenAPI schemas) for the Omnigraph graph database."
license = "MIT"
repository = "https://github.com/ModernRelay/omnigraph"
homepage = "https://github.com/ModernRelay/omnigraph"
documentation = "https://docs.rs/omnigraph-api-types"
[dependencies]
omnigraph = { package = "omnigraph-engine", path = "../omnigraph", version = "0.6.1" }
omnigraph-compiler = { path = "../omnigraph-compiler", version = "0.6.1" }
omnigraph-queries = { path = "../omnigraph-queries", version = "0.6.1" }
serde = { workspace = true }
serde_json = { workspace = true }
utoipa = { workspace = true }

View file

@ -1,7 +1,7 @@
use omnigraph::db::{GraphCommit, MergeOutcome, ReadTarget, SchemaApplyResult, Snapshot};
use omnigraph::error::{MergeConflict, MergeConflictKind};
use omnigraph::loader::{IngestResult, LoadMode};
use crate::queries::StoredQuery;
use omnigraph_queries::StoredQuery;
use omnigraph_compiler::SchemaMigrationStep;
use omnigraph_compiler::query::ast::Param;
use omnigraph_compiler::result::QueryResult;
@ -693,3 +693,87 @@ pub struct GraphInfo {
pub struct GraphListResponse {
pub graphs: Vec<GraphInfo>,
}
#[cfg(test)]
mod tests {
// Catalog-projection tests for `query_catalog_entry`: relocated here from
// `omnigraph-queries` because the function under test lives in this crate
// (keeps the test at its boundary and keeps `omnigraph-queries` free of a
// dev-dependency cycle on `omnigraph-api-types`).
use super::{ParamKind, query_catalog_entry};
use omnigraph_queries::{QueryRegistry, RegistrySpec};
fn spec(name: &str, source: &str, expose: bool) -> RegistrySpec {
RegistrySpec {
name: name.to_string(),
source: source.to_string(),
expose,
tool_name: None,
}
}
fn spec_tool(name: &str, source: &str, expose: bool, tool_name: &str) -> RegistrySpec {
RegistrySpec {
name: name.to_string(),
source: source.to_string(),
expose,
tool_name: Some(tool_name.to_string()),
}
}
#[test]
fn catalog_entry_projects_every_param_kind() {
let reg = QueryRegistry::from_specs(vec![spec_tool(
"all_types",
"query all_types($s: String, $i: I32, $big: I64, $u: U64, $f: F64, $b: Bool, \
$d: Date, $dt: DateTime, $blob: Blob, $opt: String?, $list: [I32], $vec: Vector(4)) \
{ match { $x: User } return { $x.name } }",
true,
"all",
)])
.unwrap();
let entry = query_catalog_entry(reg.lookup("all_types").unwrap());
assert_eq!(entry.name, "all_types");
assert_eq!(entry.tool_name, "all");
assert!(!entry.mutation);
let by: std::collections::HashMap<_, _> =
entry.params.iter().map(|p| (p.name.as_str(), p)).collect();
assert_eq!(by["s"].kind, ParamKind::String);
assert_eq!(by["i"].kind, ParamKind::Int);
assert_eq!(by["big"].kind, ParamKind::BigInt, "I64 → bigint (string on the wire)");
assert_eq!(by["u"].kind, ParamKind::BigInt, "U64 → bigint");
assert_eq!(by["f"].kind, ParamKind::Float);
assert_eq!(by["b"].kind, ParamKind::Bool);
assert_eq!(by["d"].kind, ParamKind::Date);
assert_eq!(by["dt"].kind, ParamKind::DateTime);
assert_eq!(by["blob"].kind, ParamKind::Blob);
assert!(!by["s"].nullable);
assert!(by["opt"].nullable, "String? → nullable");
assert_eq!(by["list"].kind, ParamKind::List);
assert_eq!(by["list"].item_kind, Some(ParamKind::Int), "[I32] → list of int");
assert_eq!(by["vec"].kind, ParamKind::Vector);
assert_eq!(by["vec"].vector_dim, Some(4));
}
#[test]
fn catalog_entry_flags_mutation_and_empty_params() {
let reg = QueryRegistry::from_specs(vec![spec(
"add_user",
"query add_user($name: String) { insert User { name: $name } }",
true,
)])
.unwrap();
let entry = query_catalog_entry(reg.lookup("add_user").unwrap());
assert!(entry.mutation, "insert body → mutation flag");
let reg2 = QueryRegistry::from_specs(vec![spec(
"no_params",
"query no_params() { match { $u: User } return { $u.name } }",
true,
)])
.unwrap();
let entry2 = query_catalog_entry(reg2.lookup("no_params").unwrap());
assert!(entry2.params.is_empty(), "no declared params → empty list");
}
}

View file

@ -24,6 +24,7 @@ omnigraph-compiler = { path = "../omnigraph-compiler", version = "0.6.1" }
omnigraph-policy = { path = "../omnigraph-policy", version = "0.6.1" }
omnigraph-config = { path = "../omnigraph-config", version = "0.6.1" }
omnigraph-queries = { path = "../omnigraph-queries", version = "0.6.1" }
omnigraph-api-types = { path = "../omnigraph-api-types", version = "0.6.1" }
axum = { workspace = true }
clap = { workspace = true }
color-eyre = { workspace = true }

View file

@ -1,4 +1,4 @@
pub mod api;
pub use omnigraph_api_types as api;
pub mod auth;
pub use omnigraph_config as config;
pub mod graph_id;