resource

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2018 License: Apache-2.0 Imports: 7 Imported by: 0

README

Description

The common interfaces, types and helper functions to work with identifiers are defined in resource file. Please see example to see how to work with identifiers.

Codecs

You could register resource.Codec for you PB type to be used to convert atlas.rpc.Identifier that defined for that type.

By default if PB resource is undefined (nil) the atlas.rpc.Identifier is converted to a string in fully qualified format specified for Atlas References, otherwise the Resource ID part is returned as string value.

If resource.Codec is not registered for a PB type the value of identifier is converted from driver.Value to a string. If Resource Type is not found it is populated from the name of PB type, the Application Name is populated if was registered. (see RegisterApplication).

protoc-gen-gorm

The plugin has support of atlas.rpc.Identifier for all association types. All you need is to define your Primary/Foreign keys as a fields of atlas.rpc.Identifier type.

In the XxxORM generated models atlas.rpc.Identifier will be replaced to the type specified in (gorm.field).tag option. The only numeric and text formats are supported. If type is not set it will be generated as interface{}.

If you want to expose foreign keys on API just leave them with empty type in gorm.field.tag and it will be calculated based on the parent's primary key type.

The Postgres types from tags are converted as follows:

    switch type_from_tag {
    case "uuid", "text", "char", "array", "cidr", "inet", "macaddr":
        orm_model_field = "string"
    case "smallint", "integer", "bigint", "numeric", "smallserial", "serial", "bigserial":
        orm_model_field = "int64"
    case "jsonb", "bytea":
        orm_model_field = "[]byte"
    case "":
        orm_model_field = "interface{}"
    default:
        return errors.New("unknown tag type of atlas.rpc.Identifier")
    }

NOTE Be sure to set type properly for association fields.

Step 1 Let's define PB resources

syntax = "proto3";

import "github.com/infobloxopen/atlas-app-toolkit/rpc/resource/resource.proto";
import "github.com/infobloxopen/protoc-gen-gorm/options/gorm.proto";

option go_package = "github.com/yourapp/pb;pb";

message A {
    option (gorm.opts).ormable = true;
    
    atlas.rpc.Identifier id = 1 [(gorm.field).tag = {type: "integer"}];
    string value = 2;
    repeated B b_list = 3; // has many
    atlas.rpc.Identifier external = 4 [(gorm.field).tag = {type: "text"}];
}

message B {
    option (gorm.opts).ormable = true;
    
    atlas.rpc.Identifier id = 1 [(gorm.field).tag = {type: "integer"}];
    string value = 2;
     // foreign key to A  parent. !!! Will be set to the type of A.id
    atlas.rpc.Identifier a_id = 3;
}

In JSON it could look like

{
  "id": "someapp/resource:a/1",
  "value": "someAvalue",
  "b_list": [
    {
      "id": "someapp/resource:b/1",
      "value": "someBvalue",
      "a_id": "someapp/resource:a/1"
    }
  ]
}

The generated code could be:

import "github.com/infobloxopen/atlas-app-toolkit/gorm/resource"

type AORM struct {
	Id int64
	Value string
	BList []*BORM
	External string
}

type BORM struct {
	Id int64
	Value string
	AId *int64
}

Step 2 The last thing you need to make identifiers work correctly is to register the name of your application, that name will be used during encoding to populate ApplicationName field of atlas.rpc.Identifier.

package main

import "github.com/infobloxopen/atlas-app-toolkit/gorm/resource"

func main() {
    resource.RegisterApplication("MyAppName")
}

FAQ

How to customize name of my PB type?

Add XXX_MessageName() string method to you PB type. See Name function.

I want to validate/generate atlas.rpc.Identifier for PB types in my application

Implement resource.Codec for your PB types and you will be given a full control on how Identifiers are converted to/from driver.Value.

Documentation

Overview

Example
package main

import (
	"fmt"

	resourcepb "github.com/infobloxopen/atlas-app-toolkit/rpc/resource"
)

type ExampleGoType struct {
	ID         int64
	ExternalID string
	VarName    string
}

type ExampleProtoMessage struct {
	Id         *resourcepb.Identifier
	ExternalId *resourcepb.Identifier
	VarName    string
}

func (ExampleProtoMessage) XXX_MessageName() string { return "ExampleProtoMessage" }
func (ExampleProtoMessage) Reset()                  {}
func (ExampleProtoMessage) String() string          { return "ExampleProtoMessage" }
func (ExampleProtoMessage) ProtoMessage()           {}

