diff --git a/api/v2beta1/wms_conversion.go b/api/v2beta1/wms_conversion.go index af7bc35..f642d4f 100644 --- a/api/v2beta1/wms_conversion.go +++ b/api/v2beta1/wms_conversion.go @@ -267,54 +267,67 @@ func (v2Service WMSService) GetTopLayer() (*WMSLayer, error) { return nil, errors.New("unable to detect the toplayer of this WMS service") } -func (v2Service WMSService) GetChildLayers(parent WMSLayer) ([]WMSLayer, error) { - children := make([]WMSLayer, 0) - +// MapLayersToV3 +func (v2Service WMSService) MapLayersToV3() pdoknlv3.Layer { + // Creates map of Groups: layers in that group + // and a list of all layers without a group + groupedLayers := map[string][]pdoknlv3.Layer{} + var notGroupedLayers []pdoknlv3.Layer for _, layer := range v2Service.Layers { - if layer.Group != nil && *layer.Group == parent.Name { - children = append(children, layer) + if layer.Group == nil { + notGroupedLayers = append(notGroupedLayers, layer.MapToV3(v2Service)) + } else { + groupedLayers[*layer.Group] = append(groupedLayers[*layer.Group], layer.MapToV3(v2Service)) } } - if len(children) == 0 { - return children, errors.New("no child layers found") + // if a topLayer is defined in the v2 it be the only layer without a group + // and there are other layers that have the topLayer as their group + // so if there is exactly 1 layer without a group + // and the name of that layer exist as a key in the map of Groups: layer in that group + // then that layer must be the topLayer + var topLayer *pdoknlv3.Layer + if len(notGroupedLayers) == 1 { + _, ok := groupedLayers[*notGroupedLayers[0].Name] + if ok { + topLayer = ¬GroupedLayers[0] + } } - return children, nil -} - -// MapLayersToV3 -func (v2Service WMSService) MapLayersToV3() pdoknlv3.Layer { - topLayer, err := v2Service.GetTopLayer() - if err != nil { - panic(err) - } + var middleLayers []pdoknlv3.Layer - var layer pdoknlv3.Layer + // if the topLayer is not defined in the v2 layers + // it needs to be created with defaults from the service + // and in this case the middleLayers are all layers without a group if topLayer == nil { - layer = pdoknlv3.Layer{ - Name: "wms", + topLayer = &pdoknlv3.Layer{ Title: &v2Service.Title, Abstract: &v2Service.Abstract, Keywords: v2Service.Keywords, Layers: &[]pdoknlv3.Layer{}, } + middleLayers = notGroupedLayers + } - var childLayersV3 []pdoknlv3.Layer - for _, childLayer := range v2Service.Layers { - childLayersV3 = append(childLayersV3, childLayer.MapToV3(v2Service)) + // if the topLayer is defined in the v2 layers + // meaning the topLayer has a name at this point + // then the middleLayers are all layers that had the topLayer name as their group + // and the bottomLayers are all layers that had a middleLayer as a group + if topLayer.Name != nil { + for _, layer := range groupedLayers[*topLayer.Name] { + bottomLayers := groupedLayers[*layer.Name] + layer.Layers = &bottomLayers + middleLayers = append(middleLayers, layer) } - layer.Layers = &childLayersV3 - } else { - layer = topLayer.MapToV3(v2Service) } + topLayer.Layers = &middleLayers - return layer + return *topLayer } func (v2Layer WMSLayer) MapToV3(v2Service WMSService) pdoknlv3.Layer { layer := pdoknlv3.Layer{ - Name: v2Layer.Name, + Name: &v2Layer.Name, Title: v2Layer.Title, Abstract: v2Layer.Abstract, Keywords: v2Layer.Keywords, @@ -382,17 +395,6 @@ func (v2Layer WMSLayer) MapToV3(v2Service WMSService) pdoknlv3.Layer { if v2Layer.Data != nil { layer.Data = Pointer(ConvertV2DataToV3(*v2Layer.Data)) - } else { - childLayersV2, err := v2Service.GetChildLayers(v2Layer) - if err != nil { - panic(err) - } - - var childLayersV3 []pdoknlv3.Layer - for _, childLayer := range childLayersV2 { - childLayersV3 = append(childLayersV3, childLayer.MapToV3(v2Service)) - } - layer.Layers = &childLayersV3 } return layer @@ -401,7 +403,7 @@ func (v2Layer WMSLayer) MapToV3(v2Service WMSService) pdoknlv3.Layer { func mapV3LayerToV2Layers(v3Layer pdoknlv3.Layer, parent *pdoknlv3.Layer, serviceEPSG string) []WMSLayer { var layers []WMSLayer - if parent == nil && v3Layer.Name == "wms" { + if parent == nil && *v3Layer.Name == "wms" { // Default top layer, do not include in v2 layers if v3Layer.Layers != nil { for _, childLayer := range *v3Layer.Layers { @@ -410,7 +412,7 @@ func mapV3LayerToV2Layers(v3Layer pdoknlv3.Layer, parent *pdoknlv3.Layer, servic } } else { v2Layer := WMSLayer{ - Name: v3Layer.Name, + Name: *v3Layer.Name, Title: v3Layer.Title, Abstract: v3Layer.Abstract, Keywords: v3Layer.Keywords, @@ -421,7 +423,7 @@ func mapV3LayerToV2Layers(v3Layer pdoknlv3.Layer, parent *pdoknlv3.Layer, servic v2Layer.Visible = PointerVal(v3Layer.Visible, true) if parent != nil { - v2Layer.Group = &parent.Name + v2Layer.Group = parent.Name } if v3Layer.DatasetMetadataURL != nil && v3Layer.DatasetMetadataURL.CSW != nil { diff --git a/api/v3/wms_types.go b/api/v3/wms_types.go index 022588a..564db65 100644 --- a/api/v3/wms_types.go +++ b/api/v3/wms_types.go @@ -88,7 +88,7 @@ type ConfigMapRef struct { } type Layer struct { - Name string `json:"name"` + Name *string `json:"name"` Title *string `json:"title,omitempty"` Abstract *string `json:"abstract,omitempty"` Keywords []string `json:"keywords"` diff --git a/api/v3/wms_types_test.go b/api/v3/wms_types_test.go index 7ed07a4..1abeef1 100644 --- a/api/v3/wms_types_test.go +++ b/api/v3/wms_types_test.go @@ -3,6 +3,7 @@ package v3 import ( "github.com/google/go-cmp/cmp" "github.com/pdok/smooth-operator/model" + controller "github.com/pdok/smooth-operator/pkg/util" "reflect" "testing" ) @@ -58,19 +59,19 @@ func TestLayer_setInheritedBoundingBoxes(t *testing.T) { { name: "setInheritedBoundingBoxes for layer", layer: Layer{ - Name: "toplayer", + Name: controller.Pointer("toplayer"), BoundingBoxes: []WMSBoundingBox{first28992BoundingBox}, Layers: &[]Layer{ { - Name: "grouplayer-1", + Name: controller.Pointer("grouplayer-1"), BoundingBoxes: []WMSBoundingBox{first4326BoundingBox}, Layers: &[]Layer{ { - Name: "datalayer-1", + Name: controller.Pointer("datalayer-1"), BoundingBoxes: []WMSBoundingBox{first4258BoundingBox}, }, { - Name: "datalayer-2", + Name: controller.Pointer("datalayer-2"), BoundingBoxes: []WMSBoundingBox{second28992BoundingBox}, }, }, @@ -127,9 +128,9 @@ func TestLayer_setInheritedBoundingBoxes(t *testing.T) { } func TestLayer_GetParent(t *testing.T) { - childLayer2 := Layer{Name: "childlayer-2"} - childLayer1 := Layer{Name: "childlayer-1", Layers: &[]Layer{childLayer2}} - topLayer := Layer{Name: "toplayer", Layers: &[]Layer{childLayer1}} + childLayer2 := Layer{Name: controller.Pointer("childlayer-2")} + childLayer1 := Layer{Name: controller.Pointer("childlayer-1"), Layers: &[]Layer{childLayer2}} + topLayer := Layer{Name: controller.Pointer("toplayer"), Layers: &[]Layer{childLayer1}} type args struct { candidateLayer *Layer diff --git a/api/v3/wms_validation.go b/api/v3/wms_validation.go index 08fc72d..f75eb86 100644 --- a/api/v3/wms_validation.go +++ b/api/v3/wms_validation.go @@ -95,10 +95,10 @@ func validateWMS(wms *WMS, warnings *[]string, reasons *[]string) { wms.Spec.Service.Layer.setInheritedBoundingBoxes() for _, layer := range wms.Spec.Service.Layer.GetAllLayers() { var layerReasons []string - if slices.Contains(names, layer.Name) { - *reasons = append(*reasons, fmt.Sprintf("layer names must be unique, layer.name '%s' is duplicated", layer.Name)) + if slices.Contains(names, *layer.Name) { + *reasons = append(*reasons, fmt.Sprintf("layer names must be unique, layer.name '%s' is duplicated", *layer.Name)) } - names = append(names, layer.Name) + names = append(names, *layer.Name) if service.Mapfile != nil && layer.BoundingBoxes != nil { *warnings = append(*warnings, sharedValidation.FormatValidationWarning("layer.boundingBoxes is not used when service.mapfile is configured", wms.GroupVersionKind(), wms.GetName())) } @@ -154,7 +154,7 @@ func validateWMS(wms *WMS, warnings *[]string, reasons *[]string) { } } if !rewriteGroupToDataLayers && validateChildStyleNameEqual { - equalStylesNames, ok := equalChildStyleNames[layer.Name] + equalStylesNames, ok := equalChildStyleNames[*layer.Name] if ok { for _, styleName := range equalStylesNames { layerReasons = append(layerReasons, fmt.Sprintf("invalid style: '%s': style.name from parent layer must not be set on a child layer", styleName)) @@ -188,7 +188,7 @@ func validateWMS(wms *WMS, warnings *[]string, reasons *[]string) { } } if len(layerReasons) != 0 { - *reasons = append(*reasons, fmt.Sprintf("%s '%s' is invalid: ", layerType, layer.Name)+strings.Join(layerReasons, ", ")) + *reasons = append(*reasons, fmt.Sprintf("%s '%s' is invalid: ", layerType, *layer.Name)+strings.Join(layerReasons, ", ")) } } @@ -212,7 +212,7 @@ func findEqualChildStyleNames(layer *Layer, equalStyleNames *map[string][]string } } if len(equalStyles) > 0 { - equalChildStyleNames[childLayer.Name] = equalStyles + equalChildStyleNames[*childLayer.Name] = equalStyles } findEqualChildStyleNames(&childLayer, equalStyleNames) } diff --git a/api/v3/wms_validation_test.go b/api/v3/wms_validation_test.go index f73f367..13f4856 100644 --- a/api/v3/wms_validation_test.go +++ b/api/v3/wms_validation_test.go @@ -1,6 +1,7 @@ package v3 import ( + controller "github.com/pdok/smooth-operator/pkg/util" "reflect" "testing" ) @@ -19,21 +20,21 @@ func Test_getEqualChildStyleNames(t *testing.T) { name: "Test equal style names", args: args{ layer: &Layer{ - Name: "toplayer", + Name: controller.Pointer("toplayer"), Styles: []Style{ {Name: "stylename-1"}, {Name: "stylename-2"}, }, Layers: &[]Layer{ { - Name: "childlayer-1", + Name: controller.Pointer("childlayer-1"), Styles: []Style{ {Name: "stylename-2"}, {Name: "stylename-3"}, }, Layers: &[]Layer{ { - Name: "childlayer-2", + Name: controller.Pointer("childlayer-2"), Styles: []Style{ {Name: "stylename-3"}, {Name: "stylename-4"}, @@ -54,21 +55,21 @@ func Test_getEqualChildStyleNames(t *testing.T) { name: "Test no equal style names", args: args{ layer: &Layer{ - Name: "toplayer", + Name: controller.Pointer("toplayer"), Styles: []Style{ {Name: "stylename-1"}, {Name: "stylename-2"}, }, Layers: &[]Layer{ { - Name: "childlayer-1", + Name: controller.Pointer("childlayer-1"), Styles: []Style{ {Name: "stylename-3"}, {Name: "stylename-4"}, }, Layers: &[]Layer{ { - Name: "childlayer-2", + Name: controller.Pointer("childlayer-2"), Styles: []Style{ {Name: "stylename-5"}, {Name: "stylename-6"}, diff --git a/internal/controller/blobdownload/blob_download.go b/internal/controller/blobdownload/blob_download.go index c9fcce2..7c13146 100644 --- a/internal/controller/blobdownload/blob_download.go +++ b/internal/controller/blobdownload/blob_download.go @@ -170,14 +170,14 @@ func downloadStylingAssets(sb *strings.Builder, wms *pdoknlv3.WMS) error { func downloadLegends(sb *strings.Builder, wms *pdoknlv3.WMS) error { for _, layer := range wms.GetAllLayersWithLegend() { - writeLine(sb, "mkdir -p %s/%s;", legendPath, layer.Name) + writeLine(sb, "mkdir -p %s/%s;", legendPath, *layer.Name) for _, style := range layer.Styles { - writeLine(sb, "rclone copyto blobs:/%s %s/%s/%s.png || exit 1;", style.Legend.BlobKey, legendPath, layer.Name, style.Name) + writeLine(sb, "rclone copyto blobs:/%s %s/%s/%s.png || exit 1;", style.Legend.BlobKey, legendPath, *layer.Name, style.Name) fileName, err := getFilenameFromBlobKey(style.Legend.BlobKey) if err != nil { return err } - writeLine(sb, "Copied legend %s to %s/%s/%s.png;", fileName, legendPath, layer.Name, style.Name) + writeLine(sb, "Copied legend %s to %s/%s/%s.png;", fileName, legendPath, *layer.Name, style.Name) } } writeLine(sb, "chown -R 999:999 %s", legendPath) diff --git a/internal/controller/blobdownload/blob_download_test.go b/internal/controller/blobdownload/blob_download_test.go index 2745f3f..08bfe17 100644 --- a/internal/controller/blobdownload/blob_download_test.go +++ b/internal/controller/blobdownload/blob_download_test.go @@ -145,7 +145,7 @@ func TestGetArgsForWMS(t *testing.T) { Service: v3.WMSService{ Title: "wms-gpkg-service-title", Layer: v3.Layer{ - Name: "wms-gpkg-layer-name", + Name: smoothoperatorutils.Pointer("wms-gpkg-layer-name"), Title: smoothoperatorutils.Pointer("wms-gpkg-layer-title"), Styles: []v3.Style{ { @@ -156,7 +156,7 @@ func TestGetArgsForWMS(t *testing.T) { }, Layers: &[]v3.Layer{ { - Name: "wms-gpkg-layer-1-name", + Name: smoothoperatorutils.Pointer("wms-gpkg-layer-1-name"), Title: smoothoperatorutils.Pointer("wms-gpkg-layer-1-title"), Styles: []v3.Style{ { @@ -177,7 +177,7 @@ func TestGetArgsForWMS(t *testing.T) { }, }, { - Name: "wms-gpkg-layer-2-name", + Name: smoothoperatorutils.Pointer("wms-gpkg-layer-2-name"), Title: smoothoperatorutils.Pointer("wms-gpkg-layer-2-title"), Styles: []v3.Style{ { @@ -222,11 +222,11 @@ func TestGetArgsForWMS(t *testing.T) { Service: v3.WMSService{ Title: "wms-tif-service-title", Layer: v3.Layer{ - Name: "wms-tif-layer-name", + Name: smoothoperatorutils.Pointer("wms-tif-layer-name"), Title: smoothoperatorutils.Pointer("wms-tif-layer-title"), Layers: &[]v3.Layer{ { - Name: "wms-tif-layer-1-name", + Name: smoothoperatorutils.Pointer("wms-tif-layer-1-name"), Title: smoothoperatorutils.Pointer("wms-tif-layer-1-title"), Styles: []v3.Style{ { @@ -244,7 +244,7 @@ func TestGetArgsForWMS(t *testing.T) { }, }, { - Name: "wms-tif-layer-2-name", + Name: smoothoperatorutils.Pointer("wms-tif-layer-2-name"), Title: smoothoperatorutils.Pointer("wms-tif-layer-2-title"), Styles: []v3.Style{ { diff --git a/internal/controller/capabilitiesgenerator/mapper.go b/internal/controller/capabilitiesgenerator/mapper.go index a2994ce..8660c3a 100644 --- a/internal/controller/capabilitiesgenerator/mapper.go +++ b/internal/controller/capabilitiesgenerator/mapper.go @@ -588,7 +588,7 @@ func getLayers(wms *pdoknlv3.WMS, canonicalUrl string) []wms130.Layer { nestedLayer := wms130.Layer{ Queryable: asPtr(1), Opaque: nil, - Name: &layer.Name, + Name: layer.Name, Title: pointerValOrDefault(layer.Title, ""), Abstract: layer.Abstract, KeywordList: &wms130.Keywords{ @@ -621,7 +621,7 @@ func getLayers(wms *pdoknlv3.WMS, canonicalUrl string) []wms130.Layer { OnlineResource: wms130.OnlineResource{ Xlink: nil, Type: asPtr("simple"), - Href: asPtr(canonicalUrl + "/legend/" + layer.Name + "/" + layer.Name + ".png"), + Href: asPtr(canonicalUrl + "/legend/" + *layer.Name + "/" + style.Name + ".png"), }, }, StyleSheetURL: nil, diff --git a/internal/controller/featureinfogenerator/featureinfo_generator_test.go b/internal/controller/featureinfogenerator/featureinfo_generator_test.go index 8dee78a..4df5a13 100644 --- a/internal/controller/featureinfogenerator/featureinfo_generator_test.go +++ b/internal/controller/featureinfogenerator/featureinfo_generator_test.go @@ -78,13 +78,13 @@ func TestGetInput(t *testing.T) { }, Service: pdoknlv3.WMSService{ Layer: pdoknlv3.Layer{ - Name: "top-layer-name", + Name: smoothoperatorutils.Pointer("top-layer-name"), Layers: &[]pdoknlv3.Layer{ { - Name: "group-layer-name", + Name: smoothoperatorutils.Pointer("group-layer-name"), Layers: &[]pdoknlv3.Layer{ { - Name: "gpkg-layer-name", + Name: smoothoperatorutils.Pointer("gpkg-layer-name"), Data: &pdoknlv3.Data{ Gpkg: &pdoknlv3.Gpkg{ Columns: []pdoknlv3.Column{ @@ -95,7 +95,7 @@ func TestGetInput(t *testing.T) { }, }, { - Name: "postgis-layer-name", + Name: smoothoperatorutils.Pointer("postgis-layer-name"), Data: &pdoknlv3.Data{ Postgis: &pdoknlv3.Postgis{ Columns: []pdoknlv3.Column{ @@ -106,7 +106,7 @@ func TestGetInput(t *testing.T) { }, }, { - Name: "tif-layer-name", + Name: smoothoperatorutils.Pointer("tif-layer-name"), Data: &pdoknlv3.Data{ TIF: &pdoknlv3.TIF{ GetFeatureInfoIncludesClass: smoothoperatorutils.Pointer(true), diff --git a/internal/controller/featureinfogenerator/mapper.go b/internal/controller/featureinfogenerator/mapper.go index 513df6e..89624fd 100644 --- a/internal/controller/featureinfogenerator/mapper.go +++ b/internal/controller/featureinfogenerator/mapper.go @@ -22,13 +22,13 @@ func MapWMSToFeatureinfoGeneratorInput(wms *pdoknlv3.WMS) (*featureinfo.Scheme, continue } l := featureinfo.Layer{ - Name: layer.Name, + Name: *layer.Name, Properties: getProperties(&layer), } parentLayer := layer.GetParent(&wms.Spec.Service.Layer) if parentLayer != nil && parentLayer.IsGroupLayer() { - l.GroupName = parentLayer.Name + l.GroupName = *parentLayer.Name } input.Layers = append(input.Layers, l) diff --git a/internal/controller/legendgenerator/mapper.go b/internal/controller/legendgenerator/mapper.go index 29867cb..a461b28 100644 --- a/internal/controller/legendgenerator/mapper.go +++ b/internal/controller/legendgenerator/mapper.go @@ -60,7 +60,7 @@ func processLayer(layer *pdoknlv3.Layer, legendReferences *[]LegendReference) { for _, style := range layer.Styles { if style.Legend == nil { *legendReferences = append(*legendReferences, LegendReference{ - Layer: layer.Name, + Layer: *layer.Name, Style: style.Name, }) } @@ -91,7 +91,7 @@ func addLegendFixerConfig(wms *pdoknlv3.WMS, data map[string]string) { for _, style := range layer.Styles { if topLevelStyleNames[style.Name] && style.Legend == nil { legendReferences = append(legendReferences, LegendReference{ - Layer: layer.Name, + Layer: *layer.Name, Style: style.Name, }) } @@ -108,18 +108,18 @@ func addLegendFixerConfig(wms *pdoknlv3.WMS, data map[string]string) { groupLayers := make(map[string][]string) - if topLayer.IsGroupLayer() { + if topLayer.IsGroupLayer() && topLayer.Name != nil { layerName := topLayer.Name targetArray := make([]string, 0) getAllNestedNonGroupLayerNames(&topLayer, &targetArray) - groupLayers[layerName] = targetArray + groupLayers[*layerName] = targetArray for _, subLayer := range *topLayer.Layers { if subLayer.IsGroupLayer() { layerName = subLayer.Name targetArray = make([]string, 0) getAllNestedNonGroupLayerNames(&subLayer, &targetArray) - groupLayers[layerName] = targetArray + groupLayers[*layerName] = targetArray } } } @@ -134,7 +134,7 @@ func getAllNestedNonGroupLayerNames(layer *pdoknlv3.Layer, target *[]string) { if subLayer.IsGroupLayer() { getAllNestedNonGroupLayerNames(&subLayer, target) } else { - *target = append(*target, subLayer.Name) + *target = append(*target, *subLayer.Name) } } } diff --git a/internal/controller/mapserver/deployment.go b/internal/controller/mapserver/deployment.go index 9cac2be..61ff318 100644 --- a/internal/controller/mapserver/deployment.go +++ b/internal/controller/mapserver/deployment.go @@ -306,7 +306,7 @@ func getReadinessProbeForWMS(wms *pdoknlv3.WMS) (*v1.Probe, error) { firstDataLayerName := "" for _, layer := range wms.Spec.Service.Layer.GetAllLayers() { if layer.IsDataLayer() { - firstDataLayerName = layer.Name + firstDataLayerName = *layer.Name break } } @@ -337,7 +337,10 @@ func getStartupProbeForWFS(wfs *pdoknlv3.WFS) (*v1.Probe, error) { func getStartupProbeForWMS(wms *pdoknlv3.WMS) (*v1.Probe, error) { var layerNames []string for _, layer := range wms.Spec.Service.Layer.GetAllLayers() { - layerNames = append(layerNames, layer.Name) + if layer.Name != nil { + layerNames = append(layerNames, *layer.Name) + } + } if len(layerNames) == 0 { return nil, errors.New("cannot get startup probe for WMS, layers could not be found") diff --git a/internal/controller/ogcwebserviceproxy/ogc_webservice_proxy.go b/internal/controller/ogcwebserviceproxy/ogc_webservice_proxy.go index d6aa039..b27b210 100644 --- a/internal/controller/ogcwebserviceproxy/ogc_webservice_proxy.go +++ b/internal/controller/ogcwebserviceproxy/ogc_webservice_proxy.go @@ -70,11 +70,11 @@ func MapWMSToOgcWebserviceProxyConfig(wms *pdoknlv3.WMS) (config Config, err err var dataLayers []string for _, childLayer := range *layer.Layers { if childLayer.IsDataLayer() { - dataLayers = append(dataLayers, childLayer.Name) + dataLayers = append(dataLayers, *childLayer.Name) } } if len(dataLayers) > 0 { - config.GroupLayers[layer.Name] = dataLayers + config.GroupLayers[*layer.Name] = dataLayers } } } diff --git a/internal/controller/ogcwebserviceproxy/ogc_webservice_proxy_test.go b/internal/controller/ogcwebserviceproxy/ogc_webservice_proxy_test.go index c50127f..28a1771 100644 --- a/internal/controller/ogcwebserviceproxy/ogc_webservice_proxy_test.go +++ b/internal/controller/ogcwebserviceproxy/ogc_webservice_proxy_test.go @@ -2,6 +2,7 @@ package ogcwebserviceproxy import ( pdoknlv3 "github.com/pdok/mapserver-operator/api/v3" + controller "github.com/pdok/smooth-operator/pkg/util" "testing" ) @@ -31,30 +32,30 @@ func TestGetConfig(t *testing.T) { Spec: pdoknlv3.WMSSpec{ Service: pdoknlv3.WMSService{ Layer: pdoknlv3.Layer{ - Name: "toplayer", + Name: controller.Pointer("toplayer"), Layers: &[]pdoknlv3.Layer{ { - Name: "grouplayer-1", + Name: controller.Pointer("grouplayer-1"), Layers: &[]pdoknlv3.Layer{ { - Name: "datalayer-1", + Name: controller.Pointer("datalayer-1"), Data: &pdoknlv3.Data{Gpkg: &pdoknlv3.Gpkg{BlobKey: "blob-1"}}, }, { - Name: "datalayer-2", + Name: controller.Pointer("datalayer-2"), Data: &pdoknlv3.Data{Gpkg: &pdoknlv3.Gpkg{BlobKey: "blob-2"}}, }, }, }, { - Name: "grouplayer-2", + Name: controller.Pointer("grouplayer-2"), Layers: &[]pdoknlv3.Layer{ { - Name: "datalayer-3", + Name: controller.Pointer("datalayer-3"), Data: &pdoknlv3.Data{Gpkg: &pdoknlv3.Gpkg{BlobKey: "blob-3"}}, }, { - Name: "datalayer-4", + Name: controller.Pointer("datalayer-4"), Data: &pdoknlv3.Data{Gpkg: &pdoknlv3.Gpkg{BlobKey: "blob-4"}}, }, },