Skip to content

Commit 4a294d9

Browse files
committed
feat: support AIP filtering
1 parent 3cccdca commit 4a294d9

20 files changed

Lines changed: 2863 additions & 647 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,8 @@ openmeter.log
2828
.claude/worktrees
2929
CLAUDE.local.md
3030

31+
# oapi-codegen patched templates (generated from patch files)
32+
api/v3/templates/chi-middleware.tmpl
33+
3134
# CodeGraph
3235
.codegraph/

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,16 @@ down: ## Stop the dependencies via docker compose
1919
$(call print-target)
2020
docker compose down --remove-orphans --volumes
2121

22+
.PHONY: patch-oapi-templates
23+
patch-oapi-templates: ## Patch oapi-codegen chi-middleware template with custom filter parsing
24+
$(call print-target)
25+
@OAPI_MOD_DIR=$$(go list -m -f '{{.Dir}}' github.com/oapi-codegen/oapi-codegen/v2) && \
26+
cp "$$OAPI_MOD_DIR/pkg/codegen/templates/chi/chi-middleware.tmpl" api/v3/templates/chi-middleware.tmpl && \
27+
chmod u+w api/v3/templates/chi-middleware.tmpl && \
28+
patch -p1 -d api/v3/templates < api/v3/templates/chi-middleware.tmpl.patch
29+
2230
.PHONY: update-openapi
23-
update-openapi: ## Update OpenAPI spec
31+
update-openapi: patch-oapi-templates ## Update OpenAPI spec
2432
$(call print-target)
2533
$(MAKE) -C api/spec generate
2634
go generate ./api/...

api/spec/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ generate: format ## Generate OpenAPI spec
55
$(call print-target)
66
pnpm --frozen-lockfile install
77
pnpm generate
8+
# Replace inline filter definitions with $ref to common/definitions/aip_filters.yaml
9+
@AIP_REF="../../../../common/definitions/aip_filters.yaml#/components/schemas"; \
10+
FILE="packages/aip/output/definitions/metering-and-billing/v3/openapi.MeteringAndBilling.yaml"; \
11+
for schema in SortQuery $$(yq '.components.schemas | keys | .[]' "$$FILE" | grep 'FieldFilter'); do \
12+
if yq -e ".components.schemas | has(\"$$schema\")" "$$FILE" > /dev/null 2>&1; then \
13+
REF_VAL="$$AIP_REF/$$schema" SCHEMA="$$schema" yq -i '.components.schemas[strenv(SCHEMA)] = {"$$ref": strenv(REF_VAL)}' "$$FILE"; \
14+
fi; \
15+
done
816
pnpm --filter @openmeter/api-spec-aip exec openapi bundle output/definitions/metering-and-billing/v3/openapi.OpenMeter.yaml -o ../../../v3/openapi.yaml
917
cp packages/legacy/output/openapi.OpenMeter.yaml ../openapi.yaml
1018
cp packages/legacy/output/openapi.OpenMeterCloud.yaml ../openapi.cloud.yaml

api/spec/packages/aip/src/common/parameters.tsp

Lines changed: 145 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,153 @@ namespace Common;
88

99
/**
1010
* Sort query.
11+
*
12+
* The `asc` suffix is optional as the default sort order is ascending.
13+
* The `desc` suffix is used to specify a descending order.
14+
* Multiple sort attributes may be provided via a comma separated list.
15+
* JSONPath notation may be used to specify a sub-attribute (eg: 'foo.bar desc').
1116
*/
12-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/SortQuery")
17+
// @useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/SortQuery")
1318
@friendlyName("SortQuery")
14-
model SortQuery {}
19+
scalar SortQuery extends string;
1520

1621
/**
1722
* Filter by a boolean value (true/false).
1823
*/
24+
// @useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/BooleanFieldFilter")
1925
@friendlyName("BooleanFieldFilter")
20-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/BooleanFieldFilter")
21-
model BooleanFieldFilter {}
26+
@extension("x-go-type", "filters.FilterBoolean")
27+
@extension(
28+
"x-go-type-import",
29+
#{ path: "github.com/openmeterio/openmeter/api/v3/filters" }
30+
)
31+
scalar BooleanFieldFilter extends boolean;
2232