func main() {
	RegisterApplication("app")

	// you want to convert PB type to your application type
	toGoTypeFunc := func(msg *ExampleProtoMessage) (*ExampleGoType, error) {
		var v ExampleGoType

		// arbitrary variables
		v.VarName = msg.VarName

		// convert RPC identifier using UUID Codec for ExampleProtoMessage resource type
		if id, err := DecodeInt64(msg, msg.Id); err != nil {
			return nil, err
		} else {
			v.ID = id
		}
		// convert RPC identifier using External Codec for default resource type
		if id, err := Decode(nil, msg.ExternalId); err != nil {
			return nil, err
		} else {
			v.ExternalID = id.(string)
		}
		return &v, nil
	}

	// let's create PB message
	pb := &ExampleProtoMessage{
		Id: &resourcepb.Identifier{
			ApplicationName: "simpleapp",
			ResourceType:    "examples",
			ResourceId:      "12",
		},
		// ExternalId stores data about "external_resource" that belongs to
		// "externalapp" and has id "id"
		ExternalId: &resourcepb.Identifier{
			ApplicationName: "externalapp",
			ResourceType:    "external_resource",
			ResourceId:      "id",
		},
		VarName: "somename",
	}

	val, err := toGoTypeFunc(pb)
	if err != nil {
		fmt.Printf("failed to convert TestProtoMessage to TestGoType: %s\n", err)
		return
	}

	fmt.Printf("application name of integer id: %v\n", val.ID)
	fmt.Printf("application name of fqstring id: %v\n", val.ExternalID)

	// so now you want to convert it back to PB representation
	toPBMessageFunc := func(v *ExampleGoType) (*ExampleProtoMessage, error) {
		var pb ExampleProtoMessage

		// arbitrary variables
		pb.VarName = v.VarName

		// convert internal id to RPC representation using registered UUID codec
		if id, err := EncodeInt64(pb, v.ID); err != nil {
			return nil, err
		} else {
			pb.Id = id
		}

		// convert fqstring id to RPC representation using registered External codec
		if id, err := Encode(nil, v.ExternalID); err != nil {
			return nil, err
		} else {
			pb.ExternalId = id
		}

		return &pb, nil
	}

	pb, err = toPBMessageFunc(val)
	if err != nil {
		fmt.Println("failed to convert TestGoType to TestProtoMessage")
	}

	fmt.Printf("application name of internal id: %s\n", pb.Id.GetApplicationName())
	fmt.Printf("resource type of internal id: %s\n", pb.Id.GetResourceType())
	fmt.Printf("resource id of internal id: %s\n", pb.Id.GetResourceId())
	fmt.Printf("application name of fqstring id: %s\n", pb.ExternalId.GetApplicationName())
	fmt.Printf("resource type of fqstring id: %s\n", pb.ExternalId.GetResourceType())
	fmt.Printf("resource id of fqstring id: %s\n", pb.ExternalId.GetResourceId())

}
Output:

application name of integer id: 12
application name of fqstring id: externalapp/external_resource/id
application name of internal id: app
resource type of internal id: exampleprotomessage
resource id of internal id: 12
application name of fqstring id: externalapp
resource type of fqstring id: external_resource
resource id of fqstring id: id

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplicationName

func ApplicationName() string

ApplicationName returns application name registered by RegisterApplication.

func Decode

func Decode(pb proto.Message, id *resourcepb.Identifier) (driver.Value, error)

Decode decodes identifier using a codec registered for pb if found.

If codec is not found and pb is nil the id is decoded in a fully qualified string value in format specified for Atlas References.

If codec is not found the only Resource ID part of the identifier is returned as string value.

func DecodeBytes

func DecodeBytes(pb proto.Message, id *resourcepb.Identifier) ([]byte, error)

DecodeBytes decodes value returned by Decode as []byte. Returns an error if value is not of []byte type.

func DecodeInt64

func DecodeInt64(pb proto.Message, id *resourcepb.Identifier) (int64, error)

DecodeInt64 decodes value returned by Decode as int64. Returns an error if value is not of int64 type.

func Encode

func Encode(pb proto.Message, value driver.Value) (*resourcepb.Identifier, error)

Encode encodes identifier using a codec registered for pb.

If codec is not found and value is not of string type an error is returned.

If codec is not found and pb is nil the id is encoded as it would be a string value in fully qualified format.

If codec is not found the value is encoded as string and Resource ID part of identifier is populated. The Application Name and Resource Type populated using ApplicationName and ResourceType functions.

func EncodeBytes

func EncodeBytes(pb proto.Message, value driver.Value) (*resourcepb.Identifier, error)

EncodeBytes converts value to string and forwards call to Encode. Returns an error if value is not of []byte type.

func EncodeInt64

func EncodeInt64(pb proto.Message, value driver.Value) (*resourcepb.Identifier, error)

EncodeInt64 converts value to string and forwards call to Encode. Returns an error if value is not of int64 type.

func Name

func Name(pb proto.Message) string

Name returns name of pb. If pb implements XXX_MessageName then it is used to return name, otherwise proto.MessageName is used and "s" symbol is added at the end of the message name.

func RegisterApplication

func RegisterApplication(name string)

RegisterApplication registers name of the application. Registered name is used by Encode to populate application name of Protocol Buffer Identifier.

func RegisterCodec

func RegisterCodec(codec Codec, pb proto.Message)

RegisterCodec registers codec for a given pb. If pb is nil the codec is registered as default. If codec is nil or registered twice for the same resource the panic is raised.

Types

type Codec

type Codec interface {
	// Encode encodes value to Protocol Buffer representation
	Encode(driver.Value) (*resourcepb.Identifier, error)
	// Decode decodes Protocol Buffer representation to the driver.Value
	Decode(*resourcepb.Identifier) (driver.Value, error)
}

Codec defines the interface package uses to encode and decode Protocol Buffer Identifier to the driver.Value. Note that implementation must be thread safe.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL