diff --git a/routePlan.go b/routePlan.go index 7b59a2f..bc02564 100644 --- a/routePlan.go +++ b/routePlan.go @@ -58,8 +58,3 @@ type RoutePlanListQueryParams struct { type RoutePlanAddTasksParams struct { Tasks []string `json:"tasks"` } - -type RoutePlansPaginated struct { - LastId string `json:"lastId,omitempty"` - RoutePlans []RoutePlan `json:"routePlans"` -} diff --git a/service/admin/client.go b/service/admin/client.go index 7ea7dd7..0fec905 100644 --- a/service/admin/client.go +++ b/service/admin/client.go @@ -101,3 +101,53 @@ func (c *Client) Delete(adminId string) error { ) return err } + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataSet atomically adds or updates metadata fields without affecting other metadata +func (c *Client) MetadataSet(adminId string, metadata ...onfleet.Metadata) (onfleet.Admin, error) { + admin := onfleet.Admin{} + body := map[string]any{ + "metadata": map[string]any{ + "$set": metadata, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{adminId}, + nil, + body, + &admin, + ) + return admin, err +} + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataPop atomically removes metadata fields without affecting other metadata +func (c *Client) MetadataPop(adminId string, names ...string) (onfleet.Admin, error) { + admin := onfleet.Admin{} + + popArray := make([]map[string]string, len(names)) + for i, name := range names { + popArray[i] = map[string]string{"name": name} + } + + body := map[string]any{ + "metadata": map[string]any{ + "$pop": popArray, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{adminId}, + nil, + body, + &admin, + ) + return admin, err +} diff --git a/service/admin/client_test.go b/service/admin/client_test.go index f482cf7..49c1364 100644 --- a/service/admin/client_test.go +++ b/service/admin/client_test.go @@ -380,4 +380,170 @@ func TestClient_ErrorScenarios(t *testing.T) { assert.Error(t, err) }) } +} + +func TestClient_MetadataSet(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedAdmin := testingutil.GetSampleAdmin() + expectedAdmin.Metadata = []onfleet.Metadata{ + { + Name: "role", + Type: "string", + Value: "manager", + }, + } + + mockClient.AddResponse("/admins/admin_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedAdmin, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/admins", mockClient.MockCaller) + + metadata := []onfleet.Metadata{ + { + Name: "role", + Type: "string", + Value: "manager", + }, + } + + admin, err := client.MetadataSet("admin_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedAdmin.ID, admin.ID) + + // Verify the field was set + assert.Len(t, admin.Metadata, 1) + assert.Equal(t, "role", admin.Metadata[0].Name) + assert.Equal(t, "manager", admin.Metadata[0].Value) + + mockClient.AssertRequestMade("PUT", "/admins/admin_123") +} + +func TestClient_MetadataSet_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedAdmin := testingutil.GetSampleAdmin() + expectedAdmin.Metadata = []onfleet.Metadata{ + { + Name: "department", + Type: "string", + Value: "operations", + }, + { + Name: "level", + Type: "number", + Value: float64(3), + }, + } + + mockClient.AddResponse("/admins/admin_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedAdmin, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/admins", mockClient.MockCaller) + + // Set only level field + metadata := []onfleet.Metadata{ + { + Name: "level", + Type: "number", + Value: float64(3), + }, + } + + admin, err := client.MetadataSet("admin_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedAdmin.ID, admin.ID) + + // Verify both fields are present (atomicity - department was preserved) + assert.Len(t, admin.Metadata, 2) + + var foundDepartment, foundLevel bool + for _, m := range admin.Metadata { + if m.Name == "department" { + foundDepartment = true + assert.Equal(t, "operations", m.Value) + } + if m.Name == "level" { + foundLevel = true + assert.Equal(t, float64(3), m.Value) + } + } + assert.True(t, foundDepartment, "department field should be preserved") + assert.True(t, foundLevel, "level field should be set") + + mockClient.AssertRequestMade("PUT", "/admins/admin_123") +} + +func TestClient_MetadataPop(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedAdmin := testingutil.GetSampleAdmin() + expectedAdmin.Metadata = []onfleet.Metadata{} + + mockClient.AddResponse("/admins/admin_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedAdmin, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/admins", mockClient.MockCaller) + + admin, err := client.MetadataPop("admin_123", "temp_access") + + assert.NoError(t, err) + assert.Equal(t, expectedAdmin.ID, admin.ID) + + // Verify the field was removed + assert.Len(t, admin.Metadata, 0) + for _, m := range admin.Metadata { + assert.NotEqual(t, "temp_access", m.Name, "temp_access field should be removed") + } + + mockClient.AssertRequestMade("PUT", "/admins/admin_123") +} + +func TestClient_MetadataPop_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedAdmin := testingutil.GetSampleAdmin() + expectedAdmin.Metadata = []onfleet.Metadata{ + { + Name: "department", + Type: "string", + Value: "operations", + }, + } + + mockClient.AddResponse("/admins/admin_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedAdmin, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/admins", mockClient.MockCaller) + + admin, err := client.MetadataPop("admin_123", "old_field") + + assert.NoError(t, err) + assert.Equal(t, expectedAdmin.ID, admin.ID) + + // Verify department was preserved (atomicity) + assert.Len(t, admin.Metadata, 1) + assert.Equal(t, "department", admin.Metadata[0].Name) + assert.Equal(t, "operations", admin.Metadata[0].Value) + + // Verify old_field is not present + for _, m := range admin.Metadata { + assert.NotEqual(t, "old_field", m.Name, "old_field should not be present") + } + + mockClient.AssertRequestMade("PUT", "/admins/admin_123") } \ No newline at end of file diff --git a/service/destination/client.go b/service/destination/client.go index e8cef5d..2f35932 100644 --- a/service/destination/client.go +++ b/service/destination/client.go @@ -70,3 +70,53 @@ func (c *Client) ListWithMetadataQuery(metadata []onfleet.Metadata) ([]onfleet.D ) return destinations, err } + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataSet atomically adds or updates metadata fields without affecting other metadata +func (c *Client) MetadataSet(destinationId string, metadata ...onfleet.Metadata) (onfleet.Destination, error) { + destination := onfleet.Destination{} + body := map[string]any{ + "metadata": map[string]any{ + "$set": metadata, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{destinationId}, + nil, + body, + &destination, + ) + return destination, err +} + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataPop atomically removes metadata fields without affecting other metadata +func (c *Client) MetadataPop(destinationId string, names ...string) (onfleet.Destination, error) { + destination := onfleet.Destination{} + + popArray := make([]map[string]string, len(names)) + for i, name := range names { + popArray[i] = map[string]string{"name": name} + } + + body := map[string]any{ + "metadata": map[string]any{ + "$pop": popArray, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{destinationId}, + nil, + body, + &destination, + ) + return destination, err +} diff --git a/service/destination/client_test.go b/service/destination/client_test.go index 8b75292..f494bd7 100644 --- a/service/destination/client_test.go +++ b/service/destination/client_test.go @@ -128,4 +128,170 @@ func TestClient_ErrorScenarios(t *testing.T) { assert.Error(t, err) }) } +} + +func TestClient_MetadataSet(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedDestination := testingutil.GetSampleDestination() + expectedDestination.Metadata = []onfleet.Metadata{ + { + Name: "location_type", + Type: "string", + Value: "warehouse", + }, + } + + mockClient.AddResponse("/destinations/destination_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedDestination, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/destinations", mockClient.MockCaller) + + metadata := []onfleet.Metadata{ + { + Name: "location_type", + Type: "string", + Value: "warehouse", + }, + } + + destination, err := client.MetadataSet("destination_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedDestination.ID, destination.ID) + + // Verify the field was set + assert.Len(t, destination.Metadata, 1) + assert.Equal(t, "location_type", destination.Metadata[0].Name) + assert.Equal(t, "warehouse", destination.Metadata[0].Value) + + mockClient.AssertRequestMade("PUT", "/destinations/destination_123") +} + +func TestClient_MetadataSet_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedDestination := testingutil.GetSampleDestination() + expectedDestination.Metadata = []onfleet.Metadata{ + { + Name: "building_code", + Type: "string", + Value: "B123", + }, + { + Name: "floor", + Type: "number", + Value: float64(3), + }, + } + + mockClient.AddResponse("/destinations/destination_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedDestination, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/destinations", mockClient.MockCaller) + + // Set only floor field + metadata := []onfleet.Metadata{ + { + Name: "floor", + Type: "number", + Value: float64(3), + }, + } + + destination, err := client.MetadataSet("destination_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedDestination.ID, destination.ID) + + // Verify both fields are present (atomicity - building_code was preserved) + assert.Len(t, destination.Metadata, 2) + + var foundBuilding, foundFloor bool + for _, m := range destination.Metadata { + if m.Name == "building_code" { + foundBuilding = true + assert.Equal(t, "B123", m.Value) + } + if m.Name == "floor" { + foundFloor = true + assert.Equal(t, float64(3), m.Value) + } + } + assert.True(t, foundBuilding, "building_code field should be preserved") + assert.True(t, foundFloor, "floor field should be set") + + mockClient.AssertRequestMade("PUT", "/destinations/destination_123") +} + +func TestClient_MetadataPop(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedDestination := testingutil.GetSampleDestination() + expectedDestination.Metadata = []onfleet.Metadata{} + + mockClient.AddResponse("/destinations/destination_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedDestination, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/destinations", mockClient.MockCaller) + + destination, err := client.MetadataPop("destination_123", "temp_flag") + + assert.NoError(t, err) + assert.Equal(t, expectedDestination.ID, destination.ID) + + // Verify the field was removed + assert.Len(t, destination.Metadata, 0) + for _, m := range destination.Metadata { + assert.NotEqual(t, "temp_flag", m.Name, "temp_flag field should be removed") + } + + mockClient.AssertRequestMade("PUT", "/destinations/destination_123") +} + +func TestClient_MetadataPop_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedDestination := testingutil.GetSampleDestination() + expectedDestination.Metadata = []onfleet.Metadata{ + { + Name: "location_type", + Type: "string", + Value: "residential", + }, + } + + mockClient.AddResponse("/destinations/destination_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedDestination, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/destinations", mockClient.MockCaller) + + destination, err := client.MetadataPop("destination_123", "old_field") + + assert.NoError(t, err) + assert.Equal(t, expectedDestination.ID, destination.ID) + + // Verify location_type was preserved (atomicity) + assert.Len(t, destination.Metadata, 1) + assert.Equal(t, "location_type", destination.Metadata[0].Name) + assert.Equal(t, "residential", destination.Metadata[0].Value) + + // Verify old_field is not present + for _, m := range destination.Metadata { + assert.NotEqual(t, "old_field", m.Name, "old_field should not be present") + } + + mockClient.AssertRequestMade("PUT", "/destinations/destination_123") } \ No newline at end of file diff --git a/service/recipient/client.go b/service/recipient/client.go index dd71435..ea390db 100644 --- a/service/recipient/client.go +++ b/service/recipient/client.go @@ -102,3 +102,53 @@ func (c *Client) ListWithMetadataQuery(metadata []onfleet.Metadata) ([]onfleet.R ) return recipients, err } + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataSet atomically adds or updates metadata fields without affecting other metadata +func (c *Client) MetadataSet(recipientId string, metadata ...onfleet.Metadata) (onfleet.Recipient, error) { + recipient := onfleet.Recipient{} + body := map[string]any{ + "metadata": map[string]any{ + "$set": metadata, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{recipientId}, + nil, + body, + &recipient, + ) + return recipient, err +} + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataPop atomically removes metadata fields without affecting other metadata +func (c *Client) MetadataPop(recipientId string, names ...string) (onfleet.Recipient, error) { + recipient := onfleet.Recipient{} + + popArray := make([]map[string]string, len(names)) + for i, name := range names { + popArray[i] = map[string]string{"name": name} + } + + body := map[string]any{ + "metadata": map[string]any{ + "$pop": popArray, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{recipientId}, + nil, + body, + &recipient, + ) + return recipient, err +} diff --git a/service/recipient/client_test.go b/service/recipient/client_test.go index bb7863a..efcc75d 100644 --- a/service/recipient/client_test.go +++ b/service/recipient/client_test.go @@ -275,4 +275,170 @@ func TestClient_PhoneNumberEncoding(t *testing.T) { assert.Equal(t, tt.phoneNumber, recipient.Phone) }) } +} + +func TestClient_MetadataSet(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedRecipient := testingutil.GetSampleRecipient() + expectedRecipient.Metadata = []onfleet.Metadata{ + { + Name: "customer_id", + Type: "string", + Value: "CUST12345", + }, + } + + mockClient.AddResponse("/recipients/recipient_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedRecipient, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/recipients", mockClient.MockCaller) + + metadata := []onfleet.Metadata{ + { + Name: "customer_id", + Type: "string", + Value: "CUST12345", + }, + } + + recipient, err := client.MetadataSet("recipient_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedRecipient.ID, recipient.ID) + + // Verify the field was set + assert.Len(t, recipient.Metadata, 1) + assert.Equal(t, "customer_id", recipient.Metadata[0].Name) + assert.Equal(t, "CUST12345", recipient.Metadata[0].Value) + + mockClient.AssertRequestMade("PUT", "/recipients/recipient_123") +} + +func TestClient_MetadataSet_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedRecipient := testingutil.GetSampleRecipient() + expectedRecipient.Metadata = []onfleet.Metadata{ + { + Name: "customer_tier", + Type: "string", + Value: "gold", + }, + { + Name: "loyalty_points", + Type: "number", + Value: float64(500), + }, + } + + mockClient.AddResponse("/recipients/recipient_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedRecipient, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/recipients", mockClient.MockCaller) + + // Set only loyalty_points field + metadata := []onfleet.Metadata{ + { + Name: "loyalty_points", + Type: "number", + Value: float64(500), + }, + } + + recipient, err := client.MetadataSet("recipient_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedRecipient.ID, recipient.ID) + + // Verify both fields are present (atomicity - customer_tier was preserved) + assert.Len(t, recipient.Metadata, 2) + + var foundTier, foundPoints bool + for _, m := range recipient.Metadata { + if m.Name == "customer_tier" { + foundTier = true + assert.Equal(t, "gold", m.Value) + } + if m.Name == "loyalty_points" { + foundPoints = true + assert.Equal(t, float64(500), m.Value) + } + } + assert.True(t, foundTier, "customer_tier field should be preserved") + assert.True(t, foundPoints, "loyalty_points field should be set") + + mockClient.AssertRequestMade("PUT", "/recipients/recipient_123") +} + +func TestClient_MetadataPop(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedRecipient := testingutil.GetSampleRecipient() + expectedRecipient.Metadata = []onfleet.Metadata{} + + mockClient.AddResponse("/recipients/recipient_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedRecipient, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/recipients", mockClient.MockCaller) + + recipient, err := client.MetadataPop("recipient_123", "temp_note") + + assert.NoError(t, err) + assert.Equal(t, expectedRecipient.ID, recipient.ID) + + // Verify the field was removed + assert.Len(t, recipient.Metadata, 0) + for _, m := range recipient.Metadata { + assert.NotEqual(t, "temp_note", m.Name, "temp_note field should be removed") + } + + mockClient.AssertRequestMade("PUT", "/recipients/recipient_123") +} + +func TestClient_MetadataPop_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedRecipient := testingutil.GetSampleRecipient() + expectedRecipient.Metadata = []onfleet.Metadata{ + { + Name: "customer_id", + Type: "string", + Value: "CUST99999", + }, + } + + mockClient.AddResponse("/recipients/recipient_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedRecipient, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/recipients", mockClient.MockCaller) + + recipient, err := client.MetadataPop("recipient_123", "old_field") + + assert.NoError(t, err) + assert.Equal(t, expectedRecipient.ID, recipient.ID) + + // Verify customer_id was preserved (atomicity) + assert.Len(t, recipient.Metadata, 1) + assert.Equal(t, "customer_id", recipient.Metadata[0].Name) + assert.Equal(t, "CUST99999", recipient.Metadata[0].Value) + + // Verify old_field is not present + for _, m := range recipient.Metadata { + assert.NotEqual(t, "old_field", m.Name, "old_field should not be present") + } + + mockClient.AssertRequestMade("PUT", "/recipients/recipient_123") } \ No newline at end of file diff --git a/service/routePlan/client.go b/service/routePlan/client.go index 63b7f71..8317fa2 100644 --- a/service/routePlan/client.go +++ b/service/routePlan/client.go @@ -63,7 +63,7 @@ func (c *Client) AddTasks(routePlanId string, params onfleet.RoutePlanAddTasksPa c.rlHttpClient, http.MethodPut, c.url, - []string{routePlanId}, + []string{routePlanId, "tasks"}, nil, params, &routePlan, @@ -88,19 +88,19 @@ func (c *Client) Get(routePlanId string) (onfleet.RoutePlan, error) { } // Reference https://docs.onfleet.com/reference/get-route-plan -func (c *Client) List(params onfleet.RoutePlanListQueryParams) (onfleet.RoutePlansPaginated, error) { - paginatedRoutePlans := onfleet.RoutePlansPaginated{} +func (c *Client) List(params onfleet.RoutePlanListQueryParams) ([]onfleet.RoutePlan, error) { + var routePlans []onfleet.RoutePlan err := c.call( c.apiKey, c.rlHttpClient, http.MethodGet, c.url, - []string{"all"}, + nil, params, nil, - &paginatedRoutePlans, + &routePlans, ) - return paginatedRoutePlans, err + return routePlans, err } // Reference https://docs.onfleet.com/reference/delete-routePlan diff --git a/service/routePlan/client_test.go b/service/routePlan/client_test.go index e7f8b0a..715b15e 100644 --- a/service/routePlan/client_test.go +++ b/service/routePlan/client_test.go @@ -13,12 +13,12 @@ func TestClient_Create(t *testing.T) { defer testingutil.CleanupTest(t, mockClient) expectedRoutePlan := testingutil.GetSampleRoutePlan() - mockClient.AddResponse("/route-plans", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans", testingutil.MockResponse{ StatusCode: 201, Body: expectedRoutePlan, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) params := onfleet.RoutePlanParams{ Name: "Evening Delivery Route", @@ -43,7 +43,7 @@ func TestClient_Create(t *testing.T) { assert.Equal(t, expectedRoutePlan.Name, routePlan.Name) assert.Equal(t, expectedRoutePlan.VehicleType, routePlan.VehicleType) - mockClient.AssertRequestMade("POST", "/route-plans") + mockClient.AssertRequestMade("POST", "/routePlans") mockClient.AssertBasicAuth("test_api_key") } @@ -52,12 +52,12 @@ func TestClient_Get(t *testing.T) { defer testingutil.CleanupTest(t, mockClient) expectedRoutePlan := testingutil.GetSampleRoutePlan() - mockClient.AddResponse("/route-plans/routeplan_123", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans/routeplan_123", testingutil.MockResponse{ StatusCode: 200, Body: expectedRoutePlan, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) routePlan, err := client.Get("routeplan_123") @@ -67,7 +67,7 @@ func TestClient_Get(t *testing.T) { assert.Equal(t, expectedRoutePlan.State, routePlan.State) assert.Len(t, routePlan.Tasks, 3) - mockClient.AssertRequestMade("GET", "/route-plans/routeplan_123") + mockClient.AssertRequestMade("GET", "/routePlans/routeplan_123") } func TestClient_Update(t *testing.T) { @@ -78,12 +78,12 @@ func TestClient_Update(t *testing.T) { expectedRoutePlan.Name = "Updated Morning Route" expectedRoutePlan.Color = "#00FF00" - mockClient.AddResponse("/route-plans/routeplan_123", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans/routeplan_123", testingutil.MockResponse{ StatusCode: 200, Body: expectedRoutePlan, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) params := onfleet.RoutePlanParams{ Name: "Updated Morning Route", @@ -99,7 +99,7 @@ func TestClient_Update(t *testing.T) { assert.Equal(t, "Updated Morning Route", routePlan.Name) assert.Equal(t, "#00FF00", routePlan.Color) - mockClient.AssertRequestMade("PUT", "/route-plans/routeplan_123") + mockClient.AssertRequestMade("PUT", "/routePlans/routeplan_123") } func TestClient_AddTasks(t *testing.T) { @@ -109,12 +109,12 @@ func TestClient_AddTasks(t *testing.T) { expectedRoutePlan := testingutil.GetSampleRoutePlan() expectedRoutePlan.Tasks = []string{"task_111", "task_222", "task_333", "task_444", "task_555"} - mockClient.AddResponse("/route-plans/routeplan_123", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans/routeplan_123", testingutil.MockResponse{ StatusCode: 200, Body: expectedRoutePlan, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) params := onfleet.RoutePlanAddTasksParams{ Tasks: []string{"task_444", "task_555"}, @@ -128,28 +128,23 @@ func TestClient_AddTasks(t *testing.T) { assert.Equal(t, "task_444", routePlan.Tasks[3]) assert.Equal(t, "task_555", routePlan.Tasks[4]) - mockClient.AssertRequestMade("PUT", "/route-plans/routeplan_123") + mockClient.AssertRequestMade("PUT", "/routePlans/routeplan_123") } func TestClient_List(t *testing.T) { mockClient := testingutil.SetupTest(t) defer testingutil.CleanupTest(t, mockClient) - expectedRoutePlans := []onfleet.RoutePlan{ + expectedResponse := []onfleet.RoutePlan{ testingutil.GetSampleRoutePlan(), } - expectedResponse := onfleet.RoutePlansPaginated{ - RoutePlans: expectedRoutePlans, - LastId: "routeplan_123", - } - - mockClient.AddResponse("/route-plans/all", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans", testingutil.MockResponse{ StatusCode: 200, Body: expectedResponse, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) params := onfleet.RoutePlanListQueryParams{ WorkerId: "worker_123", @@ -161,31 +156,30 @@ func TestClient_List(t *testing.T) { Limit: 10, } - response, err := client.List(params) + RoutePlans, err := client.List(params) assert.NoError(t, err) - assert.Len(t, response.RoutePlans, 1) - assert.Equal(t, expectedRoutePlans[0].Id, response.RoutePlans[0].Id) - assert.Equal(t, "routeplan_123", response.LastId) + assert.Len(t, RoutePlans, 1) + assert.Equal(t, expectedResponse[0].Id, RoutePlans[0].Id) - mockClient.AssertRequestMade("GET", "/route-plans/all") + mockClient.AssertRequestMade("GET", "/routePlans") } func TestClient_Delete(t *testing.T) { mockClient := testingutil.SetupTest(t) defer testingutil.CleanupTest(t, mockClient) - mockClient.AddResponse("/route-plans/routeplan_123", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans/routeplan_123", testingutil.MockResponse{ StatusCode: 200, Body: map[string]interface{}{"success": true}, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) err := client.Delete("routeplan_123") assert.NoError(t, err) - mockClient.AssertRequestMade("DELETE", "/route-plans/routeplan_123") + mockClient.AssertRequestMade("DELETE", "/routePlans/routeplan_123") } func TestClient_VehicleTypes(t *testing.T) { @@ -223,12 +217,12 @@ func TestClient_VehicleTypes(t *testing.T) { expectedRoutePlan := testingutil.GetSampleRoutePlan() expectedRoutePlan.VehicleType = tt.vehicleType - mockClient.AddResponse("/route-plans", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans", testingutil.MockResponse{ StatusCode: 201, Body: expectedRoutePlan, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) params := onfleet.RoutePlanParams{ Name: "Vehicle Type Test Route", @@ -293,12 +287,12 @@ func TestClient_PositionTypes(t *testing.T) { expectedRoutePlan.EndingHubId = nil } - mockClient.AddResponse("/route-plans", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans", testingutil.MockResponse{ StatusCode: 201, Body: expectedRoutePlan, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) params := onfleet.RoutePlanParams{ Name: "Position Test Route", @@ -351,12 +345,12 @@ func TestClient_RoutePlanStates(t *testing.T) { expectedRoutePlan := testingutil.GetSampleRoutePlan() expectedRoutePlan.State = tt.state - mockClient.AddResponse("/route-plans/routeplan_123", testingutil.MockResponse{ + mockClient.AddResponse("/routePlans/routeplan_123", testingutil.MockResponse{ StatusCode: 200, Body: expectedRoutePlan, }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) routePlan, err := client.Get("routeplan_123") @@ -377,7 +371,7 @@ func TestClient_ErrorScenarios(t *testing.T) { { name: "create invalid start time", method: "POST", - url: "/route-plans", + url: "/routePlans", statusCode: 400, operation: func(client *Client) error { _, err := client.Create(onfleet.RoutePlanParams{ @@ -390,7 +384,7 @@ func TestClient_ErrorScenarios(t *testing.T) { { name: "create missing worker and team", method: "POST", - url: "/route-plans", + url: "/routePlans", statusCode: 400, operation: func(client *Client) error { _, err := client.Create(onfleet.RoutePlanParams{ @@ -404,7 +398,7 @@ func TestClient_ErrorScenarios(t *testing.T) { { name: "get not found", method: "GET", - url: "/route-plans/nonexistent", + url: "/routePlans/nonexistent", statusCode: 404, operation: func(client *Client) error { _, err := client.Get("nonexistent") @@ -414,7 +408,7 @@ func TestClient_ErrorScenarios(t *testing.T) { { name: "update not found", method: "PUT", - url: "/route-plans/nonexistent", + url: "/routePlans/nonexistent", statusCode: 404, operation: func(client *Client) error { _, err := client.Update("nonexistent", onfleet.RoutePlanParams{ @@ -427,7 +421,7 @@ func TestClient_ErrorScenarios(t *testing.T) { { name: "add tasks to completed route plan", method: "PUT", - url: "/route-plans/completed_123", + url: "/routePlans/completed_123", statusCode: 400, operation: func(client *Client) error { _, err := client.AddTasks("completed_123", onfleet.RoutePlanAddTasksParams{ @@ -439,7 +433,7 @@ func TestClient_ErrorScenarios(t *testing.T) { { name: "delete active route plan", method: "DELETE", - url: "/route-plans/active_123", + url: "/routePlans/active_123", statusCode: 409, operation: func(client *Client) error { return client.Delete("active_123") @@ -448,7 +442,7 @@ func TestClient_ErrorScenarios(t *testing.T) { { name: "list unauthorized", method: "GET", - url: "/route-plans/all", + url: "/routePlans/all", statusCode: 401, operation: func(client *Client) error { _, err := client.List(onfleet.RoutePlanListQueryParams{}) @@ -467,7 +461,7 @@ func TestClient_ErrorScenarios(t *testing.T) { Body: testingutil.GetSampleErrorResponse(), }) - client := Plug("test_api_key", nil, "https://api.example.com/route-plans", mockClient.MockCaller) + client := Plug("test_api_key", nil, "https://api.example.com/routePlans", mockClient.MockCaller) err := tt.operation(client) assert.Error(t, err) diff --git a/service/task/client.go b/service/task/client.go index 37dd38c..a0eaba6 100644 --- a/service/task/client.go +++ b/service/task/client.go @@ -228,3 +228,53 @@ func (c *Client) AutoAssignMulti(params onfleet.TaskAutoAssignMultiParams) (onfl ) return autoAssignMulti, err } + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataSet atomically adds or updates metadata fields without affecting other metadata +func (c *Client) MetadataSet(taskId string, metadata ...onfleet.Metadata) (onfleet.Task, error) { + task := onfleet.Task{} + body := map[string]any{ + "metadata": map[string]any{ + "$set": metadata, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{taskId}, + nil, + body, + &task, + ) + return task, err +} + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataPop atomically removes metadata fields without affecting other metadata +func (c *Client) MetadataPop(taskId string, names ...string) (onfleet.Task, error) { + task := onfleet.Task{} + + popArray := make([]map[string]string, len(names)) + for i, name := range names { + popArray[i] = map[string]string{"name": name} + } + + body := map[string]any{ + "metadata": map[string]any{ + "$pop": popArray, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{taskId}, + nil, + body, + &task, + ) + return task, err +} diff --git a/service/task/client_test.go b/service/task/client_test.go index 357f06d..3ce7d03 100644 --- a/service/task/client_test.go +++ b/service/task/client_test.go @@ -560,4 +560,268 @@ func TestClient_DifferentConfigurations(t *testing.T) { mockClient.AssertBasicAuth(tt.apiKey) }) } +} + +func TestClient_List_FilterByState(t *testing.T) { + tests := []struct { + name string + state string + }{ + {"unassigned tasks", "0"}, + {"assigned tasks", "1"}, + {"active tasks", "2"}, + {"completed tasks", "3"}, + {"multiple states", "0,1,2"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedTasks := onfleet.TasksPaginated{ + Tasks: []onfleet.Task{ + testingutil.GetSampleTask(), + }, + LastId: "last_task_123", + } + + mockClient.AddResponse("/tasks", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedTasks, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/tasks", mockClient.MockCaller) + + params := onfleet.TaskListQueryParams{ + From: 1640995200, + To: 1672531199, + State: tt.state, + } + + tasks, err := client.List(params) + + assert.NoError(t, err) + assert.Len(t, tasks.Tasks, 1) + assert.Equal(t, expectedTasks.LastId, tasks.LastId) + + mockClient.AssertRequestMade("GET", "/tasks") + }) + } +} + +func TestClient_List_FilterByContainer(t *testing.T) { + tests := []struct { + name string + containers string + }{ + {"single worker container", "worker_123"}, + {"single team container", "team_456"}, + {"multiple containers", "worker_123,team_456"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedTasks := onfleet.TasksPaginated{ + Tasks: []onfleet.Task{ + testingutil.GetSampleTask(), + }, + LastId: "last_task_789", + } + + mockClient.AddResponse("/tasks", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedTasks, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/tasks", mockClient.MockCaller) + + params := onfleet.TaskListQueryParams{ + From: 1640995200, + To: 1672531199, + Containers: tt.containers, + } + + tasks, err := client.List(params) + + assert.NoError(t, err) + assert.Len(t, tasks.Tasks, 1) + assert.Equal(t, expectedTasks.LastId, tasks.LastId) + + mockClient.AssertRequestMade("GET", "/tasks") + }) + } +} + +func TestClient_MetadataSet(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + // Response after setting the field + expectedTask := testingutil.GetSampleTask() + expectedTask.Metadata = []onfleet.Metadata{ + { + Name: "pnd_order_num", + Type: "string", + Value: "12345", + }, + } + + mockClient.AddResponse("/tasks/task_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedTask, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/tasks", mockClient.MockCaller) + + metadata := []onfleet.Metadata{ + { + Name: "pnd_order_num", + Type: "string", + Value: "12345", + }, + } + + task, err := client.MetadataSet("task_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedTask.ID, task.ID) + + // Verify the field was set + assert.Len(t, task.Metadata, 1) + assert.Equal(t, "pnd_order_num", task.Metadata[0].Name) + assert.Equal(t, "12345", task.Metadata[0].Value) + + mockClient.AssertRequestMade("PUT", "/tasks/task_123") +} + +func TestClient_MetadataSet_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + // Response after setting: existing field preserved, new field added + expectedTask := testingutil.GetSampleTask() + expectedTask.Metadata = []onfleet.Metadata{ + { + Name: "existing_field", + Type: "string", + Value: "existing_value", + }, + { + Name: "new_field", + Type: "string", + Value: "new_value", + }, + } + + mockClient.AddResponse("/tasks/task_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedTask, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/tasks", mockClient.MockCaller) + + // Set only new_field + metadata := []onfleet.Metadata{ + { + Name: "new_field", + Type: "string", + Value: "new_value", + }, + } + + task, err := client.MetadataSet("task_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedTask.ID, task.ID) + + // Verify both fields are present (atomicity - existing_field was preserved) + assert.Len(t, task.Metadata, 2) + + var foundExisting, foundNew bool + for _, m := range task.Metadata { + if m.Name == "existing_field" { + foundExisting = true + assert.Equal(t, "existing_value", m.Value) + } + if m.Name == "new_field" { + foundNew = true + assert.Equal(t, "new_value", m.Value) + } + } + assert.True(t, foundExisting, "existing_field should be preserved") + assert.True(t, foundNew, "new_field should be set") + + mockClient.AssertRequestMade("PUT", "/tasks/task_123") +} + +func TestClient_MetadataPop(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + // Response after popping: field is removed + expectedTask := testingutil.GetSampleTask() + expectedTask.Metadata = []onfleet.Metadata{} + + mockClient.AddResponse("/tasks/task_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedTask, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/tasks", mockClient.MockCaller) + + task, err := client.MetadataPop("task_123", "error") + + assert.NoError(t, err) + assert.Equal(t, expectedTask.ID, task.ID) + + // Verify the field was removed + assert.Len(t, task.Metadata, 0) + for _, m := range task.Metadata { + assert.NotEqual(t, "error", m.Name, "error field should be removed") + } + + mockClient.AssertRequestMade("PUT", "/tasks/task_123") +} + +func TestClient_MetadataPop_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + // Response after popping: field_to_remove is gone, field_to_keep remains + expectedTask := testingutil.GetSampleTask() + expectedTask.Metadata = []onfleet.Metadata{ + { + Name: "field_to_keep", + Type: "string", + Value: "preserved_value", + }, + } + + mockClient.AddResponse("/tasks/task_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedTask, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/tasks", mockClient.MockCaller) + + task, err := client.MetadataPop("task_123", "field_to_remove") + + assert.NoError(t, err) + assert.Equal(t, expectedTask.ID, task.ID) + + // Verify field_to_keep was preserved (atomicity) + assert.Len(t, task.Metadata, 1) + assert.Equal(t, "field_to_keep", task.Metadata[0].Name) + assert.Equal(t, "preserved_value", task.Metadata[0].Value) + + // Verify field_to_remove is not present + for _, m := range task.Metadata { + assert.NotEqual(t, "field_to_remove", m.Name, "field_to_remove should not be present") + } + + mockClient.AssertRequestMade("PUT", "/tasks/task_123") } \ No newline at end of file diff --git a/service/worker/client.go b/service/worker/client.go index da51356..4ae2723 100644 --- a/service/worker/client.go +++ b/service/worker/client.go @@ -213,3 +213,53 @@ func (c *Client) Delete(workerId string) error { ) return err } + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataSet atomically adds or updates metadata fields without affecting other metadata +func (c *Client) MetadataSet(workerId string, metadata ...onfleet.Metadata) (onfleet.Worker, error) { + worker := onfleet.Worker{} + body := map[string]any{ + "metadata": map[string]any{ + "$set": metadata, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{workerId}, + nil, + body, + &worker, + ) + return worker, err +} + +// Reference https://docs.onfleet.com/reference/metadata +// MetadataPop atomically removes metadata fields without affecting other metadata +func (c *Client) MetadataPop(workerId string, names ...string) (onfleet.Worker, error) { + worker := onfleet.Worker{} + + popArray := make([]map[string]string, len(names)) + for i, name := range names { + popArray[i] = map[string]string{"name": name} + } + + body := map[string]any{ + "metadata": map[string]any{ + "$pop": popArray, + }, + } + err := c.call( + c.apiKey, + c.rlHttpClient, + http.MethodPut, + c.url, + []string{workerId}, + nil, + body, + &worker, + ) + return worker, err +} diff --git a/service/worker/client_test.go b/service/worker/client_test.go index a92b3d5..edecdf7 100644 --- a/service/worker/client_test.go +++ b/service/worker/client_test.go @@ -586,4 +586,170 @@ func TestClient_ErrorScenarios(t *testing.T) { assert.Error(t, err) }) } +} + +func TestClient_MetadataSet(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedWorker := testingutil.GetSampleWorker() + expectedWorker.Metadata = []onfleet.Metadata{ + { + Name: "employee_id", + Type: "string", + Value: "EMP123", + }, + } + + mockClient.AddResponse("/workers/worker_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedWorker, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/workers", mockClient.MockCaller) + + metadata := []onfleet.Metadata{ + { + Name: "employee_id", + Type: "string", + Value: "EMP123", + }, + } + + worker, err := client.MetadataSet("worker_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedWorker.ID, worker.ID) + + // Verify the field was set + assert.Len(t, worker.Metadata, 1) + assert.Equal(t, "employee_id", worker.Metadata[0].Name) + assert.Equal(t, "EMP123", worker.Metadata[0].Value) + + mockClient.AssertRequestMade("PUT", "/workers/worker_123") +} + +func TestClient_MetadataSet_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedWorker := testingutil.GetSampleWorker() + expectedWorker.Metadata = []onfleet.Metadata{ + { + Name: "department", + Type: "string", + Value: "delivery", + }, + { + Name: "shift", + Type: "string", + Value: "morning", + }, + } + + mockClient.AddResponse("/workers/worker_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedWorker, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/workers", mockClient.MockCaller) + + // Set only shift field + metadata := []onfleet.Metadata{ + { + Name: "shift", + Type: "string", + Value: "morning", + }, + } + + worker, err := client.MetadataSet("worker_123", metadata...) + + assert.NoError(t, err) + assert.Equal(t, expectedWorker.ID, worker.ID) + + // Verify both fields are present (atomicity - department was preserved) + assert.Len(t, worker.Metadata, 2) + + var foundDepartment, foundShift bool + for _, m := range worker.Metadata { + if m.Name == "department" { + foundDepartment = true + assert.Equal(t, "delivery", m.Value) + } + if m.Name == "shift" { + foundShift = true + assert.Equal(t, "morning", m.Value) + } + } + assert.True(t, foundDepartment, "department field should be preserved") + assert.True(t, foundShift, "shift field should be set") + + mockClient.AssertRequestMade("PUT", "/workers/worker_123") +} + +func TestClient_MetadataPop(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedWorker := testingutil.GetSampleWorker() + expectedWorker.Metadata = []onfleet.Metadata{} + + mockClient.AddResponse("/workers/worker_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedWorker, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/workers", mockClient.MockCaller) + + worker, err := client.MetadataPop("worker_123", "temp_flag") + + assert.NoError(t, err) + assert.Equal(t, expectedWorker.ID, worker.ID) + + // Verify the field was removed + assert.Len(t, worker.Metadata, 0) + for _, m := range worker.Metadata { + assert.NotEqual(t, "temp_flag", m.Name, "temp_flag field should be removed") + } + + mockClient.AssertRequestMade("PUT", "/workers/worker_123") +} + +func TestClient_MetadataPop_Atomicity(t *testing.T) { + mockClient := testingutil.SetupTest(t) + defer testingutil.CleanupTest(t, mockClient) + + expectedWorker := testingutil.GetSampleWorker() + expectedWorker.Metadata = []onfleet.Metadata{ + { + Name: "employee_id", + Type: "string", + Value: "EMP456", + }, + } + + mockClient.AddResponse("/workers/worker_123", testingutil.MockResponse{ + StatusCode: 200, + Body: expectedWorker, + }) + + client := Plug("test_api_key", nil, "https://api.example.com/workers", mockClient.MockCaller) + + worker, err := client.MetadataPop("worker_123", "old_field") + + assert.NoError(t, err) + assert.Equal(t, expectedWorker.ID, worker.ID) + + // Verify employee_id was preserved (atomicity) + assert.Len(t, worker.Metadata, 1) + assert.Equal(t, "employee_id", worker.Metadata[0].Name) + assert.Equal(t, "EMP456", worker.Metadata[0].Value) + + // Verify old_field is not present + for _, m := range worker.Metadata { + assert.NotEqual(t, "old_field", m.Name, "old_field should not be present") + } + + mockClient.AssertRequestMade("PUT", "/workers/worker_123") } \ No newline at end of file diff --git a/task.go b/task.go index 45ae367..01a5f5a 100644 --- a/task.go +++ b/task.go @@ -273,9 +273,11 @@ type TaskListQueryParams struct { From int64 `json:"from,omitempty,string"` To int64 `json:"to,omitempty,string"` // Used for pagination - LastId string `json:"lastId,omitempty"` - Worker string `json:"worker,omitempty"` - CompleteBeforeBefore int64 `json:"completeBeforeBefore,omitempty,string"` - CompleteAfterAfter int64 `json:"completeAfterAfter,omitempty,string"` - Dependencies []string `json:"dependencies,omitempty"` + LastId string `json:"lastId,omitempty"` + State string `json:"state,omitempty"` + Worker string `json:"worker,omitempty"` + CompleteBeforeBefore int64 `json:"completeBeforeBefore,omitempty,string"` + CompleteAfterAfter int64 `json:"completeAfterAfter,omitempty,string"` + Dependencies string `json:"dependencies,omitempty"` + Containers string `json:"containers,omitempty"` }