Skip to content

Commit

Permalink
feat: store changes filter by start time (#455)
Browse files Browse the repository at this point in the history
  • Loading branch information
ewanharris authored Dec 17, 2024
2 parents 7e3ed38 + 53af06c commit a390427
Show file tree
Hide file tree
Showing 29 changed files with 89 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Main config
OPENFGA_DOCKER_TAG = v1.7.0
OPEN_API_REF ?= 30477608a587fbebea8940129703c11238530f71
OPEN_API_REF ?= 7c098f10acd22137c659c407818a4e0880044afe
OPEN_API_URL = https://raw.githubusercontent.com/openfga/api/${OPEN_API_REF}/docs/openapiv2/apidocs.swagger.json
OPENAPI_GENERATOR_CLI_DOCKER_TAG = v6.4.0
NODE_DOCKER_TAG = 20-alpine
Expand Down
4 changes: 2 additions & 2 deletions config/clients/dotnet/template/Client/Client.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ public class {{appShortName}}Client : IDisposable {
* Read Changes - Read the list of historical relationship tuple writes and deletes
*/
public async Task<ReadChangesResponse> ReadChanges(ClientReadChangesRequest? body = default,
IClientReadChangesOptions? options = default,
ClientReadChangesOptions? options = default,
CancellationToken cancellationToken = default) =>
await api.ReadChanges(GetStoreId(options), body?.Type, options?.PageSize, options?.ContinuationToken, cancellationToken);
await api.ReadChanges(GetStoreId(options), body?.Type, options?.PageSize, options?.ContinuationToken, body?.StartTime, cancellationToken);

/**
* Read - Read tuples previously written to the store (does not evaluate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ namespace {{packageName}}.Client.Model;

public interface IClientReadChangesRequest {
string Type { get; set; }
DateTime? StartTime {get; set; }
}

public class ClientReadChangesRequest : IClientReadChangesRequest, IEquatable<ClientReadChangesRequest>,
IValidatableObject {
public string Type { get; set; }
public DateTime? StartTime {get; set; }

public bool Equals(ClientReadChangesRequest input) {
if (input == null) {
Expand Down
3 changes: 2 additions & 1 deletion config/clients/dotnet/template/OpenFgaClientTests.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -629,9 +629,10 @@ public class {{appShortName}}ClientTests {

var type = "repo";
var pageSize = 25;
var startTime = DateTime.Parse("2022-01-01T00:00:00Z");
var continuationToken =
"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==";
var response = await fgaClient.ReadChanges(new ClientReadChangesRequest { Type = type }, new ClientReadChangesOptions {
var response = await fgaClient.ReadChanges(new ClientReadChangesRequest { Type = type, StartTime = startTime }, new ClientReadChangesOptions {
PageSize = pageSize,
ContinuationToken = continuationToken,
});
Expand Down
3 changes: 2 additions & 1 deletion config/clients/dotnet/template/README_calling_api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ Reads the list of historical relationship tuple writes and deletes.
[API Documentation]({{apiDocsUrl}}#/Relationship%20Tuples/ReadChanges)

```csharp
var body = new ClientReadChangesRequest { Type = "document" };
var startTime = DateTime.Parse("2022-01-01T00:00:00Z");
var body = new ClientReadChangesRequest { Type = "document", StartTime = startTime };
var options = new ClientReadChangesOptions {
PageSize = 10,
ContinuationToken = "...",
Expand Down
3 changes: 2 additions & 1 deletion config/clients/dotnet/template/api_test.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -1672,8 +1672,9 @@ namespace {{testPackageName}}.Api {

var type = "repo";
var pageSize = 25;
var startTime = DateTime.Parse("2022-01-01T00:00:00Z");
var continuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==";
var response = await {{appCamelCaseName}}Api.ReadChanges(_storeId, type, pageSize, continuationToken);
var response = await {{appCamelCaseName}}Api.ReadChanges(_storeId, type, pageSize, continuationToken, startTime);

mockHandler.Protected().Verify(
"SendAsync",
Expand Down
1 change: 1 addition & 0 deletions config/clients/go/template/README_calling_api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ options := ClientReadChangesOptions{
ContinuationToken: {{packageName}}.PtrString("eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="),
// You can rely on the store id set in the configuration or override it for this specific request
StoreId: {{packageName}}.PtrString("01FQH7V8BEG3GPQW93KTRFR8JB"),
StartTime: {{packageName}}.PtrString("2022-01-01T00:00:00Z"),
}
data, err := fgaClient.ReadChanges(context.Background()).Body(body).Options(options).Execute()

Expand Down
3 changes: 3 additions & 0 deletions config/clients/go/template/api_test.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"testing"
"time"

"github.com/jarcoal/httpmock"
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/credentials"
Expand Down Expand Up @@ -789,9 +790,11 @@ func Test{{appShortName}}Api(t *testing.T) {
return resp, nil
},
)
startTime, err := time.Parse(time.RFC3339, "2022-01-01T00:00:00Z")
got, response, err := apiClient.{{appShortName}}Api.ReadChanges(context.Background(), "01GXSB9YR785C4FYS3C0RTG7B2").
Type_("repo").
PageSize(25).
StartTime(startTime).
ContinuationToken("eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==").
Execute()
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions config/clients/go/template/client/client.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"math"
_nethttp "net/http"
"time"

fgaSdk "{{gitHost}}/{{gitUserId}}/{{gitRepoId}}"
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/credentials"
Expand Down Expand Up @@ -1125,6 +1126,7 @@ type SdkClientReadChangesRequestInterface interface {

type ClientReadChangesRequest struct {
Type string `json:"type,omitempty"`
StartTime time.Time `json:"start_time,omitempty"`
}

type ClientReadChangesOptions struct {
Expand Down
6 changes: 6 additions & 0 deletions config/clients/go/template/client/client_test.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"testing"
"time"

"github.com/jarcoal/httpmock"
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}"
Expand Down Expand Up @@ -1038,8 +1039,13 @@ func Test{{appShortName}}Client(t *testing.T) {
return resp, nil
},
)
startTime, err := time.Parse(time.RFC3339,"2022-01-01T00:00:00Z")
if err != nil {
t.Fatalf("Failed to parse startTime: %v", err)
}
body := ClientReadChangesRequest{
Type: "document",
StartTime: startTime,
}
options := ClientReadChangesOptions{ContinuationToken: {{packageName}}.PtrString("eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="), PageSize: {{packageName}}.PtrInt32(25)}
got, err := fgaClient.ReadChanges(context.Background()).Body(body).Options(options).Execute()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ public class OpenFgaApiIntegrationTest {
// When
api.write(storeId, writeRequest).get();
ReadChangesResponse response =
api.readChanges(storeId, null, null, null).get().getData();
api.readChanges(storeId, null, null, null,null).get().getData();
// Then
assertEquals(1, response.getChanges().size());
Expand Down
15 changes: 10 additions & 5 deletions config/clients/java/template/OpenFgaApiTest.java.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.time.OffsetDateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -794,9 +795,10 @@ public class OpenFgaApiTest {
String type = null; // Input is optional
Integer pageSize = null; // Input is optional
String continuationToken = null; // Input is optional
OffsetDateTime startTime = null; //Input is optional
// When
var response = fga.readChanges(DEFAULT_STORE_ID, type, pageSize, continuationToken)
var response = fga.readChanges(DEFAULT_STORE_ID, type, pageSize, continuationToken, startTime)
.get();
// Then
Expand All @@ -814,7 +816,7 @@ public class OpenFgaApiTest {
@Test
public void readChanges_storeIdRequired() throws Exception {
// When
var exception = assertThrows(FgaInvalidParameterException.class, () -> fga.readChanges(null, null, null, null)
var exception = assertThrows(FgaInvalidParameterException.class, () -> fga.readChanges(null, null, null, null, null)
.get());
// Then
Expand All @@ -831,10 +833,11 @@ public class OpenFgaApiTest {
String type = null; // Input is optional
Integer pageSize = null; // Input is optional
String continuationToken = null; // Input is optional
OffsetDateTime startTime = null; // Input is optional
// When
ExecutionException execException = assertThrows(
ExecutionException.class, () -> fga.readChanges(DEFAULT_STORE_ID, type, pageSize, continuationToken)
ExecutionException.class, () -> fga.readChanges(DEFAULT_STORE_ID, type, pageSize, continuationToken, startTime)
.get());
// Then
Expand All @@ -856,10 +859,11 @@ public class OpenFgaApiTest {
String type = null; // Input is optional
Integer pageSize = null; // Input is optional
String continuationToken = null; // Input is optional
OffsetDateTime startTime = null; // Input is optional
// When
ExecutionException execException = assertThrows(
ExecutionException.class, () -> fga.readChanges(DEFAULT_STORE_ID, type, pageSize, continuationToken)
ExecutionException.class, () -> fga.readChanges(DEFAULT_STORE_ID, type, pageSize, continuationToken, startTime)
.get());
// Then
Expand All @@ -880,10 +884,11 @@ public class OpenFgaApiTest {
String type = null; // Input is optional
Integer pageSize = null; // Input is optional
String continuationToken = null; // Input is optional
OffsetDateTime startTime = null; // Input is optional
// When
ExecutionException execException = assertThrows(
ExecutionException.class, () -> fga.readChanges(DEFAULT_STORE_ID, type, pageSize, continuationToken)
ExecutionException.class, () -> fga.readChanges(DEFAULT_STORE_ID, type, pageSize, continuationToken, startTime)
.get());
// Then
Expand Down
3 changes: 2 additions & 1 deletion config/clients/java/template/README_calling_api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ Reads the list of historical relationship tuple writes and deletes.
> Passing `ClientReadChangesOptions` is optional. All fields of `ClientReadChangesOptions` are optional.

```java
var request = new ClientReadChangesRequest().type("document");
var startTime = OffsetDateTime.parse("2022-01-01T00:00:00+00:00");
var request = new ClientReadChangesRequest().type("document").startTime(startTime);
var options = new ClientReadChangesOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
.pageSize(10)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
{{>licenseInfo}}
package {{clientPackage}}.model;

import java.time.OffsetDateTime;

public class ClientReadChangesRequest {
private String type;
private OffsetDateTime startTime;
public ClientReadChangesRequest type(String type) {
this.type = type;
return this;
}

public ClientReadChangesRequest startTime(OffsetDateTime startTime) {
this.startTime = startTime;
return this;
}

public String getType() {
return type;
}

public OffsetDateTime getStartTime(){
return startTime;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public class OpenFgaClient {
var options = readChangesOptions != null ? readChangesOptions : new ClientReadChangesOptions();
var overrides = new ConfigurationOverride().addHeaders(options);
return call(() -> api.readChanges(
storeId, request.getType(), options.getPageSize(), options.getContinuationToken(), overrides))
storeId, request.getType(), options.getPageSize(), options.getContinuationToken(), request.getStartTime(), overrides))
.thenApply(ClientReadChangesResponse::new);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {{invokerPackage}}.*;
import {{modelPackage}}.*;
import java.net.http.HttpClient;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
Expand Down Expand Up @@ -694,13 +695,14 @@ public class OpenFgaClientTest {
public void readChanges() throws Exception {
// Given
String changeType = "repo";
OffsetDateTime startTime = null;
String user = "user:81684243-9356-4421-8fbf-a4f8d36aa31b";
String relation = "viewer";
String object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a";
String continuationToken =
"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ";
ClientReadChangesRequest request = new ClientReadChangesRequest().type(changeType);
ClientReadChangesRequest request = new ClientReadChangesRequest().type(changeType).startTime(startTime);
String getUrl =
String.format("https://api.fga.example/stores/%s/changes?type=%s", DEFAULT_STORE_ID, changeType);
String responseBody = String.format(
Expand Down
3 changes: 2 additions & 1 deletion config/clients/js/template/README_calling_api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,13 @@ Reads the list of historical relationship tuple writes and deletes.

```javascript
const type = 'document';
const startTime = "2022-01-01T00:00:00Z"
const options = {
pageSize: 25,
continuationToken: 'eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==',
};

const response = await fgaClient.readChanges({ type }, options);
const response = await fgaClient.readChanges({ type, startTime }, options);

// response.continuation_token = ...
// response.changes = [
Expand Down
4 changes: 3 additions & 1 deletion config/clients/js/template/client.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export interface ClientListRelationsResponse {

export interface ClientReadChangesRequest {
type: string;
startTime?: string;
}

export type ClientExpandRequest = ExpandRequestTupleKey;
Expand Down Expand Up @@ -379,13 +380,14 @@ export class {{appShortName}}Client extends BaseAPI {
* @param {ClientRequestOpts & PaginationOptions} [options]
* @param {number} [options.pageSize]
* @param {string} [options.continuationToken]
* @param {string} [body.startTime]
* @param {object} [options.headers] - Custom headers to send alongside the request
* @param {object} [options.retryParams] - Override the retry parameters for this request
* @param {number} [options.retryParams.maxRetry] - Override the max number of retries on each API request
* @param {number} [options.retryParams.minWaitInMs] - Override the minimum wait before a retry is initiated
*/
async readChanges(body?: ClientReadChangesRequest, options: ClientRequestOptsWithStoreId & PaginationOptions = {}): PromiseResult<ReadChangesResponse> {
return this.api.readChanges(this.getStoreId(options)!, body?.type, options.pageSize, options.continuationToken, options);
return this.api.readChanges(this.getStoreId(options)!, body?.type, options.pageSize, options.continuationToken, body?.startTime, options);
}

/**
Expand Down
8 changes: 5 additions & 3 deletions config/clients/js/template/tests/client.test.ts.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -249,12 +249,13 @@ describe("{{appTitleCaseName}} Client", () => {
it("should properly call the ReadChanges API", async () => {
const type = "repo";
const pageSize = 25;
const startTime = "2022-01-01T00:00:00Z";
const continuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==";
const scope = nocks.readChanges(baseConfig.storeId!, type, pageSize, continuationToken);
const scope = nocks.readChanges(baseConfig.storeId!, type, pageSize, continuationToken, startTime);
expect(scope.isDone()).toBe(false);
const response = await fgaClient.readChanges({ type }, { pageSize, continuationToken });
const response = await fgaClient.readChanges({ type, startTime }, { pageSize, continuationToken });

expect(scope.isDone()).toBe(true);
expect(response).toMatchObject({ changes: expect.arrayContaining([]) });
Expand All @@ -263,8 +264,9 @@ describe("{{appTitleCaseName}} Client", () => {
it("should properly call the ReadChanges API with no type", async () => {
const pageSize = 25;
const continuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==";
const startTime = "2022-01-01T00:00:00Z";
const scope = nocks.readChanges(baseConfig.storeId!, "", pageSize, continuationToken);
const scope = nocks.readChanges(baseConfig.storeId!, "", pageSize, continuationToken,"");
expect(scope.isDone()).toBe(false);
const response = await fgaClient.readChanges(undefined, { pageSize, continuationToken });
Expand Down
5 changes: 3 additions & 2 deletions config/clients/js/template/tests/helpers/nocks.ts.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,14 @@ export const getNocks = ((nock: typeof Nock) => ({
authorization_model: authorizationModel
});
},
readChanges: (storeId: string, type: string, pageSize: number, contToken: string, basePath = defaultConfiguration.getBasePath()) => {
readChanges: (storeId: string, type: string, pageSize: number, contToken: string, startTime: string, basePath = defaultConfiguration.getBasePath()) => {
return nock(basePath)
.get(`/stores/${storeId}/changes`)
.query({
page_size: pageSize,
continuation_token: contToken,
...(type ? { type } : { })
...(type ? { type } : { }),
...(startTime ? {start_time: startTime } :{})
})
.reply(200, {
changes: [{
Expand Down
5 changes: 3 additions & 2 deletions config/clients/js/template/tests/index.test.ts.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -801,11 +801,12 @@ describe("{{appTitleCaseName}} SDK", function () {
const type = "repo";
const pageSize = 25;
const continuationToken = "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==";
const startTime = "2022-01-01T00:00:00Z";
const scope = nocks.readChanges(baseConfig.storeId!, type, pageSize, continuationToken);
const scope = nocks.readChanges(baseConfig.storeId!, type, pageSize, continuationToken, startTime);
expect(scope.isDone()).toBe(false);
const response = await fgaApi.readChanges(baseConfig.storeId!, type, pageSize, continuationToken);
const response = await fgaApi.readChanges(baseConfig.storeId!, type, pageSize, continuationToken, startTime);
expect(scope.isDone()).toBe(true);
expect(response).toMatchObject({ changes: expect.arrayContaining([]) });
Expand Down
2 changes: 1 addition & 1 deletion config/clients/python/template/README_calling_api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ options = {
"page_size": "25",
"continuation_token": "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="
}
body = ClientReadChangesRequest(type="document")
body = ClientReadChangesRequest(type="document", start_time="2022-01-01T00:00:00Z")

response = await fga_client.read_changes(body, options)
# response.continuation_token = ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ class OpenFgaClient:
"""
kwargs = options_to_kwargs(options)
kwargs["type"] = body.type
kwargs["start_time"] = body.start_time
api_response = {{#asyncio}}await {{/asyncio}}self._api.read_changes(
**kwargs,
)
Expand Down
Loading

0 comments on commit a390427

Please sign in to comment.