Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add optional "parent" field to Device objects. #887

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions clients/http/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ func (dc DeviceClient) AllDevices(ctx context.Context, labels []string, offset i
return res, nil
}

func (dc DeviceClient) AllDevicesWithChildren(ctx context.Context, parent string, maxLevels uint, labels []string, offset int, limit int) (res responses.MultiDevicesResponse, err errors.EdgeX) {
requestParams := url.Values{}
if len(labels) > 0 {
requestParams.Set(common.Labels, strings.Join(labels, common.CommaSeparator))
}
requestParams.Set(common.DescendantsOf, parent)
requestParams.Set(common.MaxLevels, strconv.FormatUint(uint64(maxLevels), 10))
requestParams.Set(common.Offset, strconv.Itoa(offset))
requestParams.Set(common.Limit, strconv.Itoa(limit))
err = utils.GetRequest(ctx, &res, dc.baseUrl, common.ApiAllDeviceRoute, requestParams, dc.authInjector)
if err != nil {
return res, errors.NewCommonEdgeXWrapper(err)
}
return res, nil
}

func (dc DeviceClient) DeviceNameExists(ctx context.Context, name string) (res dtoCommon.BaseResponse, err errors.EdgeX) {
path := common.NewPathBuilder().EnableNameFieldEscape(dc.enableNameFieldEscape).
SetPath(common.ApiDeviceRoute).SetPath(common.Check).SetPath(common.Name).SetNameFieldPath(name).BuildPath()
Expand Down
9 changes: 9 additions & 0 deletions clients/http/device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,12 @@ func TestQueryDevicesByServiceName(t *testing.T) {
require.NoError(t, err)
require.IsType(t, responses.MultiDevicesResponse{}, res)
}

func TestQueryDeviceTree(t *testing.T) {
ts := newTestServer(http.MethodGet, common.ApiAllDeviceRoute, responses.MultiDevicesResponse{})
defer ts.Close()
client := NewDeviceClient(ts.URL, NewNullAuthenticationInjector(), false)
res, err := client.AllDevicesWithChildren(context.Background(), "MyRoot", 3, []string{"label1", "label2"}, 1, 10)
require.NoError(t, err)
require.IsType(t, responses.MultiDevicesResponse{}, res)
}
7 changes: 7 additions & 0 deletions clients/interfaces/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ type DeviceClient interface {
// offset: The number of items to skip before starting to collect the result set. Default is 0.
// limit: The number of items to return. Specify -1 will return all remaining items after offset. The maximum will be the MaxResultCount as defined in the configuration of service. Default is 20.
AllDevices(ctx context.Context, labels []string, offset int, limit int) (responses.MultiDevicesResponse, errors.EdgeX)
// AllDevicesWithChildren returns all devices who have parent, grandparent, etc. of the
// given device name. Devices can also be filtered by labels.
// Device tree is descended at most maxLevels. If maxLevels is 0, there is no limit.
// The result can be limited in a certain range by specifying the offset and limit parameters.
// offset: The number of items to skip before starting to collect the result set. Default is 0.
// limit: The number of items to return. Specify -1 will return all remaining items after offset. The maximum will be the MaxResultCount as defined in the configuration of service. Default is 20.
AllDevicesWithChildren(ctx context.Context, parent string, maxLevels uint, labels []string, offset int, limit int) (responses.MultiDevicesResponse, errors.EdgeX)
// DeviceNameExists checks whether the device exists.
DeviceNameExists(ctx context.Context, name string) (common.BaseResponse, errors.EdgeX)
// DeviceByName returns a device by device name.
Expand Down
113 changes: 99 additions & 14 deletions clients/interfaces/mocks/DeviceClient.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 12 additions & 10 deletions common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,18 @@ const (
Key = "key"
ServiceId = "serviceId"

Offset = "offset" //query string to specify the number of items to skip before starting to collect the result set.
Limit = "limit" //query string to specify the numbers of items to return
Labels = "labels" //query string to specify associated user-defined labels for querying a given object. More than one label may be specified via a comma-delimited list
PushEvent = "ds-pushevent" //query string to specify if an event should be pushed to the EdgeX system
ReturnEvent = "ds-returnevent" //query string to specify if an event should be returned from device service
RegexCommand = "ds-regexcmd" //query string to specify if the command name is in regular expression format
Flatten = "flatten" //query string to specify if the request json payload should be flattened to update multiple keys with the same prefix
KeyOnly = "keyOnly" //query string to specify if the response will only return the keys of the specified query key prefix, without values and metadata
Plaintext = "plaintext" //query string to specify if the response will return the stored plain text value of the key(s) without any encoding
Deregistered = "deregistered" //query string to specify if the response will return the registries of deregistered services
Offset = "offset" //query string to specify the number of items to skip before starting to collect the result set.
Limit = "limit" //query string to specify the numbers of items to return
Labels = "labels" //query string to specify associated user-defined labels for querying a given object. More than one label may be specified via a comma-delimited list
PushEvent = "ds-pushevent" //query string to specify if an event should be pushed to the EdgeX system
ReturnEvent = "ds-returnevent" //query string to specify if an event should be returned from device service
RegexCommand = "ds-regexcmd" //query string to specify if the command name is in regular expression format
DescendantsOf = "descendantsOf" //Limit returned devices to those who have parent, grandparent, etc. of the given device name
MaxLevels = "maxLevels" //Limit returned devices to this many levels below 'descendantsOf' (0=unlimited)
Flatten = "flatten" //query string to specify if the request json payload should be flattened to update multiple keys with the same prefix
KeyOnly = "keyOnly" //query string to specify if the response will only return the keys of the specified query key prefix, without values and metadata
Plaintext = "plaintext" //query string to specify if the response will return the stored plain text value of the key(s) without any encoding
Deregistered = "deregistered" //query string to specify if the response will return the registries of deregistered services
)

// Constants related to the default value of query strings in the v3 service APIs
Expand Down
5 changes: 5 additions & 0 deletions dtos/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Device struct {
DBTimestamp `json:",inline"`
Id string `json:"id,omitempty" yaml:"id,omitempty" validate:"omitempty,uuid"`
Name string `json:"name" yaml:"name" validate:"required,edgex-dto-none-empty-string"`
Parent string `json:"parent,omitempty" yaml:"parent,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
AdminState string `json:"adminState" yaml:"adminState" validate:"oneof='LOCKED' 'UNLOCKED'"`
OperatingState string `json:"operatingState" yaml:"operatingState" validate:"oneof='UP' 'DOWN' 'UNKNOWN'"`
Expand All @@ -29,6 +30,7 @@ type Device struct {
type UpdateDevice struct {
Id *string `json:"id" validate:"required_without=Name,edgex-dto-uuid"`
Name *string `json:"name" validate:"required_without=Id,edgex-dto-none-empty-string"`
Parent *string `json:"parent,omitempty" yaml:"parent,omitempty"`
Description *string `json:"description" validate:"omitempty"`
AdminState *string `json:"adminState" validate:"omitempty,oneof='LOCKED' 'UNLOCKED'"`
OperatingState *string `json:"operatingState" validate:"omitempty,oneof='UP' 'DOWN' 'UNKNOWN'"`
Expand All @@ -47,6 +49,7 @@ func ToDeviceModel(dto Device) models.Device {
var d models.Device
d.Id = dto.Id
d.Name = dto.Name
d.Parent = dto.Parent
d.Description = dto.Description
d.ServiceName = dto.ServiceName
d.ProfileName = dto.ProfileName
Expand All @@ -67,6 +70,7 @@ func FromDeviceModelToDTO(d models.Device) Device {
dto.DBTimestamp = DBTimestamp(d.DBTimestamp)
dto.Id = d.Id
dto.Name = d.Name
dto.Parent = d.Parent
dto.Description = d.Description
dto.ServiceName = d.ServiceName
dto.ProfileName = d.ProfileName
Expand All @@ -88,6 +92,7 @@ func FromDeviceModelToUpdateDTO(d models.Device) UpdateDevice {
dto := UpdateDevice{
Id: &d.Id,
Name: &d.Name,
Parent: &d.Parent,
Description: &d.Description,
AdminState: &adminState,
OperatingState: &operatingState,
Expand Down
Loading