2333
/**
2434
* Filter by a numeric value.
35+
* All properties are optional; provide exactly one to specify the comparison.
2536
*/
2637
@friendlyName("NumericFieldFilter")
27-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/NumericFieldFilter")
28-
model NumericFieldFilter {}
38+
// @useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/NumericFieldFilter")
39+
@extension("x-go-type", "filters.FilterNumeric")
40+
@extension(
41+
"x-go-type-import",
42+
#{ path: "github.com/openmeterio/openmeter/api/v3/filters" }
43+
)
44+
model NumericFieldFilter {
45+
/** Value strictly equals the given numeric value. */
46+
eq?: float64;
47+
48+
/** Value does not equal the given numeric value. */
49+
neq?: float64;
50+
51+
/** Returns entities that match any of the comma-delimited numeric values. */
52+
@encode(ArrayEncoding.commaDelimited)
53+
oeq?: float64[];
54+
55+
/** Value is less than the given numeric value. */
56+
lt?: float64;
57+
58+
/** Value is less than or equal to the given numeric value. */
59+
lte?: float64;
60+
61+
/** Value is greater than the given numeric value. */
62+
gt?: float64;
63+
64+
/** Value is greater than or equal to the given numeric value. */
65+
gte?: float64;
66+
}
2967

3068
/**
3169
* Filters on the given string field value by either exact or fuzzy match.
70+
* All properties are optional; provide exactly one to specify the comparison.
3271
*/
3372
@friendlyName("StringFieldFilter")
34-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/StringFieldFilter")
35-
model StringFieldFilter {}
73+
// @useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/StringFieldFilter")
74+
@extension("x-go-type", "filters.FilterString")
75+
@extension(
76+
"x-go-type-import",
77+
#{ path: "github.com/openmeterio/openmeter/api/v3/filters" }
78+
)
79+
union StringFieldFilter {
80+
string: string,
81+
object: {
82+
/** Value strictly equals the given string value. */
83+
eq?: string,
84+
85+
/** Value contains the given string value (fuzzy match). */
86+
contains?: string,
87+
88+
/** Returns entities that fuzzy-match any of the comma-delimited phrases in the filter string. */
89+
@encode(ArrayEncoding.commaDelimited)
90+
ocontains?: string[],
91+
92+
/** Returns entities that exact match any of the comma-delimited phrases in the filter string. */
93+
@encode(ArrayEncoding.commaDelimited)
94+
oeq?: string[],
95+
96+
/** Value does not equal the given string value. */
97+
neq?: string,
98+
},
99+
}
36100

37101
/**
38102
* Filters on the given string field value by exact match.
103+
* All properties are optional; provide exactly one to specify the comparison.
39104
*/
40105
@friendlyName("StringFieldFilterExact")
41-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/StringFieldFilterExact")
42-
model StringFieldFilterExact {}
106+
// @useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/StringFieldFilterExact")
107+
@extension("x-go-type", "filters.FilterStringExact")
108+
@extension(
109+
"x-go-type-import",
110+
#{ path: "github.com/openmeterio/openmeter/api/v3/filters" }
111+
)
112+
model StringFieldFilterExact {
113+
/** Value strictly equals the given string value. */
114+
eq?: string;
115+
116+
/** Returns entities that exact match any of the comma-delimited phrases in the filter string. */
117+
@encode(ArrayEncoding.commaDelimited)
118+
oeq?: string[];
119+
120+
/** Value does not equal the given string value. */
121+
neq?: string;
122+
}
43123

44124
/**
45125
* Filters on the given datetime (RFC-3339) field value.
126+
* All properties are optional; provide exactly one to specify the comparison.
46127
*/
47128
@friendlyName("DateTimeFieldFilter")
48-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/DateTimeFieldFilter")
49-
model DateTimeFieldFilter {}
129+
// @useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/DateTimeFieldFilter")
130+
@extension("x-go-type", "filters.FilterDateTime")
131+
@extension(
132+
"x-go-type-import",
133+
#{ path: "github.com/openmeterio/openmeter/api/v3/filters" }
134+
)
135+
model DateTimeFieldFilter {
136+
/** Value strictly equals given RFC-3339 formatted timestamp in UTC. */
137+
eq?: Shared.DateTime;
138+
139+
/** Value does not equal the given RFC-3339 formatted timestamp in UTC. */
140+
neq?: Shared.DateTime;
141+
142+
/** Returns entities that match any of the comma-delimited RFC-3339 formatted timestamps. */
143+
@encode(ArrayEncoding.commaDelimited)
144+
oeq?: Shared.DateTime[];
145+
146+
/** Value is less than the given RFC-3339 formatted timestamp in UTC. */
147+
lt?: Shared.DateTime;
148+
149+
/** Value is less than or equal to the given RFC-3339 formatted timestamp in UTC. */
150+
lte?: Shared.DateTime;
151+
152+
/** Value is greater than the given RFC-3339 formatted timestamp in UTC. */
153+
gt?: Shared.DateTime;
154+
155+
/** Value is greater than or equal to the given RFC-3339 formatted timestamp in UTC. */
156+
gte?: Shared.DateTime;
157+
}
50158

51159
/**
52160
* Filters on the resource's `labels` field. Filters must use dot-notation to identify
@@ -57,29 +165,30 @@ model DateTimeFieldFilter {}
57165
* - `filter[labels.env][ocontains]=dev,test`
58166
*/
59167
@friendlyName("LabelsFieldFilter")
60-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/LabelsFieldFilter")
61-
model LabelsFieldFilter {}
168+
// @useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/LabelsFieldFilter")
169+
@extension("x-go-type", "filters.FilterString")
170+
@extension(
171+
"x-go-type-import",
172+
#{ path: "github.com/openmeterio/openmeter/api/v3/filters" }
173+
)
174+
union LabelsFieldFilter {
175+
string: string,
176+
object: {
177+
/** Value strictly equals the given string value. */
178+
eq?: string,
62179

63-
/**
64-
* Filters on the resource's `public_labels` field. Filters must use dot-notation to identify
65-
* the label key that will be used to filter the results. For example:
66-
* - `filter[public_labels.owner]`
67-
* - `filter[public_labels.owner][neq]=kong`
68-
* - `filter[public_labels.env]=dev`
69-
* - `filter[public_labels.env][ocontains]=dev,test`
70-
*/
71-
@friendlyName("PublicLabelsFieldFilter")
72-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/PublicLabelsFieldFilter")
73-
model PublicLabelsFieldFilter {}
180+
/** Value contains the given string value (fuzzy match). */
181+
contains?: string,
74182

75-
/**
76-
* Filters on the resource's `attributes` field. Filters must use dot-notation to identify
77-
* the attribute key that will be used to filter the results. For example:
78-
* - `filter[attributes.owner]`
79-
* - `filter[attributes.owner][neq]=kong`
80-
* - `filter[attributes.env]=dev`
81-
* - `filter[attributes.env][ocontains]=dev,test`
82-
*/
83-
@friendlyName("AttributesFieldFilter")
84-
@useRef("../../../../common/definitions/aip_filters.yaml#/components/schemas/AttributesFieldFilter")
85-
model AttributesFieldFilter {}
183+
/** Returns entities that fuzzy-match any of the comma-delimited phrases in the filter string. */
184+
@encode(ArrayEncoding.commaDelimited)
185+
ocontains?: string[],
186+
187+
/** Returns entities that exact match any of the comma-delimited phrases in the filter string. */
188+
@encode(ArrayEncoding.commaDelimited)
189+
oeq?: string[],
190+
191+
/** Value does not equal the given string value. */
192+
neq?: string,
193+
},
194+
}

api/spec/packages/aip/src/customers/operations.tsp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ namespace Customers;
2121
model ListCustomersParamsFilter {
2222
/**
2323
* Filter customers by key.
24-
* Case-insensitive partial match.
2524
*/
26-
key?: Shared.ExternalResourceKey;
25+
key?: Common.StringFieldFilter;
2726
}
2827

2928
interface CustomersOperations {

api/spec/packages/aip/src/llmcost/operations.tsp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ namespace LLMCost;
1717
* TODO: This is a temporary solution to support the filter API.
1818
*/
1919
@friendlyName("FilterSingleString")
20+
@extension("x-go-type", "filters.StringFilter")
21+
@extension(
22+
"x-go-type-import",
23+
#{ path: "github.com/openmeterio/openmeter/api/v3/filters" }
24+
)
2025
model FilterSingleString {
2126
/**
2227
* The field must match the provided value.

0 commit comments

Comments
 (0)