Skip to content

Commit 2303e46

Browse files
authored
Merge pull request #3 from hubuum/codex/update-relationship-query-model-for-classes
Align relationship model with class related endpoints
2 parents 5593b45 + 9df60a3 commit 2303e46

7 files changed

Lines changed: 164 additions & 107 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ The format is based on Keep a Changelog, and this project aims to follow Semanti
99
### Changed
1010

1111
- Redesigned relationship helpers around the new relation endpoint layout:
12+
- `Class::related_classes()` now targets `/api/v1/classes/{class_id}/related/classes`
13+
- added `Class::related_relations()` for `/api/v1/classes/{class_id}/related/relations`
14+
- added `Class::related_graph()` for `/api/v1/classes/{class_id}/related/graph`
1215
- `Object::related_objects()` now targets `/api/v1/classes/{class_id}/objects/{object_id}/related/objects`
1316
- added `Object::related_relations()` for `/related/relations`
1417
- added `Object::related_graph()` for `/related/graph`
15-
- Cursor-backed relationship requests now support query filters in addition to sorting, limits, and cursors, so class-transitive, class-scoped, related-object, and related-relation listings can all use the shared DB query interface.
18+
- Cursor-backed relationship requests now support query filters in addition to sorting, limits, and cursors, so connected-class, class-related-relation, related-object, and related-relation listings can all use the shared DB query interface.
1619
- `Client::search(...)` is now the typed unified search builder for `/api/v1/search` and `/api/v1/search/stream`.
1720

1821
### Added
@@ -23,6 +26,7 @@ The format is based on Keep a Changelog, and this project aims to follow Semanti
2326
### Breaking
2427

2528
- The public `Client::search`/`AsyncClient::search` low-level resource helper has been replaced by the unified search builder. Resource querying continues through resource handles like `client.classes().query()`.
29+
- `Class::transitive_relations()` and `Class::transitive_relations_to(...)` were removed. Class traversal now mirrors object traversal through `related_classes()`, `related_relations()`, and `related_graph()`.
2630
- Relationship examples and fluent filters should use the new API query aliases such as `from_classes`, `to_classes`, `from_objects`, `to_objects`, and `class_relation` instead of the older storage-shaped field names.
2731

