From 0906b0f0996f811bfcc9837c1ada9ba1c398d560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Larivi=C3=A8re?= Date: Wed, 25 Feb 2026 10:19:05 -0500 Subject: [PATCH] feat(entries)!: use options structs for GetEntries and GetByName - add GetEntriesOptions with optional Name and Path (*string) fields - add GetByNameOptions with optional Path (*string) field - update GetEntries and GetEntriesWithContext on credential and folder services - update GetByName and GetByNameWithContext to accept GetByNameOptions - nil option fields mean the filter is not applied - update tests accordingly --- VERSION | 2 +- entries.go | 17 +++++++++-------- entry_credential.go | 36 ++++++++++++++++++++++-------------- entry_credential_test.go | 18 +++++++++++------- entry_folder.go | 16 ++++++++-------- entry_folder_test.go | 12 ++++++++---- 6 files changed, 59 insertions(+), 42 deletions(-) diff --git a/VERSION b/VERSION index c5523bd..6633391 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.17.0 +0.18.0 diff --git a/entries.go b/entries.go index 51f1692..7bb847d 100644 --- a/entries.go +++ b/entries.go @@ -173,15 +173,16 @@ type entryListRawResponse struct { } // getEntriesOptions contains optional filters for listing entries. -type getEntriesOptions struct { - Name string - Path string +// A nil value means the filter is not applied. +type GetEntriesOptions struct { + Name *string + Path *string } // getEntries returns a list of entries from a vault with optional filters. // Entries with unsupported types are skipped. // This function handles pagination automatically and returns all entries across all pages. -func (c *Client) getEntries(ctx context.Context, vaultId string, opts getEntriesOptions) ([]Entry, error) { +func (c *Client) getEntries(ctx context.Context, vaultId string, opts GetEntriesOptions) ([]Entry, error) { if vaultId == "" { return nil, fmt.Errorf("vaultId is required") } @@ -202,11 +203,11 @@ func (c *Client) getEntries(ctx context.Context, vaultId string, opts getEntries for { q := parsedUrl.Query() - if opts.Name != "" { - q.Set("name", opts.Name) + if opts.Name != nil { + q.Set("name", *opts.Name) } - if opts.Path != "" { - q.Set("path", opts.Path) + if opts.Path != nil { + q.Set("path", *opts.Path) } q.Set("page", fmt.Sprintf("%d", currentPage)) parsedUrl.RawQuery = q.Encode() diff --git a/entry_credential.go b/entry_credential.go index 0b0fac3..954cb6b 100644 --- a/entry_credential.go +++ b/entry_credential.go @@ -452,19 +452,19 @@ func (c *EntryCredentialService) DeleteByIdWithContext(ctx context.Context, vaul return nil } -// GetEntries returns a list of credential entries from a vault with optional name and path filters. +// GetEntries returns a list of credential entries from a vault with optional filters. // Note: The API does not support filtering by entry type, so all entries are fetched and filtered client-side. -func (c *EntryCredentialService) GetEntries(vaultId, name, path string) ([]Entry, error) { - return c.GetEntriesWithContext(context.Background(), vaultId, name, path) +func (c *EntryCredentialService) GetEntries(vaultId string, opts GetEntriesOptions) ([]Entry, error) { + return c.GetEntriesWithContext(context.Background(), vaultId, opts) } -// GetEntriesWithContext returns a list of credential entries from a vault with optional name and path filters. +// GetEntriesWithContext returns a list of credential entries from a vault with optional filters. // The provided context can be used to cancel the request. // Note: The API does not support filtering by entry type, so all entries are fetched and filtered client-side. -func (c *EntryCredentialService) GetEntriesWithContext(ctx context.Context, vaultId, name, path string) ([]Entry, error) { - entries, err := c.client.getEntries(ctx, vaultId, getEntriesOptions{ - Name: name, - Path: path, +func (c *EntryCredentialService) GetEntriesWithContext(ctx context.Context, vaultId string, opts GetEntriesOptions) ([]Entry, error) { + entries, err := c.client.getEntries(ctx, vaultId, GetEntriesOptions{ + Name: opts.Name, + Path: opts.Path, }) if err != nil { return nil, err @@ -481,17 +481,25 @@ func (c *EntryCredentialService) GetEntriesWithContext(ctx context.Context, vaul return credentials, nil } -// GetByName retrieves a single credential entry by name, path, and subType. +// GetByNameOptions contains optional filters for GetByName. +// A nil field means the filter is not applied. +type GetByNameOptions struct { + Path *string +} + +// GetByName retrieves a single credential entry by name, subType, and optional filters. +// Returns ErrEntryNotFound if no match exists. // Returns ErrMultipleEntriesFound if more than one match exists. -func (c *EntryCredentialService) GetByName(vaultId, name, path, subType string) (Entry, error) { - return c.GetByNameWithContext(context.Background(), vaultId, name, path, subType) +func (c *EntryCredentialService) GetByName(vaultId, name, subType string, opts GetByNameOptions) (Entry, error) { + return c.GetByNameWithContext(context.Background(), vaultId, name, subType, opts) } -// GetByNameWithContext retrieves a single credential entry by name, path, and subType. +// GetByNameWithContext retrieves a single credential entry by name, subType, and optional filters. +// Returns ErrEntryNotFound if no match exists. // Returns ErrMultipleEntriesFound if more than one match exists. // The provided context can be used to cancel the request. -func (c *EntryCredentialService) GetByNameWithContext(ctx context.Context, vaultId, name, path, subType string) (Entry, error) { - entries, err := c.GetEntriesWithContext(ctx, vaultId, name, path) +func (c *EntryCredentialService) GetByNameWithContext(ctx context.Context, vaultId, name, subType string, opts GetByNameOptions) (Entry, error) { + entries, err := c.GetEntriesWithContext(ctx, vaultId, GetEntriesOptions{Name: &name, Path: opts.Path}) if err != nil { return Entry{}, err } diff --git a/entry_credential_test.go b/entry_credential_test.go index b738ddf..37e6fb1 100644 --- a/entry_credential_test.go +++ b/entry_credential_test.go @@ -226,16 +226,20 @@ func Test_GetEntries_Filters(t *testing.T) { t.Logf("Created entry %q with ID: %s", entry.Name, id) } + serverName := "Server" + serverBackupName := "Server Backup" + nonExistentName := "Non Existent Entry" + // Test 1: GetEntries with path filter should return all 3 entries t.Log("Test 1: GetEntries with path filter") - entries, err := testClient.Entries.Credential.GetEntries(vault.Id, "", testPath) + entries, err := testClient.Entries.Credential.GetEntries(vault.Id, GetEntriesOptions{Path: &testPath}) require.NoError(t, err, "GetEntries failed") assert.Len(t, entries, 3, "Expected 3 entries with path filter") t.Logf("Found %d entries in path %q", len(entries), testPath) // Test 2: GetEntries with exact name match - should return only "Server", not "Server Backup" or "Server Production" t.Log("Test 2: GetEntries with exact name match") - entries, err = testClient.Entries.Credential.GetEntries(vault.Id, "Server", "") + entries, err = testClient.Entries.Credential.GetEntries(vault.Id, GetEntriesOptions{Name: &serverName}) require.NoError(t, err, "GetEntries with exact name failed") assert.Len(t, entries, 1, "Expected 1 entry with exact name match") if len(entries) > 0 { @@ -245,14 +249,14 @@ func Test_GetEntries_Filters(t *testing.T) { // Test 3: GetEntries with name and path filter t.Log("Test 3: GetEntries with name and path filter") - entries, err = testClient.Entries.Credential.GetEntries(vault.Id, "Server Backup", testPath) + entries, err = testClient.Entries.Credential.GetEntries(vault.Id, GetEntriesOptions{Name: &serverBackupName, Path: &testPath}) require.NoError(t, err, "GetEntries with name and path filter failed") assert.Len(t, entries, 1, "Expected 1 entry with name and path filter") t.Logf("Found %d entry with combined filters", len(entries)) // Test 4: GetEntries with non-existent name should return empty t.Log("Test 4: GetEntries with non-existent name") - entries, err = testClient.Entries.Credential.GetEntries(vault.Id, "Non Existent Entry", testPath) + entries, err = testClient.Entries.Credential.GetEntries(vault.Id, GetEntriesOptions{Name: &nonExistentName, Path: &testPath}) require.NoError(t, err, "GetEntries with non-existent name failed") assert.Empty(t, entries, "Expected 0 entries for non-existent name") t.Logf("Correctly returned %d entries for non-existent name", len(entries)) @@ -284,14 +288,14 @@ func Test_GetByName(t *testing.T) { // Single match t.Log("Test: single match by name") - got, err := testClient.Entries.Credential.GetByName(vault.Id, "MyCredential", testPath, EntryCredentialSubTypeDefault) + got, err := testClient.Entries.Credential.GetByName(vault.Id, "MyCredential", EntryCredentialSubTypeDefault, GetByNameOptions{Path: &testPath}) require.NoError(t, err) assert.Equal(t, id, got.Id) assert.Equal(t, "MyCredential", got.Name) // Not found t.Log("Test: not found") - _, err = testClient.Entries.Credential.GetByName(vault.Id, "NonExistent", testPath, EntryCredentialSubTypeDefault) + _, err = testClient.Entries.Credential.GetByName(vault.Id, "NonExistent", EntryCredentialSubTypeDefault, GetByNameOptions{Path: &testPath}) assert.Error(t, err) assert.False(t, errors.Is(err, ErrMultipleEntriesFound)) @@ -307,6 +311,6 @@ func Test_GetByName(t *testing.T) { }) require.NoError(t, err) - _, err = testClient.Entries.Credential.GetByName(vault.Id, "MyCredential", testPath, EntryCredentialSubTypeDefault) + _, err = testClient.Entries.Credential.GetByName(vault.Id, "MyCredential", EntryCredentialSubTypeDefault, GetByNameOptions{Path: &testPath}) assert.True(t, errors.Is(err, ErrMultipleEntriesFound)) } diff --git a/entry_folder.go b/entry_folder.go index c75dfff..5c084a6 100644 --- a/entry_folder.go +++ b/entry_folder.go @@ -266,19 +266,19 @@ func (c *EntryFolderService) DeleteByIdWithContext(ctx context.Context, vaultId return nil } -// GetEntries returns a list of folder entries from a vault with optional name and path filters. +// GetEntries returns a list of folder entries from a vault with optional filters. // Note: The API does not support filtering by entry type, so all entries are fetched and filtered client-side. -func (c *EntryFolderService) GetEntries(vaultId, name, path string) ([]Entry, error) { - return c.GetEntriesWithContext(context.Background(), vaultId, name, path) +func (c *EntryFolderService) GetEntries(vaultId string, opts GetEntriesOptions) ([]Entry, error) { + return c.GetEntriesWithContext(context.Background(), vaultId, opts) } -// GetEntriesWithContext returns a list of folder entries from a vault with optional name and path filters. +// GetEntriesWithContext returns a list of folder entries from a vault with optional filters. // The provided context can be used to cancel the request. // Note: The API does not support filtering by entry type, so all entries are fetched and filtered client-side. -func (c *EntryFolderService) GetEntriesWithContext(ctx context.Context, vaultId, name, path string) ([]Entry, error) { - entries, err := c.client.getEntries(ctx, vaultId, getEntriesOptions{ - Name: name, - Path: path, +func (c *EntryFolderService) GetEntriesWithContext(ctx context.Context, vaultId string, opts GetEntriesOptions) ([]Entry, error) { + entries, err := c.client.getEntries(ctx, vaultId, GetEntriesOptions{ + Name: opts.Name, + Path: opts.Path, }) if err != nil { return nil, err diff --git a/entry_folder_test.go b/entry_folder_test.go index d0ab913..2967776 100644 --- a/entry_folder_test.go +++ b/entry_folder_test.go @@ -241,10 +241,14 @@ func Test_GetFolderEntries_Filters(t *testing.T) { t.Logf("Created folder entry %q with ID: %s", entry.Name, id) } + databaseName := "Database" + databaseBackupName := "Database Backup" + nonExistentName := "Non Existent Folder" + // Test 1: GetEntries with path filter should return at least our 3 folders // Note: DVLS may auto-create parent folders, so we check for >= 3 t.Log("Test 1: GetEntries with path filter") - entries, err := testClient.Entries.Folder.GetEntries(vault.Id, "", testPath) + entries, err := testClient.Entries.Folder.GetEntries(vault.Id, GetEntriesOptions{Path: &testPath}) require.NoError(t, err, "GetEntries failed") assert.GreaterOrEqual(t, len(entries), 3, "Expected at least 3 folder entries with path filter") @@ -260,7 +264,7 @@ func Test_GetFolderEntries_Filters(t *testing.T) { // Test 2: GetEntries with exact name match - should return only "Database" t.Log("Test 2: GetEntries with exact name match") - entries, err = testClient.Entries.Folder.GetEntries(vault.Id, "Database", "") + entries, err = testClient.Entries.Folder.GetEntries(vault.Id, GetEntriesOptions{Name: &databaseName}) require.NoError(t, err, "GetEntries with exact name failed") assert.Len(t, entries, 1, "Expected 1 folder entry with exact name match") if len(entries) > 0 { @@ -270,14 +274,14 @@ func Test_GetFolderEntries_Filters(t *testing.T) { // Test 3: GetEntries with name and path filter t.Log("Test 3: GetEntries with name and path filter") - entries, err = testClient.Entries.Folder.GetEntries(vault.Id, "Database Backup", testPath) + entries, err = testClient.Entries.Folder.GetEntries(vault.Id, GetEntriesOptions{Name: &databaseBackupName, Path: &testPath}) require.NoError(t, err, "GetEntries with name and path filter failed") assert.Len(t, entries, 1, "Expected 1 folder entry with name and path filter") t.Logf("Found %d folder entry with combined filters", len(entries)) // Test 4: GetEntries with non-existent name should return empty t.Log("Test 4: GetEntries with non-existent name") - entries, err = testClient.Entries.Folder.GetEntries(vault.Id, "Non Existent Folder", testPath) + entries, err = testClient.Entries.Folder.GetEntries(vault.Id, GetEntriesOptions{Name: &nonExistentName, Path: &testPath}) require.NoError(t, err, "GetEntries with non-existent name failed") assert.Empty(t, entries, "Expected 0 folder entries for non-existent name") t.Logf("Correctly returned %d folder entries for non-existent name", len(entries))