func()

in internal/kibana/data_view/models.go [15:168]


func (model *dataViewModel) populateFromAPI(ctx context.Context, data *kbapi.DataViewsDataViewResponseObject, spaceID string) diag.Diagnostics {
	if data == nil {
		return nil
	}

	var diags diag.Diagnostics

	resourceID := clients.CompositeId{
		ClusterId:  model.SpaceID.ValueString(),
		ResourceId: *data.DataView.Id,
	}

	// An existing null map should should be semantically equal to an empty map.
	semanticEqualEmptyMap := func(existing types.Map, incoming types.Map) types.Map {
		if !utils.IsKnown(existing) && len(incoming.Elements()) == 0 {
			return types.MapNull(incoming.ElementType(ctx))
		}
		return incoming
	}

	// An existing null slice should be semantically equal to an empty slice.
	semanticEqualEmptySlice := func(existing types.List, incoming types.List) types.List {
		if !utils.IsKnown(existing) && len(incoming.Elements()) == 0 {
			return types.ListNull(incoming.ElementType(ctx))
		}
		return incoming
	}

	handleNamespaces := func(existingList types.List, incoming []string) types.List {
		p := path.Root("data_view").AtName("namespaces")
		existing := utils.ListTypeToSlice_String(ctx, existingList, p, &diags)

		// incoming is typically [] except in <= v8.8.2 where it is omitted
		if incoming == nil {
			if existing == nil {
				return types.ListNull(types.StringType)
			} else {
				return existingList
			}
		}

		// An existing null slice should be semantically equal to a slice only containing the current space ID.
		if existing == nil && len(incoming) == 1 && incoming[0] == model.SpaceID.ValueString() {
			return types.ListNull(types.StringType)
		}

		// Keep the original ordering if equal but unordered
		// The API response is ordered by name.
		// Additionally, allow for the response containing an extra namespace that is the current SpaceID
		// If the SpaceID is not included in the `namespaces` field, when trying to GET the object it will 404
		if (len(existing) == len(incoming)) || (len(existing) == len(incoming)-1) {
			useExisting := true
			for _, ns := range existing {
				if !slices.Contains(incoming, ns) {
					if ns == spaceID {
						continue
					}
					useExisting = false
					break
				}
			}
			if useExisting {
				return existingList
			}
		}

		return utils.SliceToListType_String(ctx, incoming, p, &diags)
	}

	model.ID = types.StringValue(resourceID.String())
	model.DataView = utils.StructToObjectType(ctx, data.DataView, getDataViewAttrTypes(), path.Root("data_view"), &diags,
		func(item kbapi.DataViewsDataViewResponseObjectInner, meta utils.ObjectMeta) innerModel {
			dvInner := utils.ObjectTypeAs[innerModel](ctx, model.DataView, meta.Path, &diags)
			if dvInner == nil {
				dvInner = &innerModel{}
			}

			return innerModel{
				Title:         types.StringPointerValue(item.Title),
				Name:          types.StringPointerValue(item.Name),
				ID:            types.StringPointerValue(item.Id),
				TimeFieldName: types.StringPointerValue(item.TimeFieldName),
				SourceFilters: semanticEqualEmptySlice(dvInner.SourceFilters,
					utils.SliceToListType(ctx, utils.Deref(item.SourceFilters), types.StringType, meta.Path.AtName("source_filters"), &diags,
						func(item kbapi.DataViewsSourcefilterItem, meta utils.ListMeta) string {
							return item.Value
						})),
				FieldAttributes: semanticEqualEmptyMap(dvInner.FieldAttributes,
					utils.MapToMapType(ctx, utils.Deref(item.FieldAttrs), getFieldAttrElemType(), meta.Path.AtName("field_attrs"), &diags,
						func(item kbapi.DataViewsFieldattrs, meta utils.MapMeta) fieldAttrModel {
							return fieldAttrModel{
								CustomLabel: types.StringPointerValue(item.CustomLabel),
								Count:       types.Int64PointerValue(utils.Itol(item.Count)),
							}
						})),
				RuntimeFieldMap: semanticEqualEmptyMap(dvInner.RuntimeFieldMap,
					utils.MapToMapType(ctx, utils.Deref(item.RuntimeFieldMap), getRuntimeFieldMapElemType(), meta.Path.AtName("runtime_field_map"), &diags,
						func(item kbapi.DataViewsRuntimefieldmap, meta utils.MapMeta) runtimeFieldModel {
							return runtimeFieldModel{
								Type:         types.StringValue(item.Type),
								ScriptSource: types.StringPointerValue(item.Script.Source),
							}
						})),
				FieldFormats: semanticEqualEmptyMap(dvInner.FieldFormats,
					utils.MapToMapType(ctx, utils.Deref(item.FieldFormats), getFieldFormatElemType(), meta.Path.AtName("field_formats"), &diags,
						func(item kbapi.DataViewsFieldformat, meta utils.MapMeta) fieldFormatModel {
							return fieldFormatModel{
								ID: types.StringPointerValue(item.Id),
								Params: utils.StructToObjectType(ctx, item.Params, getFieldFormatParamsAttrTypes(), meta.Path.AtName("params"), &diags,
									func(item kbapi.DataViewsFieldformatParams, meta utils.ObjectMeta) fieldFormatParamsModel {
										return fieldFormatParamsModel{
											Pattern:                types.StringPointerValue(item.Pattern),
											UrlTemplate:            types.StringPointerValue(item.UrlTemplate),
											LabelTemplate:          types.StringPointerValue(item.LabelTemplate),
											InputFormat:            types.StringPointerValue(item.InputFormat),
											OutputFormat:           types.StringPointerValue(item.OutputFormat),
											OutputPrecision:        types.Int64PointerValue(utils.Itol(item.OutputPrecision)),
											IncludeSpaceWithSuffix: types.BoolPointerValue(item.IncludeSpaceWithSuffix),
											UseShortSuffix:         types.BoolPointerValue(item.UseShortSuffix),
											Timezone:               types.StringPointerValue(item.Timezone),
											FieldType:              types.StringPointerValue(item.FieldType),
											Colors: utils.SliceToListType(ctx, utils.Deref(item.Colors), getFieldFormatParamsColorsElemType(), meta.Path.AtName("colors"), meta.Diags,
												func(item kbapi.DataViewsFieldformatParamsColor, meta utils.ListMeta) colorConfigModel {
													return colorConfigModel{
														Range:      types.StringPointerValue(item.Range),
														Regex:      types.StringPointerValue(item.Regex),
														Text:       types.StringPointerValue(item.Text),
														Background: types.StringPointerValue(item.Background),
													}
												}),
											FieldLength: types.Int64PointerValue(utils.Itol(item.FieldLength)),
											Transform:   types.StringPointerValue(item.Transform),
											LookupEntries: utils.SliceToListType(ctx, utils.Deref(item.LookupEntries), getFieldFormatParamsLookupEntryElemType(), meta.Path.AtName("lookup_entries"), meta.Diags,
												func(item kbapi.DataViewsFieldformatParamsLookup, meta utils.ListMeta) lookupEntryModel {
													return lookupEntryModel{
														Key:   types.StringPointerValue(item.Key),
														Value: types.StringPointerValue(item.Value),
													}
												}),
											UnknownKeyValue: types.StringPointerValue(item.UnknownKeyValue),
											Type:            types.StringPointerValue(item.Type),
											Width:           types.Int64PointerValue(utils.Itol(item.Width)),
											Height:          types.Int64PointerValue(utils.Itol(item.Height)),
										}
									}),
							}
						})),
				AllowNoIndex: types.BoolPointerValue(item.AllowNoIndex),
				Namespaces:   handleNamespaces(dvInner.Namespaces, utils.Deref(item.Namespaces)),
			}
		})

	return diags
}