Skip to content

Commit c84dfd6

Browse files
authored
feat: add where filters to osograph (#5662)
* feat: add `type-safe` query builder and where clause parser * feat: add `where` parameter support to all list queries with `JSON` scalar * feat: add where clause validation schemas with `createWhereSchema` factory * refactor: add `FilterableConnectionArgs` type and update resolver helper utilities * feat: implement filtering support across all `OsoGraph` resolvers * chore: add `graphql-scalars` dependency for JSON scalar support * refactor: use `graphql-scalars` for DateTime and JSON scalar resolvers * docs: add filtering guide with where clause examples for `OsoGraph` * chore: add `where` argument to `Viewer.runs` * chore: run `codegen` scripts * chore: use `query-builder` + `where` format * feat: implement `queryWithPagination` helper * chore: run `codegen` scripts * feat: use static `basePredicate` option * chore: update `osograph` docs
1 parent ff1bba1 commit c84dfd6

26 files changed

+1555
-543
lines changed

apps/docs/docs/guides/ops/osograph.md

Lines changed: 393 additions & 64 deletions
Large diffs are not rendered by default.

apps/frontend/app/api/v1/osograph/schema/graphql/base.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ extend schema
55
)
66

77
scalar DateTime
8+
scalar JSON
89

910
enum MemberRole {
1011
owner

apps/frontend/app/api/v1/osograph/schema/graphql/data-model.graphql

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ type DataModel {
77
isEnabled: Boolean!
88
createdAt: DateTime!
99
updatedAt: DateTime!
10-
revisions(first: Int = 50, after: String): DataModelRevisionConnection!
11-
releases(first: Int = 50, after: String): DataModelReleaseConnection!
10+
revisions(first: Int = 50, after: String, where: JSON): DataModelRevisionConnection!
11+
releases(first: Int = 50, after: String, where: JSON): DataModelReleaseConnection!
1212
latestRevision: DataModelRevision
1313
latestRelease: DataModelRelease
1414
}
@@ -123,8 +123,21 @@ type DataModelKindOptions {
123123
}
124124

125125
extend type Query {
126-
dataModel(id: ID!): DataModel
127-
dataModels(first: Int = 50, after: String): DataModelConnection!
126+
"""
127+
List all data models with optional filtering and pagination.
128+
129+
The where parameter accepts a JSON object with field-level filtering.
130+
Each field can have comparison operators: eq, neq, gt, gte, lt, lte, in, like, ilike, is
131+
132+
Example:
133+
```json
134+
{
135+
"name": { "like": "%user%" },
136+
"is_enabled": { "eq": true }
137+
}
138+
```
139+
"""
140+
dataModels(first: Int = 50, after: String, where: JSON): DataModelConnection!
128141
}
129142

130143
input CreateDataModelInput {

apps/frontend/app/api/v1/osograph/schema/graphql/dataset.graphql

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ type Dataset {
1111
updatedAt: DateTime!
1212
creator: User!
1313
organization: Organization!
14-
tables(first: Int = 50, after: String): TableConnection!
14+
tables(first: Int = 50, after: String, where: JSON): TableConnection!
1515

1616
"""
1717
The runs for this dataset. For USER_MODEL datasets, each run is related to individual data models.
1818
FOR DATA_INGESTION datasets, each run is related to individual ingestion jobs.
1919
For DATA_CONNECTOR datasets, runs are not applicable and this field will be an empty list.
2020
"""
21-
runs(first: Int = 50, after: String): RunConnection!
21+
runs(first: Int = 50, after: String, where: JSON): RunConnection!
2222

2323
typeDefinition: DatasetTypeDefinition!
2424
}
@@ -32,7 +32,7 @@ type DataModelDefinition {
3232
If the dataset is of type USER_MODEL, this field will contain the list of data models
3333
associated with the dataset. Otherwise it will be an empty list.
3434
"""
35-
dataModels(first: Int = 50, after: String): DataModelConnection!
35+
dataModels(first: Int = 50, after: String, where: JSON): DataModelConnection!
3636
}
3737

3838
type DatasetEdge {
@@ -76,24 +76,39 @@ type TableConnection {
7676

7777
extend type Query {
7878
"""
79-
List all datasets
79+
List all datasets with optional filtering and pagination.
80+
81+
The where parameter accepts a JSON object with field-level filtering.
82+
Each field can have comparison operators: eq, neq, gt, gte, lt, lte, in, like, ilike, is
83+
84+
Example:
85+
```json
86+
{
87+
"name": { "like": "%hello%" },
88+
"type": { "eq": "USER_MODEL" }
89+
}
90+
```
8091
"""
81-
datasets(first: Int = 50, after: String): DatasetConnection!
92+
datasets(first: Int = 50, after: String, where: JSON): DatasetConnection!
8293

8394
"""
84-
Get a dataset by ID
95+
Get table column metadata. The where parameter must include:
96+
- orgId: Organization ID
97+
- catalogName: Catalog name
98+
- schemaName: Schema name
99+
- tableName: Table name
100+
101+
Example:
102+
```json
103+
{
104+
"orgId": { "eq": "org-uuid" },
105+
"catalogName": { "eq": "user_iceberg" },
106+
"schemaName": { "eq": "ds_schema" },
107+
"tableName": { "eq": "my_table" }
108+
}
109+
```
85110
"""
86-
dataset(id: ID!): Dataset
87-
88-
"""
89-
Get table column metadata
90-
"""
91-
datasetTableMetadata(
92-
orgId: ID!
93-
catalogName: String!
94-
schemaName: String!
95-
tableName: String!
96-
): [TableColumn!]!
111+
tables(where: JSON!): [TableColumn!]!
97112
}
98113

99114
extend type Mutation {

apps/frontend/app/api/v1/osograph/schema/graphql/invitation.graphql

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,20 @@ type InvitationConnection {
2626

2727
extend type Query {
2828
"""
29-
Get an invitation by ID
30-
"""
31-
invitation(id: ID!): Invitation
29+
List all invitations with optional filtering and pagination.
3230
31+
The where parameter accepts a JSON object with field-level filtering.
32+
Each field can have comparison operators: eq, neq, gt, gte, lt, lte, in, like, ilike, is
33+
34+
Example:
35+
```json
36+
{
37+
"status": { "eq": "PENDING" },
38+
"email": { "ilike": "%@example.com" }
39+
}
40+
```
3341
"""
34-
List invitations for current user
35-
"""
36-
myInvitations(first: Int = 50, after: String): InvitationConnection!
42+
invitations(first: Int = 50, after: String, where: JSON): InvitationConnection!
3743
}
3844

3945
extend type Mutation {

apps/frontend/app/api/v1/osograph/schema/graphql/notebook.graphql

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,24 @@ type NotebookConnection {
2424

2525
extend type Query {
2626
"""
27-
List all notebooks
28-
"""
29-
notebooks(first: Int = 50, after: String): NotebookConnection!
27+
Query notebooks with optional filtering and pagination.
3028
29+
The where parameter accepts a JSON object with field-level filtering.
30+
Each field can have comparison operators: eq, neq, gt, gte, lt, lte, in, like, ilike, is.
31+
32+
Example:
33+
```json
34+
{
35+
"notebook_name": { "like": "%churn%" },
36+
"created_at": { "gte": "2024-01-01T00:00:00Z" }
37+
}
38+
```
3139
"""
32-
Get a notebook by ID
33-
"""
34-
notebook(id: ID!): Notebook
40+
notebooks(
41+
where: JSON
42+
first: Int = 50
43+
after: String
44+
): NotebookConnection!
3545
}
3646

3747
extend type Mutation {

apps/frontend/app/api/v1/osograph/schema/graphql/organization.graphql

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ type Organization {
55
description: String
66
createdAt: DateTime!
77
updatedAt: DateTime!
8-
members(first: Int = 50, after: String): UserConnection!
9-
notebooks(first: Int = 50, after: String): NotebookConnection!
10-
datasets(first: Int = 50, after: String): DatasetConnection!
8+
members(first: Int = 50, after: String, where: JSON): UserConnection!
9+
notebooks(first: Int = 50, after: String, where: JSON): NotebookConnection!
10+
datasets(first: Int = 50, after: String, where: JSON): DatasetConnection!
1111
}
1212

1313
type OrganizationMember {
@@ -32,14 +32,24 @@ type OrganizationConnection {
3232

3333
extend type Query {
3434
"""
35-
List all organizations
36-
"""
37-
organizations(first: Int = 50, after: String): OrganizationConnection!
35+
Query organizations with optional filtering and pagination.
3836
37+
The where parameter accepts a JSON object with field-level filtering.
38+
Each field can have comparison operators: eq, neq, gt, gte, lt, lte, in, like, ilike, is
39+
40+
Example:
41+
```json
42+
{
43+
"name": { "like": "%oso%" },
44+
"created_at": { "gte": "2024-01-01T00:00:00Z" }
45+
}
46+
```
3947
"""
40-
Get an organization by ID or name
41-
"""
42-
organization(id: ID, name: String): Organization
48+
organizations(
49+
where: JSON
50+
first: Int = 50
51+
after: String
52+
): OrganizationConnection!
4353
}
4454

4555
extend type Mutation {

apps/frontend/app/api/v1/osograph/schema/graphql/scheduler.graphql

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,20 @@ type RunConnection {
5858

5959
extend type Query {
6060
"""
61-
Get a run by ID
61+
List all runs with optional filtering and pagination.
62+
63+
The where parameter accepts a JSON object with field-level filtering.
64+
Each field can have comparison operators: eq, neq, gt, gte, lt, lte, in, like, ilike, is
65+
66+
Example:
67+
```json
68+
{
69+
"status": { "eq": "RUNNING" },
70+
"datasetId": { "eq": "dataset-uuid" }
71+
}
72+
```
6273
"""
63-
run(id: ID!): Run
74+
runs(first: Int = 50, after: String, where: JSON): RunConnection!
6475
}
6576

6677
extend type Mutation {

apps/frontend/app/api/v1/osograph/schema/graphql/user.graphql

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ type User {
44
fullName: String
55
avatarUrl: String
66
role: String!
7-
organizations(first: Int = 50, after: String): OrganizationConnection!
7+
organizations(first: Int = 50, after: String, where: JSON): OrganizationConnection!
88
}
99

1010
type UserEdge {
@@ -26,11 +26,11 @@ type Viewer {
2626
email: String!
2727
fullName: String
2828
avatarUrl: String
29-
organizations(first: Int = 50, after: String): OrganizationConnection!
30-
notebooks(first: Int = 50, after: String): NotebookConnection!
31-
datasets(first: Int = 50, after: String): DatasetConnection!
32-
invitations(first: Int = 50, after: String): InvitationConnection!
33-
runs(first: Int = 50, after: String): RunConnection!
29+
organizations(first: Int = 50, after: String, where: JSON): OrganizationConnection!
30+
notebooks(first: Int = 50, after: String, where: JSON): NotebookConnection!
31+
datasets(first: Int = 50, after: String, where: JSON): DatasetConnection!
32+
invitations(first: Int = 50, after: String, where: JSON): InvitationConnection!
33+
runs(first: Int = 50, after: String, where: JSON): RunConnection!
3434
}
3535

3636
extend type Query {

0 commit comments

Comments
 (0)