Swift 4: How to use Foundation Locale struct if you have enum with name Locale - swift4.2

So, I have custom enum with name Locale:
public enum Locale: String {
case ru
case uz
}
I'm using it for api response json. If I want use Foundation Locale struct then xcode looks to just my local declared enum.
How to I can use Foundation Locale struct if I have enum with same name?

You can use Foundation.Locale to differentiate Foundation Locale and your local enum

Related

mapstructure tags not used by Viper when writing to YAML

I have structs defined as follows
type config struct {
Contexts map[string]Context `mapstructure:"contexts"`
CurrentContext string `mapstructure:"current-context"`
Tokens []Token `mapstructure:"tokens"`
}
type Context struct {
Endpoint string `mapstructure:"endpoint,omitempty"`
Token string `mapstructure:"token,omitempty"`
Platform string `mapstructure:"platform"`
Components []string `mapstructure:"components,omitempty"`
Channel string `mapstructure:"channel,omitempty"`
Version string `mapstructure:"version,omitempty"`
EnforcedProvider string `mapstructure:"enforced-provider,omitempty"`
}
I'm writing to a YAML config file as follows
configObj.Contexts[contextName] = context
viper.Set("contexts", configObj.Contexts)
viper.Set("current-context", configObj.CurrentContext)
viper.Set("tokens", configObj.Tokens)
err = viper.WriteConfig()
if err != nil {
return err
}
The mapstructure tags I have defined are not written to the YAML file, instead the field names are written in lower case. This is especially a problem with the EnforcedProvider field which is written as enforcedprovider instead of enforced-provider.
How do I make it so that the mapstructure tag is used ?
The documentation mentions mapstructure tags in its Unmarshaling section, but not in its WriteConfig section.
It looks like WriteConfig will go through one of the default encoders :
location where such encoders are declared:
https://github.com/spf13/viper/blob/b89e554a96abde447ad13a26dcc59fd00375e555/viper.go#L341
code for the yaml codec (it just calls the default yaml Marshal/Unmarshal functions):
https://github.com/spf13/viper/blob/b89e554a96abde447ad13a26dcc59fd00375e555/internal/encoding/yaml/codec.go
If you know you will read/write from yaml files only, the simplest way is to set yaml tags on your struct (following the documentation of the gopkg.in/yaml.v2 package) :
type config {
Contexts map[string]Context `yaml:"contexts"`
CurrentContext string `yaml:"current-context"`
Tokens []Token `yaml:"tokens"`
}
type Context struct {
Endpoint string `yaml:"endpoint,omitempty"`
Token string `yaml:"token,omitempty"`
Platform string `yaml:"platform"`
Components []string `yaml:"components,omitempty"`
Channel string `yaml:"channel,omitempty"`
Version string `yaml:"version,omitempty"`
EnforcedProvider string `yaml:"enforced-provider,omitempty"`
}

Go - Same interface to handle multiple types

