add an examples test to selectors (#1590)
## Type of change - [x] 🐹 Trivial/Minor ## Issue(s) * #1224
This commit is contained in:
parent
4d46847f6c
commit
c00b5811e9
223
src/pkg/selectors/example_selectors_test.go
Normal file
223
src/pkg/selectors/example_selectors_test.go
Normal file
@ -0,0 +1,223 @@
|
||||
package selectors_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||
"github.com/alcionai/corso/src/pkg/selectors"
|
||||
)
|
||||
|
||||
// ExampleNewSelector demonstrates creation and distribution of a Selector.
|
||||
func Example_newSelector() {
|
||||
// Selectors should use application-specific constructors.
|
||||
// Generate a selector for backup operations.
|
||||
seb := selectors.NewExchangeBackup()
|
||||
|
||||
// Generate a selector for restore and 'backup details' operations.
|
||||
ser := selectors.NewExchangeRestore()
|
||||
|
||||
// The core selector can be passed around without slicing any
|
||||
// application-specific data.
|
||||
bSel := seb.Selector
|
||||
rSel := ser.Selector
|
||||
|
||||
// And can be re-cast to the application instance again.
|
||||
seb, _ = bSel.ToExchangeBackup()
|
||||
ser, _ = rSel.ToExchangeRestore()
|
||||
|
||||
// Casting the core selector to a different application will
|
||||
// result in an error.
|
||||
if _, err := bSel.ToOneDriveBackup(); err != nil {
|
||||
// this errors, because bSel is an Exchange selector.
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// You can inspect the selector.Service to know which application to use.
|
||||
switch bSel.Service {
|
||||
case selectors.ServiceExchange:
|
||||
//nolint
|
||||
bSel.ToExchangeBackup()
|
||||
case selectors.ServiceOneDrive:
|
||||
//nolint
|
||||
bSel.ToOneDriveBackup()
|
||||
}
|
||||
|
||||
// Output: OneDrive service is not Exchange: wrong selector service type
|
||||
}
|
||||
|
||||
// ExampleIncludeUsers demonstrates how to specify users in a selector.
|
||||
func Example_includeUsers() {
|
||||
seb := selectors.NewExchangeBackup()
|
||||
|
||||
// Selectors specify the data that should be handled
|
||||
// in an operation by specifying the Scope of data.
|
||||
seb.Include(
|
||||
// Selector application instances own the API which describes
|
||||
// the scopes of data that callers may specify.
|
||||
seb.Users([]string{"my-user-id"}),
|
||||
)
|
||||
|
||||
// Selection scopes can be passed around independently.
|
||||
yourUser := seb.Users([]string{"your-user-id"})
|
||||
|
||||
// Most scopes accept multiple values, unioning them into the final selection.
|
||||
otherUsers := seb.Users([]string{"foo-user-id", "bar-user-id"})
|
||||
|
||||
// Multiple scopes can be added at a time.
|
||||
// All calls to Include append those scopes to the current set,
|
||||
// so this addition will also include "my-user-id" from before.
|
||||
seb.Include(
|
||||
yourUser,
|
||||
otherUsers,
|
||||
)
|
||||
|
||||
// Two predefined sets of values exist: any and none.
|
||||
// Any is a wildcard that accepts all values.
|
||||
seb.Users(selectors.Any())
|
||||
// None is the opposite of Any: rejecting all values.
|
||||
seb.Users(selectors.None())
|
||||
}
|
||||
|
||||
// ExampleIncludeFoldersAndItems demonstrates how to select for granular data.
|
||||
func Example_includeFoldersAndItems() {
|
||||
seb := selectors.NewExchangeBackup()
|
||||
|
||||
// Much of the data handled by Corso exists within an established hierarchy.
|
||||
// Resource Owner-level data (such as users) sits at the top, with Folder
|
||||
// structures and individual items below. Higher level scopes will automatically
|
||||
// involve all descendant data in the hierarchy.
|
||||
|
||||
// Users will select all Exchange data owned by the specified user.
|
||||
seb.Users([]string{"foo-user-id"})
|
||||
|
||||
// Lower level Scopes are described on a per-data-type basis. This scope will
|
||||
// select all email in the Inbox folder, for all users in the tenant.
|
||||
seb.MailFolders(selectors.Any(), []string{"Inbox"})
|
||||
|
||||
// Folder-level scopes will, by default, include every folder whose name matches
|
||||
// the provided value, regardless of its position in the hierarchy. If you want
|
||||
// to restrict the scope to a specific path, you can use the PrefixMatch option.
|
||||
// This scope selects all data in /foolder, but will skip /other/foolder.
|
||||
seb.MailFolders(
|
||||
selectors.Any(),
|
||||
[]string{"foolder"},
|
||||
selectors.PrefixMatch())
|
||||
|
||||
// Individual items can be selected, too. You don't have to use the Any()
|
||||
// selection for users and folders when specifying an item, but these ids are
|
||||
// usually unique, and have a low chance of collision.
|
||||
seb.Mails(
|
||||
selectors.Any(),
|
||||
selectors.Any(),
|
||||
[]string{"item-id-1", "item-id-2"},
|
||||
)
|
||||
}
|
||||
|
||||
// ExampleFilters demonstrates selector filters.
|
||||
func Example_filters() {
|
||||
ser := selectors.NewExchangeRestore()
|
||||
|
||||
// In addition to data ownership details (user, folder, itemID), certain operations
|
||||
// like `backup details` and restores allow items to be selected by filtering on
|
||||
// previously gathered metadata.
|
||||
|
||||
// Unlike `Include()`, which will incorporate data so long as any Scope matches,
|
||||
// scopes in the `Filter()` category work as an intersection. Data must pass
|
||||
// every filter to be selected. The following selector will only include emails
|
||||
// received before the data, and with the given subject
|
||||
ser.Filter(
|
||||
// Note that the ReceivedBefore scope only accepts a single string instead of
|
||||
// a slice. Since Filters act as intersections rather than unions, it wouldn't
|
||||
// make much sense to accept multiple values here.
|
||||
ser.MailReceivedBefore("2006-01-02"),
|
||||
// But you can still make a compound filter by adding each scope individually.
|
||||
ser.MailSubject("the answer to life, the universe, and everything"),
|
||||
)
|
||||
|
||||
// Selectors can specify both Filter and Inclusion scopes. Now, not only will the
|
||||
// data only include emails matching the filters above, it will only include emails
|
||||
// owned by this one user.
|
||||
ser.Include(ser.Users([]string{"foo-user-id"}))
|
||||
}
|
||||
|
||||
var (
|
||||
//nolint
|
||||
ctxBG = context.Background()
|
||||
exampleDetails = &details.Details{
|
||||
DetailsModel: details.DetailsModel{
|
||||
Entries: []details.DetailsEntry{
|
||||
{
|
||||
RepoRef: "tID/exchange/uID/email/example/itemID",
|
||||
ShortRef: "xyz",
|
||||
ItemInfo: details.ItemInfo{
|
||||
Exchange: &details.ExchangeInfo{
|
||||
ItemType: details.ExchangeMail,
|
||||
Subject: "the answer to life, the universe, and everything",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// ExampleReduceDetails demonstrates how selectors are used to filter backup details.
|
||||
func Example_reduceDetails() {
|
||||
ser := selectors.NewExchangeRestore()
|
||||
|
||||
// The Reduce() call is where our constructed selectors are applied to the data
|
||||
// from a previous backup record.
|
||||
filteredDetails := ser.Reduce(ctxBG, exampleDetails)
|
||||
|
||||
// We haven't added any scopes to our selector yet, so none of the data is retained.
|
||||
fmt.Println("Before adding scopes:", len(filteredDetails.Entries))
|
||||
|
||||
ser.Include(ser.Mails([]string{"uID"}, []string{"example"}, []string{"xyz"}))
|
||||
ser.Filter(ser.MailSubject("the answer to life"))
|
||||
|
||||
// Now that we've selected our data, we should find a result.
|
||||
filteredDetails = ser.Reduce(ctxBG, exampleDetails)
|
||||
fmt.Println("After adding scopes:", len(filteredDetails.Entries))
|
||||
|
||||
// Output: Before adding scopes: 0
|
||||
// After adding scopes: 1
|
||||
}
|
||||
|
||||
// ExampleScopeMatching demonstrates how to compare data against an individual scope.
|
||||
func Example_scopeMatching() {
|
||||
// Just like sets of backup data can be filtered down using Reduce(), we can check
|
||||
// if an individual bit of data matches our scopes, too.
|
||||
scope := selectors.
|
||||
NewExchangeBackup().
|
||||
Mails(
|
||||
[]string{"id-1"},
|
||||
[]string{"Inbox"},
|
||||
selectors.Any(),
|
||||
)[0]
|
||||
|
||||
// To compare data against a scope, you need to specify the category of data,
|
||||
// and input the value to check.
|
||||
result := scope.Matches(selectors.ExchangeMailFolder, "inbox")
|
||||
fmt.Println("Matches the mail folder 'inbox':", result)
|
||||
|
||||
// Non-matching values will return false.
|
||||
result = scope.Matches(selectors.ExchangeUser, "id-42")
|
||||
fmt.Println("Matches the user by id 'id-42':", result)
|
||||
|
||||
// If you specify a category that doesn't belong to the expected
|
||||
// data type, the result is always false, even if the underlying
|
||||
// comparators match.
|
||||
result = scope.Matches(selectors.ExchangeContact, "id-1")
|
||||
fmt.Println("Matches the contact by id 'id-1':", result)
|
||||
|
||||
// When in doubt, you can check the category of data in the scope
|
||||
// with the Category() method.
|
||||
cat := scope.Category()
|
||||
fmt.Println("Scope Category:", cat)
|
||||
|
||||
// Output: Matches the mail folder 'inbox': true
|
||||
// Matches the user by id 'id-42': false
|
||||
// Matches the contact by id 'id-1': false
|
||||
// Scope Category: ExchangeMail
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user