2832
## [0.0.1] - 2026-03-12

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/client/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,12 @@ mod parity_contract {
210210
let _ = $module::Handle::<Class>::delete;
211211
let _ = $module::Handle::<Class>::permissions;
212212
let _ = $module::Handle::<Class>::permissions_request;
213-
let _ = $module::Handle::<Class>::relations;
213+
let _ = $module::Handle::<Class>::related_classes;
214+
let _ = $module::Handle::<Class>::related_relations;
215+
let _ = $module::Handle::<Class>::related_graph;
214216
let _ = $module::Handle::<Class>::relation;
215217
let _ = $module::Handle::<Class>::create_relation;
216218
let _ = $module::Handle::<Class>::delete_relation;
217-
let _ = $module::Handle::<Class>::transitive_relations;
218-
let _ = $module::Handle::<Class>::transitive_relations_to;
219219

220220
let _ = $module::Handle::<Object>::related_objects;
221221
let _ = $module::Handle::<Object>::related_relations;

src/endpoints.rs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ pub enum Endpoint {
2121
Classes,
2222
ClassesById,
2323
ClassPermissions,
24-
ClassScopedRelations,
25-
ClassScopedRelationById,
26-
ClassRelationsTransitive,
27-
ClassRelationsTransitiveTo,
24+
ClassRelatedClasses,
25+
ClassRelatedRelations,
26+
ClassRelatedGraph,
27+
ClassRelationsFromClass,
28+
ClassRelationFromClassById,
2829
Namespaces,
2930
NamespacesById,
3031
NamespacePermissions,
@@ -78,16 +79,13 @@ impl Endpoint {
7879
Endpoint::Classes => "/api/v1/classes",
7980
Endpoint::ClassesById => "/api/v1/classes/{class_id}",
8081
Endpoint::ClassPermissions => "/api/v1/classes/{class_id}/permissions",
81-
Endpoint::ClassScopedRelations => "/api/v1/classes/{class_id}/relations",
82-
Endpoint::ClassScopedRelationById => {
82+
Endpoint::ClassRelatedClasses => "/api/v1/classes/{class_id}/related/classes",
83+
Endpoint::ClassRelatedRelations => "/api/v1/classes/{class_id}/related/relations",
84+
Endpoint::ClassRelatedGraph => "/api/v1/classes/{class_id}/related/graph",
85+
Endpoint::ClassRelationsFromClass => "/api/v1/classes/{class_id}/relations",
86+
Endpoint::ClassRelationFromClassById => {
8387
"/api/v1/classes/{class_id}/relations/{relation_id}"
8488
}
85-
Endpoint::ClassRelationsTransitive => {
86-
"/api/v1/classes/{class_id}/relations/transitive/"
87-
}
88-
Endpoint::ClassRelationsTransitiveTo => {
89-
"/api/v1/classes/{class_id}/relations/transitive/class/{class_id_to}"
90-
}
9189
Endpoint::Namespaces => "/api/v1/namespaces",
9290
Endpoint::NamespacesById => "/api/v1/namespaces/{namespace_id}",
9391

@@ -172,10 +170,11 @@ mod test {
172170
get_group_by_id = { Endpoint::GroupsById, "/api/v1/iam/groups/{group_id}" },
173171
get_class_permissions = { Endpoint::ClassPermissions, "/api/v1/classes/{class_id}/permissions" },
174172
get_class_by_id = { Endpoint::ClassesById, "/api/v1/classes/{class_id}" },
175-
get_class_scoped_relations = { Endpoint::ClassScopedRelations, "/api/v1/classes/{class_id}/relations" },
176-
get_class_scoped_relation_by_id = { Endpoint::ClassScopedRelationById, "/api/v1/classes/{class_id}/relations/{relation_id}" },
177-
get_class_transitive = { Endpoint::ClassRelationsTransitive, "/api/v1/classes/{class_id}/relations/transitive/" },
178-
get_class_transitive_to = { Endpoint::ClassRelationsTransitiveTo, "/api/v1/classes/{class_id}/relations/transitive/class/{class_id_to}" },
173+
get_class_related_classes = { Endpoint::ClassRelatedClasses, "/api/v1/classes/{class_id}/related/classes" },
174+
get_class_related_relations = { Endpoint::ClassRelatedRelations, "/api/v1/classes/{class_id}/related/relations" },
175+
get_class_related_graph = { Endpoint::ClassRelatedGraph, "/api/v1/classes/{class_id}/related/graph" },
176+
class_relations_from_class = { Endpoint::ClassRelationsFromClass, "/api/v1/classes/{class_id}/relations" },
177+
class_relation_from_class_by_id = { Endpoint::ClassRelationFromClassById, "/api/v1/classes/{class_id}/relations/{relation_id}" },
179178
get_namespace_by_id = { Endpoint::NamespacesById, "/api/v1/namespaces/{namespace_id}" },
180179
get_namespace_permission_grant = { Endpoint::NamespacePermissionsGrant, "/api/v1/namespaces/{namespace_id}/permissions/group/{group_id}" },
181180
get_namespace_single_permission_grant = { Endpoint::NamespacePermissionGrant, "/api/v1/namespaces/{namespace_id}/permissions/group/{group_id}/{permission}" },
@@ -220,10 +219,11 @@ mod test {
220219
get_group_by_id = { Endpoint::GroupsById, '/', "api/v1/iam/groups/{group_id}" },
221220
get_class_permissions = { Endpoint::ClassPermissions, '/', "api/v1/classes/{class_id}/permissions" },
222221
get_class_by_id = { Endpoint::ClassesById, '/', "api/v1/classes/{class_id}" },
223-
get_class_scoped_relations = { Endpoint::ClassScopedRelations, '/', "api/v1/classes/{class_id}/relations" },
224-
get_class_scoped_relation_by_id = { Endpoint::ClassScopedRelationById, '/', "api/v1/classes/{class_id}/relations/{relation_id}" },
225-
get_class_transitive = { Endpoint::ClassRelationsTransitive, '/', "api/v1/classes/{class_id}/relations/transitive/" },
226-
get_class_transitive_to = { Endpoint::ClassRelationsTransitiveTo, '/', "api/v1/classes/{class_id}/relations/transitive/class/{class_id_to}" },
222+
get_class_related_classes = { Endpoint::ClassRelatedClasses, '/', "api/v1/classes/{class_id}/related/classes" },
223+
get_class_related_relations = { Endpoint::ClassRelatedRelations, '/', "api/v1/classes/{class_id}/related/relations" },
224+
get_class_related_graph = { Endpoint::ClassRelatedGraph, '/', "api/v1/classes/{class_id}/related/graph" },
225+
class_relations_from_class = { Endpoint::ClassRelationsFromClass, '/', "api/v1/classes/{class_id}/relations" },
226+
class_relation_from_class_by_id = { Endpoint::ClassRelationFromClassById, '/', "api/v1/classes/{class_id}/relations/{relation_id}" },
227227
get_namespace_by_id = { Endpoint::NamespacesById, '/', "api/v1/namespaces/{namespace_id}" },
228228
get_namespace_permission_grant = { Endpoint::NamespacePermissionsGrant, '/', "api/v1/namespaces/{namespace_id}/permissions/group/{group_id}" },
229229
get_namespace_single_permission_grant = { Endpoint::NamespacePermissionGrant, '/', "api/v1/namespaces/{namespace_id}/permissions/group/{group_id}/{permission}" },

src/resources/class.rs

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ use crate::{
77
client::{
88
r#async::{
99
CursorRequest as AsyncCursorRequest, EmptyPostParams as AsyncEmptyPostParams,
10-
Handle as AsyncHandle, QueryOp as AsyncQueryOp,
10+
GraphRequest as AsyncGraphRequest, Handle as AsyncHandle, QueryOp as AsyncQueryOp,
1111
},
1212
sync::{
1313
CursorRequest as SyncCursorRequest, EmptyPostParams as SyncEmptyPostParams,
14-
Handle as SyncHandle, QueryOp as SyncQueryOp, one_or_err,
14+
GraphRequest as SyncGraphRequest, Handle as SyncHandle, QueryOp as SyncQueryOp,
15+
one_or_err,
1516
},
1617
},
1718
endpoints::Endpoint,
@@ -58,11 +59,22 @@ pub struct ClassRelationResource {
5859
}
5960

6061
#[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)]
61-
pub struct ClassRelationTransitive {
62-
pub ancestor_class_id: i32,
63-
pub descendant_class_id: i32,
64-
pub depth: i32,
65-
pub path: Vec<Option<i32>>,
62+
pub struct ClassWithPath {
63+
pub id: i32,
64+
pub name: String,
65+
pub namespace_id: i32,
66+
pub description: String,
67+
pub json_schema: serde_json::Value,
68+
pub validate_schema: bool,
69+
pub created_at: HubuumDateTime,
70+
pub updated_at: HubuumDateTime,
71+
pub path: Vec<i32>,
72+
}
73+
74+
#[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)]
75+
pub struct RelatedClassGraph {
76+
pub classes: Vec<ClassWithPath>,
77+
pub relations: Vec<ClassRelation>,
6678
}
6779

6880
impl SyncHandle<Class> {
@@ -135,10 +147,26 @@ impl SyncHandle<Class> {
135147
)
136148
}
137149

138-
pub fn relations(&self) -> SyncCursorRequest<ClassRelation> {
150+
pub fn related_classes(&self) -> SyncCursorRequest<ClassWithPath> {
139151
SyncCursorRequest::new(
140152
self.client().clone(),
141-
Endpoint::ClassScopedRelations,
153+
Endpoint::ClassRelatedClasses,
154+
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
155+
)
156+
}
157+
158+
pub fn related_relations(&self) -> SyncCursorRequest<ClassRelation> {
159+
SyncCursorRequest::new(
160+
self.client().clone(),
161+
Endpoint::ClassRelatedRelations,
162+
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
163+
)
164+
}
165+
166+
pub fn related_graph(&self) -> SyncGraphRequest<RelatedClassGraph> {
167+
SyncGraphRequest::new(
168+
self.client().clone(),
169+
Endpoint::ClassRelatedGraph,
142170
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
143171
)
144172
}
@@ -164,7 +192,7 @@ impl SyncHandle<Class> {
164192
self.client()
165193
.request_with_endpoint::<NewClassRelationFromClassParams, ClassRelation>(
166194
reqwest::Method::POST,
167-
&Endpoint::ClassScopedRelations,
195+
&Endpoint::ClassRelationsFromClass,
168196
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
169197
vec![],
170198
NewClassRelationFromClassParams {
@@ -180,7 +208,7 @@ impl SyncHandle<Class> {
180208
self.client()
181209
.request_with_endpoint::<SyncEmptyPostParams, ()>(
182210
reqwest::Method::DELETE,
183-
&Endpoint::ClassScopedRelationById,
211+
&Endpoint::ClassRelationFromClassById,
184212
vec![
185213
(Cow::Borrowed("class_id"), self.id().to_string().into()),
186214
(Cow::Borrowed("relation_id"), relation_id.to_string().into()),
@@ -190,28 +218,6 @@ impl SyncHandle<Class> {
190218
)?;
191219
Ok(())
192220
}
193-
194-
pub fn transitive_relations(&self) -> SyncCursorRequest<ClassRelationTransitive> {
195-
SyncCursorRequest::new(
196-
self.client().clone(),
197-
Endpoint::ClassRelationsTransitive,
198-
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
199-
)
200-
}
201-
202-
pub fn transitive_relations_to(
203-
&self,
204-
class_id: i32,
205-
) -> SyncCursorRequest<ClassRelationTransitive> {
206-
SyncCursorRequest::new(
207-
self.client().clone(),
208-
Endpoint::ClassRelationsTransitiveTo,
209-
vec![
210-
(Cow::Borrowed("class_id"), self.id().to_string().into()),
211-
(Cow::Borrowed("class_id_to"), class_id.to_string().into()),
212-
],
213-
)
214-
}
215221
}
216222

217223
impl AsyncHandle<Class> {
@@ -266,10 +272,26 @@ impl AsyncHandle<Class> {
266272
)
267273
}
268274

269-
pub fn relations(&self) -> AsyncCursorRequest<ClassRelation> {
275+
pub fn related_classes(&self) -> AsyncCursorRequest<ClassWithPath> {
276+
AsyncCursorRequest::new(
277+
self.client().clone(),
278+
Endpoint::ClassRelatedClasses,
279+
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
280+
)
281+
}
282+
283+
pub fn related_relations(&self) -> AsyncCursorRequest<ClassRelation> {
270284
AsyncCursorRequest::new(
271285
self.client().clone(),
272-
Endpoint::ClassScopedRelations,
286+
Endpoint::ClassRelatedRelations,
287+
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
288+
)
289+
}
290+
291+
pub fn related_graph(&self) -> AsyncGraphRequest<RelatedClassGraph> {
292+
AsyncGraphRequest::new(
293+
self.client().clone(),
294+
Endpoint::ClassRelatedGraph,
273295
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
274296
)
275297
}
@@ -296,7 +318,7 @@ impl AsyncHandle<Class> {
296318
self.client()
297319
.request_with_endpoint::<NewClassRelationFromClassParams, ClassRelation>(
298320
reqwest::Method::POST,
299-
&Endpoint::ClassScopedRelations,
321+
&Endpoint::ClassRelationsFromClass,
300322
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
301323
vec![],
302324
NewClassRelationFromClassParams {
@@ -313,7 +335,7 @@ impl AsyncHandle<Class> {
313335
self.client()
314336
.request_with_endpoint::<AsyncEmptyPostParams, ()>(
315337
reqwest::Method::DELETE,
316-
&Endpoint::ClassScopedRelationById,
338+
&Endpoint::ClassRelationFromClassById,
317339
vec![
318340
(Cow::Borrowed("class_id"), self.id().to_string().into()),
319341
(Cow::Borrowed("relation_id"), relation_id.to_string().into()),
@@ -324,26 +346,4 @@ impl AsyncHandle<Class> {
324346
.await?;
325347
Ok(())
326348
}
327-
328-
pub fn transitive_relations(&self) -> AsyncCursorRequest<ClassRelationTransitive> {
329-
AsyncCursorRequest::new(
330-
self.client().clone(),
331-
Endpoint::ClassRelationsTransitive,
332-
vec![(Cow::Borrowed("class_id"), self.id().to_string().into())],
333-
)
334-
}
335-
336-
pub fn transitive_relations_to(
337-
&self,
338-
class_id: i32,
339-
) -> AsyncCursorRequest<ClassRelationTransitive> {
340-
AsyncCursorRequest::new(
341-
self.client().clone(),
342-
Endpoint::ClassRelationsTransitiveTo,
343-
vec![
344-
(Cow::Borrowed("class_id"), self.id().to_string().into()),
345-
(Cow::Borrowed("class_id_to"), class_id.to_string().into()),
346-
],
347-
)
348-
}
349349
}

src/resources/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ mod user;
1111

1212
pub use self::class::{
1313
Class, ClassGet, ClassPatch, ClassPost, ClassRelation, ClassRelationGet, ClassRelationPatch,
14-
ClassRelationPost, ClassRelationTransitive,
14+
ClassRelationPost, ClassWithPath, RelatedClassGraph,
1515
};
1616
pub use self::group::{Group, GroupGet, GroupPatch, GroupPost};
1717
pub use self::namespace::{Namespace, NamespaceGet, NamespacePatch, NamespacePost};

0 commit comments

Comments
 (0)