I have the following structs declared in packageA
type FlagSkel struct {
Name string
Short string
HelpMsg string
}
type FlagString struct {
Value string
DefaultValue string
}
type CompositeFlagString struct {
FlagSkel
FlagString
}
In another package, I am trying to initialise (outside any function) a var of the later type as follows:
var Name = packageA.CompositeFlagString{
FlagSkel: {
Name: "name",
Short: "",
HelpMsg: "Something here",
},
FlagString: {
DefaultValue: "",
},
}
However vscode compiler shows me the attached error
What am I doing wrong?
You need to specify the type for the struct literals:
packageA.CompositeFlagString{
FlagSkel: packageA.FlagSkel{
Name: "name",
Short: "",
HelpMsg: "Something here",
},
FlagString: packageA.FlagString{
DefaultValue: "",
},
}
You missed to set the type of your inner structs you want to create.
your variable initialisation should be:
var Name = packageA.CompositeFlagString{
FlagSkel: packageA.FlagSkel {
Name: "name",
Short: "",
HelpMsg: "Something here",
},
FlagString: packageA.FlagString {
DefaultValue: "",
},
}
If you change this, it should work.
Related
I have a golang function that returns roles of type map[string]map[string]string
eg:
map[foo:map[name:abc env:dev id:465 project:e-1] boo:map[name:def env:prd id:82 project:e-1] :doo[name:ght env:stg id:353 project:e-3]]
and I created a schema for it like the following...
func dataSourceAwsAccountHelper() *schema.Resource {
return &schema.Resource{
Read: accountHelperRead,
Schema: map[string]*schema.Schema{
"roles": {
Type: schema.TypeMap,
Elem: &schema.Schema{
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
Computed: true,
},
"id": &schema.Schema{
Computed: true,
Type: schema.TypeString,
},
},
}
}
And the create method to pass the role values to the schema
func rolesRead(d *schema.ResourceData, m interface{}) error {
filteredRoles := filterAccounts("john") // returns `map[string]map[string]string`
if err := d.Set("account_map", filteredRoles); err != nil {
return err
}
//accountMaps := make(map[string]interface{})
d.SetId("-")
return nil
}
but the Terraform output is an empty map, how do I fix it please help :)
Outputs:
output = {
"roles" = tomap(null) /* of map of string */
"id" = tostring(null)
}
expecting output like
Outputs:
output = {
"roles" = { foo = {name = "abc" env = "dev" id= 465 project = "e-1"}
boo = {name = "efg" env = "prd" id= 82 project = "e-2"}
},
"id" = "-"
}
What you are trying to do here is not possbile with the legacy Terraform SDK that you are using. Maps can only be of primitive types: TypeString, TypeInt, TypeBool.
To create this structure you'll need to migrate to the new framework, which is built for the type system of modern Terraform rather than (as is the case for SDKv2) the type system of classic Terraform v0.11 and earlier.
In the Terraform Plugin Framework, the equivalent structure to what you tried to describe here is MapNestedAttribute, with the following describing the schema structure you showed in your question:
schema.MapNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
// ...
},
"env": schema.StringAttribute{
// ...
},
"id": schema.NumberAttribute{
// ...
},
"project": schema.StringAttribute{
// ...
},
},
},
}
This represents a map of objects with the given attributes, and so the above schema type is equivalent to the following type constraint as might be written in a Terraform module using the Terraform language's type constraint syntax:
map(
object({
name = string
env = string
id = number
project = string
})
)
I have a golang function that returns roles of type map[string]map[string]string
eg:
map[foo:map[name:abc env:dev id:465 project:e-1] boo:map[name:def env:prd id:82 project:e-1] :doo[name:ght env:stg id:353 project:e-3]]
and I created a schema for it like the following...
func dataSourceAwsAccountHelper() *schema.Resource {
return &schema.Resource{
Read: accountHelperRead,
Schema: map[string]*schema.Schema{
"roles": {
Type: schema.TypeMap,
Elem: &schema.Schema{
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
Computed: true,
},
"id": &schema.Schema{
Computed: true,
Type: schema.TypeString,
},
},
}
}
And the create method to pass the role values to the schema
func rolesRead(d *schema.ResourceData, m interface{}) error {
filteredRoles := filterAccounts("john") // returns `map[string]map[string]string`
if err := d.Set("account_map", filteredRoles); err != nil {
return err
}
//accountMaps := make(map[string]interface{})
d.SetId("-")
return nil
}
but the Terraform output is an empty map, how do I fix it please help :)
Outputs:
output = {
"roles" = tomap(null) /* of map of string */
"id" = tostring(null)
}
expecting output like
Outputs:
output = {
"roles" = { foo = {name = "abc" env = "dev" id= 465 project = "e-1"}
boo = {name = "efg" env = "prd" id= 82 project = "e-2"}
},
"id" = "-"
}
What you are trying to do here is not possbile with the legacy Terraform SDK that you are using. Maps can only be of primitive types: TypeString, TypeInt, TypeBool.
To create this structure you'll need to migrate to the new framework, which is built for the type system of modern Terraform rather than (as is the case for SDKv2) the type system of classic Terraform v0.11 and earlier.
In the Terraform Plugin Framework, the equivalent structure to what you tried to describe here is MapNestedAttribute, with the following describing the schema structure you showed in your question:
schema.MapNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
// ...
},
"env": schema.StringAttribute{
// ...
},
"id": schema.NumberAttribute{
// ...
},
"project": schema.StringAttribute{
// ...
},
},
},
}
This represents a map of objects with the given attributes, and so the above schema type is equivalent to the following type constraint as might be written in a Terraform module using the Terraform language's type constraint syntax:
map(
object({
name = string
env = string
id = number
project = string
})
)
I'm trying to construct a Go Swagger response to my existing code without changing a bunch of it and I currently have:
// DataExpressionInput - only public so we can use it embedded in dataExpression
// swagger:model
type DataExpressionInput struct {
Name string `json:"name"`
Expression string `json:"expression"`
Type expressionType `json:"type"`
Comments string `json:"comments"`
Tags []string `json:"tags"`
}
// swagger:model dataExpressionModel
type DataExpression struct {
// The main data expression information
//
// Required: true
*DataExpressionInput
// Additional metadata
*pixlUser.APIObjectItem
}
//swagger:response dataExpressionLookup
type DataExpressionLookup map[string]DataExpression
I'm trying to return a dataExpressionLookup Object via my API but when I export the swagger definition i get:
"definitions": {
"DataExpressionInput": {
"description": "DataExpressionInput - only public so we can use it embedded in dataExpression",
"x-go-package": "github.com/pixlise/core/v2/core/expression"
},
"dataExpressionModel": {
"x-go-name": "DataExpression",
"x-go-package": "github.com/pixlise/core/v2/core/expression"
}
},
"responses": {
"dataExpressionLookup": {
"description": "",
"schema": {}
},
"deleteResponse": {
"description": "",
"schema": {}
},
"genericError": {
"description": "",
"schema": {}
},
"shareResponse": {
"description": "",
"schema": {}
}
},
Is it possible to create a struct with dynamic/arbitrary fields and values?
My app will receive request with JSON body:
{
"Details": {
"Id": “123”,
},
"Event": {
"Event": "Event",
},
“RequestValues”: [
{
“Name": "Name1",
"Value": "Val1"
},
{
"Name": "Name2",
"Value": 2
},
{
"Name": “Foo”,
"Value": true
}
]
}
This will be unmarshalled to my model 'Request':
type Request struct {
Details Details `json:"Details"`
Event Event `json:"Event"`
RequestValues []RequestValues `json:"RequestValues"`
}
type Details struct {
Id string `json:"Id"`
}
type Event struct {
Event string `json:"Event"`
}
type RequestValues struct {
Name string `json:"Name"`
Value string `json:"Value"`
}
I have to re-map model 'Request' to a new model 'Event' with arbitrary fields in "Values". After marshalling new re- mapped model 'Event' I should get this JSON output that corresponds to the request:
{
"Event": "Event"
"Values": {
“Id": "123", <= non arbitrary mapping from Request.Detail.Id
"Name1": "Val1", <= arbitrary
"Name2": 2, <= arbitrary
“Foo”: true <= arbitrary
}
}
Arbitrary values will be mapped from "RequestValues". Names of those fields should be the values of Request.RequestValues.Name and their values should be the values of Request.RequestValues.Value
Here is my 'Event' model:
type Event struct {
Event string `json:"Event"`
Values Values `json:"Values"`
}
type Values struct{
Id string `json:"Id"`
}
Firstly, here's a JSON-valid copy of your JSON:
{
"Details": {
"Id": "123"
},
"Event": {
"Event": "Event"
},
"RequestValues": [
{
"RequestValueName": "Name1",
"RequestValue": "Val1"
},
{
"RequestValueName": "Name2",
"RequestValue": 2
},
{
"RequestValueName": "Foo",
"RequestValue": true
}
]
}
Start by creating a type Input struct{} to describe the JSON that you're looking to parse, and a type Output struct{} for the JSON that you're looking to generate, and write a little code to convert from one to the other. You don't have to add all of the fields right away - you can start with just Event for example and add more until you've got them all.
I've done this in https://play.golang.org/p/PvpKnFMrJjN to show you, but I would recommend having only a quick read of it before trying to recreate it yourself.
A useful tool to convert JSON into Go structs is https://mholt.github.io/json-to-go/ but it will trip on RequestValue in your example which has several data types (and is therefore where we use interface{}).
I thing that you can use map like this:
package main
import (
"fmt"
)
type Event struct {
event string
values map[string]string
}
func main() {
eventVar := Event{event: "event", values: map[string]string{}}
eventVar.values["Id"] = "12345"
eventVar.values["vale1"] = "value"
fmt.Println(eventVar)
}
You just need to validate somehow that the id it's in there, this if you need values in the same level.
I hope this works for you.
Currently, I'm trying to pass an object as a variable to a mutation as shown below:
type ShopLocation {
lane1: String
lane2: String
city: String
postalCode: String
country: String
}
type ShopResponse {
statusCode: Int
messageCode: String
data: String
}
type Mutation {
createShop(
name: String
email: String
location: ShopLocation
): ShopResponse
}
But I get the following error:
{
"error": {
"errors": [
{
"message": "The type of Mutation.createShop(location:) must be Input Type but got: ShopLocation.",
"extensions": {
"code": "GRAPHQL_VALIDATION_FAILED",
"exception": {
"stacktrace": [
"Error: The type of Mutation.createShop(location:) must be Input Type but got: ShopLocation.",
" at assertValidSchema (.../node_modules/graphql/type/validate.js:71:11)",
" at Object.validate (.../node_modules/graphql/validation/validate.js:55:35)",
" at Promise.resolve.then (.../node_modules/apollo-server-core/src/runQuery.ts:188:30)",
" at <anonymous>",
" at process._tickDomainCallback (internal/process/next_tick.js:228:7)"
]
}
}
}
]
}
}
Any idea how to properly do this?
You need to make the ShopLocation with input keyword instead of type,
input ShopLocationInput {
lane1: String
lane2: String
city: String
postalCode: String
country: String
}
type ShopResponse {
statusCode: Int
messageCode: String
data: String
}
type Mutation {
createShop(
name: String
email: String
location: ShopLocationInput
): ShopResponse
}