I am dealing with multiple vendor APIs which allow creating Device records but as expected they represent devices differently. Basic example (focusing on difference of ID types among vendors) -
Vendor1#Device uses integer IDs { ID: <int>, ...vendor1 specific details }
Vendor2#Device uses UUIDs { UUID: <string>, ...vendor2 specific details }
Since, the structures vary among vendors, I am planning to save these (device records) in a MongoDB collection so I have created the following interface to use from application code -
type Device struct {
Checksum string
RemoteID ?? # vendor1 uses int and vendor2 uses uuid
}
type DataAccessor interface {
FindDeviceByChecksum(string) (Device, error)
InsertDevice(Device) (bool, error)
}
This will be used from a orchestration/service object, like -
type Adapter interface {
AssignGroupToDevice(GroupID, DeviceRemoteID ??) (bool, error)
}
type Orchestrator struct {
da DataAccessor
vendorAPI Adapter
}
// Inside orchestrator#Assign method
device, _ := o.da.FindDeviceByChecksum("checksum from arg")
.
.
o.vendorAPI.AssignGroupToDevice("groupID from arg", device.RemoteID ??)
// The above method calls out vendor's HTTP API and passes the json payload built from args
//
As you can see, I can't put a type for RemoteID or DeviceRemoteID. What are my options to handle this pragmatically? An empty interface would have me writing type switches in the interface implementation? Generics? or something else? I am confused.
Your application code should not care at all about the actual vendors and their APIs.
Try to define some core entity package that you will use in your domain, in your application. This can be anything you decide and shouldn't be dependent on external dependencies.
The service will define the interface it needs in order to do the appropiate BL (Find, Insert, Assign group id)
For example:
Entity package can be device
package device
type Device struct {
Checksum string
RemoteID string
}
Note that you can define the RemoteID as a string. For each vendor, you will have an adapter that has knowledge of both the application entities and the external vendor API. Each adapter will need to implement the interface the service requires.
type DeviceRepository interface {
FindDeviceByChecksum(string) (device.Device, error)
InsertDevice(device.Device) (bool, error)
}
type VendorAdapter interface {
AssignGroupToDevice(GroupID, DeviceRemoteID string) (bool, error)
}
type Orchestrator struct {
deviceRepo DeviceRepository
vendorAdapter VendorAdapter
}
// Inside orchestrator#Assign method
device, err := o.deviceRepo.FindDeviceByChecksum("checksum from arg")
if err != nil {...}
.
.
o.vendorAdapter.AssignGroupToDevice("groupID from arg", device.RemoteID)
//
You can note here a few things:
Defined the interfaces in the service package. (Define interfaces where you are using/requiring them)
DeviceRepository: This is the data layer, responsible for persisting your entity (into mongo) (repo is just a convention I'm used to, it doesn't have to be called repo :)
VendorAdapter: adapter to the actual vendor. The service has no knowledge about the implementation of this vendor adapter. It doesn't care what it does with the remote-id. The vendor API that uses int will just convert the string to int.
Of course naming is optional. You can use DeviceProvider instead of VendoreAdapter for example, anything that will make sense to you and your team.
This is the whole point of the adapters, they are converting from/to entity to the external. From application language into the specific external language and vice versa. In some way, a repository is just an adapter to the database.
Edit: For example, the vendor adapter with the int remote-id will just convert the string to int (Unless I'm totally missing the point lol:) :
package vendor2
type adapter struct {
...
}
func (a *adapter) AssignGroupToDevice(groupID, deviceRemoteID string) error {
vendor2RemoteID, err := strconv.Atoi(deviceRemoteID)
if err != nil {...}
// send to vendor api2, using the vendor2RemoteID which is int
}
Edit2:
If there is another field that is different between these vendors and is not primitive, you can still use string. The vendor's adapter will just need to marshal the string to the specific vendor's custom payload.
Another way is of course do as #blackgreen said and save it as interface{}
You need to make a few decisions:
How you will serialize it to the database
How you will serialize it in the vendor's adapters
Are you using it in the application? Meaning is the application has knowledge or is agnostic to the value. (if so, you probably won't want to save it as a string. maybe :)
The repo - will save it as JSON to the DB
The vendor adapter - will convert this interface{} to the actual payload the API needs
But there are many many other options to deal with dynamic types, so sorry I didn't quite answer your question. The core of the solution depends on whether the application uses it, or it is only data for the vendor adapter to use.

Use different database structs in global configuration struct

I have a global config for most settings (e.g. Logfiles) which I use in all Projects, for example:
project config
type Config struct {
Logfile string
Loglevel string
Database *database.Database
}
The config itself has its own project, the database has its own projects and the implementation is done in its own project. (So I have config project, database project, and app project).
I want every Project to implement the database itself since all of them have different functions attached to it. Since I don't want multiple fields for every database, I have a minimum interface which is satisfied by all Database Implementations
project database
// This interface is referenced by the Config struct using *database.Database
type Database interface {
InitDatabase() error
}
type AppDatabase interface {
InitDatabase() error // To satisfy the Database interface
AdditionalFunction1()
AdditionalFunction2()
}
type OtherAppDatabase interface {
InitDatabase() error
OtherFunc1()
}
When I want to implement the database, I want to assign the new database struct to the (project-) global configuration (e.g config.Database).
However, this does not work as I cannot assign the new struct (which implements the database interface) to the conf.Database interface, e.g.
project app
type OtherAppDatabase struct {
*sql.DB
}
func (db *OtherAppDatabase) InitDatabase() error {
conf := config.GetConfig() // this just returns the global config file
conf.Database = d // This does not work [1]
}
func (db *OtherAppDatabase) OtherFunc1() {}
[1]: Cannot use 'db' (type *OtherAppDatabase) as type *database.Database in assignment
Inspection info: Reports incompatible types in binary and unary expressions.
Is there a way to keep one database field in the global config and assign the specific database to it as needed?
Thanks and best regards,

How to specify OpenAPI validation for CRD

I'm currently writing a kubernetes controller, using kubernetes go-client.
I've managed to generate the OpenAPI spec for the resources managed by the controller (by running openapi-gen and annotating types with +k8s:openapi-gen=true).
I also want to generate validators like a maximum length or regex but I don't find any resource about how to do it.
Here is my types.go
package v1
import (
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +resource:path=project
type Project struct {
meta.TypeMeta `json:",inline"`
meta.ObjectMeta `json:"metadata,omitempty"`
Domain string `json:"domain"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ProjectList struct {
meta.TypeMeta `json:",inline"`
meta.ListMeta `json:"metadata,omitempty"`
Items []Project `json:"items"`
}
What I'm trying to achieve is to generate the OpenAPI spec using openapi-gen and include in the spec the following validation for the Domain: regex [a-z]+ and maximum length of 18.
You have to modify the crd.yaml file using openAPIV3Schema, as it is compulsory to add structural schema to prevent sending of malicious data to the API server
The solution to your question is to add the below fields in spec part of your yaml:
domain:
type: string
maxLength: 18
pattern: "[a-z]+"
for more information you can read this article:=> crd-schema

golang enum support in swagger codegen

I am not able to generate the enum with swagger codegen for golang. What modification needs to be done in go model.mustache and GoClientCodegen.java ?
I tried this in mustache :
{{>partial_header}}
package {{packageName}}
{{#models}}{{#imports}}
import ({{/imports}}{{#imports}}
"{{import}}"{{/imports}}{{#imports}}
)
{{/imports}}{{#model}}{{#description}}
// {{{description}}}{{/description}}
type {{classname}} struct {
{{#vars}}{{#description}}
// {{{description}}}{{/description}}
{{name}} {{{datatype}}} `json:"{{baseName}},omitempty"`
{{/vars}}
}
{{#enum}}
type enum string
const (
"COMPLETE"
"INCOMPLETE"
)
{{/enum}}
{{/model}}{{/models}}
GoClientCodegen.java is same. What needs to be modified in the java file and the mustache file ?

Resources