README

GoData

This is an implementation of OData in Go. It is capable of parsing an OData request, and exposing it in a standard way so that any provider can consume OData requests and produce a response. Providers can be written for general usage like producing SQL statements for a databases, or very specific uses like connecting to another API.

Most OData server frameworks are C#/.NET or Java. These require using the CLR or JVM, and are overkill for a lot of use cases. By using Go we aim to provide a lightweight, fast, and concurrent OData service. By exposing a generic interface to an OData request, we hope to enable any backend to expose itself with an OData API with as little effort as possible.

Status

This project is not finished yet, and cannot be used in its current state. Progress is underway to make it usable, and eventually fully compatible with the OData V4 specification.

Work in Progress

  • Parse OData URLs
  • Create provider interface for GET requests
  • Parse OData POST and PATCH requests
  • Create provider interface for POST and PATCH requests
  • Parse OData DELETE requests
  • Create provider interface for PATCH requests
  • Allow injecting middleware into the request pipeline to enable such features as caching, authentication, telemetry, etc.
  • Work on fully supporting the OData specification with unit tests

Feel free to contribute with any of these tasks.

High Level Architecture

If you're interesting in helping out, here is a quick introduction to the code to help you understand the process. The code works something like this:

  1. A provider is initialized that defines the object model (i.e., metadata), of the OData service. (See the example directory.)
  2. An HTTP request is received by the request handler in service.go
  3. The URL is parsed into a data structure defined in request_model.go
  4. The request model is semanticized, so each piece of the request is associated with an entity/type/collection/etc. in the provider object model.
  5. The correct method and type of request (entity, collection, $metadata, $ref, property, etc.) is determined from the semantic information.
  6. The request is then delegated to the appropriate method of a GoDataProvider, which will produce a response based on the semantic information, and package it into a response defined in response_model.go.
  7. The response is converted to JSON and sent back to the client.
Expand ▾ Collapse ▴

Documentation

Index

Constants

const (
	ExpandTokenOpenParen = iota
	ExpandTokenCloseParen
	ExpandTokenNav
	ExpandTokenComma
	ExpandTokenSemicolon
	ExpandTokenEquals
	ExpandTokenLiteral
)

const (
	FilterTokenOpenParen int = iota
	FilterTokenCloseParen
	FilterTokenWhitespace
	FilterTokenNav
	FilterTokenColon // for 'any' and 'all' lambda operators
	FilterTokenComma // 5
	FilterTokenLogical
	FilterTokenOp
	FilterTokenFunc
	FilterTokenLambda
	FilterTokenNull // 10
	FilterTokenIt
	FilterTokenRoot
	FilterTokenFloat
	FilterTokenInteger
	FilterTokenString // 15
	FilterTokenDate
	FilterTokenTime
	FilterTokenDateTime
	FilterTokenBoolean
	FilterTokenLiteral // 20
	FilterTokenDuration
)

const (
	ALLPAGES = "allpages"
	NONE     = "none"
)

const (
	GoDataString         = "Edm.String"
	GoDataInt16          = "Edm.Int16"
	GoDataInt32          = "Edm.Int32"
	GoDataInt64          = "Edm.Int64"
	GoDataDecimal        = "Edm.Decimal"
	GoDataBinary         = "Edm.Binary"
	GoDataBoolean        = "Edm.Boolean"
	GoDataTimeOfDay      = "Edm.TimeOfDay"
	GoDataDate           = "Edm.Date"
	GoDataDateTimeOffset = "Edm.DateTimeOffset"
)

const (
	ASC  = "asc"
	DESC = "desc"
)

const (
	OpAssociationLeft int = iota
	OpAssociationRight
	OpAssociationNone
)

const (
	NodeTypeLiteral int = iota
	NodeTypeOp
	NodeTypeFunc
)

const (
	RequestKindUnknown int = iota
	RequestKindMetadata
	RequestKindService
	RequestKindEntity
	RequestKindCollection
	RequestKindSingleton
	RequestKindProperty
	RequestKindPropertyValue
	RequestKindRef
	RequestKindCount
)

const (
	SemanticTypeUnknown int = iota
	SemanticTypeEntity
	SemanticTypeEntitySet
	SemanticTypeDerivedEntity
	SemanticTypeAction
	SemanticTypeFunction
	SemanticTypeProperty
	SemanticTypePropertyValue
	SemanticTypeRef
	SemanticTypeCount
	SemanticTypeMetadata
)

const (
	SearchTokenLiteral int = iota
	SearchTokenOpenParen
	SearchTokenCloseParen
	SearchTokenOp
	SearchTokenWhitespace
)

const (
	ODataFieldContext string = "@odata.context"
	ODataFieldCount   string = "@odata.count"
	ODataFieldValue   string = "value"
)

Variables

var GlobalExpandTokenizer = ExpandTokenizer()

var GlobalFilterParser = FilterParser()

var GlobalFilterTokenizer = FilterTokenizer()

var GlobalSearchParser = SearchParser()

var GlobalSearchTokenizer = SearchTokenizer()

Functions

func ParseExpandOption

func ParseExpandOption(queue *tokenQueue, item *ExpandItem) error

func ParseName

func ParseName(segment string) string

func ParseUrlPath

func ParseUrlPath(path string) (*GoDataSegment, *GoDataSegment, error)

func SemanticizeExpandQuery

func SemanticizeExpandQuery(
	expand *GoDataExpandQuery,
	service *GoDataService,
	entity *GoDataEntityType,
) error

func SemanticizeFilterQuery

func SemanticizeFilterQuery(
	filter *GoDataFilterQuery,
	service *GoDataService,
	entity *GoDataEntityType,
) error

func SemanticizeOrderByQuery

func SemanticizeOrderByQuery(orderby *GoDataOrderByQuery, service *GoDataService, entity *GoDataEntityType) error

func SemanticizePathSegment

func SemanticizePathSegment(segment *GoDataSegment, service *GoDataService) error

func SemanticizeRequest

func SemanticizeRequest(req *GoDataRequest, service *GoDataService) error

Compare a request to a given service, and validate the semantics and update the request with semantics included

func SemanticizeSelectQuery

func SemanticizeSelectQuery(sel *GoDataSelectQuery, service *GoDataService, entity *GoDataEntityType) error

Types

type DuplicateQueryParameterError

type DuplicateQueryParameterError struct {
	Parameter string
}

func (*DuplicateQueryParameterError) Error

func (err *DuplicateQueryParameterError) Error() string

type ExpandItem

type ExpandItem struct {
	Path    []*Token
	Filter  *GoDataFilterQuery
	At      *GoDataFilterQuery
	Search  *GoDataSearchQuery
	OrderBy *GoDataOrderByQuery
	Skip    *GoDataSkipQuery
	Top     *GoDataTopQuery
	Select  *GoDataSelectQuery
	Expand  *GoDataExpandQuery
	Levels  int
}

Represents an item to expand in an OData query. Tracks the path of the entity to expand and also the filter, levels, and reference options, etc.

func ParseExpandItem

func ParseExpandItem(input tokenQueue) (*ExpandItem, error)

type Function

type Function struct {
	Token string
	// The number of parameters this function accepts
	Params []int
}

type GoDataAction

type GoDataAction struct {
	XMLName       xml.Name `xml:"Action"`
	Name          string   `xml:"Name,attr"`
	IsBound       string   `xml:"IsBound,attr,omitempty"`
	EntitySetPath string   `xml:"EntitySetPath,attr,omitempty"`
	Parameters    []*GoDataParameter
	ReturnType    *GoDataReturnType
}

type GoDataActionImport

type GoDataActionImport struct {
	XMLName   xml.Name `xml:"ActionImport"`
	Name      string   `xml:"Name,attr"`
	Action    string   `xml:"Action,attr"`
	EntitySet string   `xml:"EntitySet,attr,omitempty"`
}

type GoDataAnnotation

type GoDataAnnotation struct {
	XMLName   xml.Name `xml:"Annotation"`
	Term      string   `xml:"Term,attr"`
	Qualifier string   `xml:"Qualifier,attr,omitempty"`
}

type GoDataAnnotations

type GoDataAnnotations struct {
	XMLName     xml.Name `xml:"Annotations"`
	Target      string   `xml:"Target,attr"`
	Qualifier   string   `xml:"Qualifier,attr,omitempty"`
	Annotations []*GoDataAnnotation
}

type GoDataApplyQuery

type GoDataApplyQuery string

func ParseApplyString

func ParseApplyString(apply string) (*GoDataApplyQuery, error)

type GoDataComplexType

type GoDataComplexType struct {
	XMLName              xml.Name `xml:"ComplexType"`
	Name                 string   `xml:"Name,attr"`
	BaseType             string   `xml:"BaseType,attr,omitempty"`
	Abstract             string   `xml:"Abstract,attr,omitempty"`
	OpenType             string   `xml:"OpenType,attr,omitempty"`
	Properties           []*GoDataProperty
	NavigationProperties []*GoDataNavigationProperty
}

type GoDataCountQuery

type GoDataCountQuery bool

func ParseCountString

func ParseCountString(count string) (*GoDataCountQuery, error)

type GoDataEntityContainer

type GoDataEntityContainer struct {
	XMLName         xml.Name `xml:"EntityContainer"`
	Name            string   `xml:"Name,attr"`
	Extends         string   `xml:"Extends,attr,omitempty"`
	EntitySets      []*GoDataEntitySet
	Singletons      []*GoDataSingleton
	ActionImports   []*GoDataActionImport
	FunctionImports []*GoDataFunctionImport
}

type GoDataEntitySet

type GoDataEntitySet struct {
	XMLName                    xml.Name `xml:"EntitySet"`
	Name                       string   `xml:"Name,attr"`
	EntityType                 string   `xml:"EntityType,attr"`
	IncludeInServiceDocument   string   `xml:"IncludeInServiceDocument,attr,omitempty"`
	NavigationPropertyBindings []*GoDataNavigationPropertyBinding
}

type GoDataEntityType

type GoDataEntityType struct {
	XMLName              xml.Name `xml:"EntityType"`
	Name                 string   `xml:"Name,attr"`
	BaseType             string   `xml:"BaseType,attr,omitempty"`
	Abstract             string   `xml:"Abstract,attr,omitempty"`
	OpenType             string   `xml:"OpenType,attr,omitempty"`
	HasStream            string   `xml:"HasStream,attr,omitempty"`
	Key                  *GoDataKey
	Properties           []*GoDataProperty
	NavigationProperties []*GoDataNavigationProperty
}

type GoDataEnumType

type GoDataEnumType struct {
	XMLName        xml.Name `xml:"EnumType"`
	Name           string   `xml:"Name,attr"`
	UnderlyingType string   `xml:"UnderlyingType,attr,omitempty"`
	IsFlags        string   `xml:"IsFlags,attr,omitempty"`
	Members        []*GoDataMember
}

type GoDataError

type GoDataError struct {
	ResponseCode int
	Message      string
	Cause        error
}

func BadRequestError

func BadRequestError(message string) *GoDataError

func GoneError

func GoneError(message string) *GoDataError

func InternalServerError

func InternalServerError(message string) *GoDataError

func MethodNotAllowedError

func MethodNotAllowedError(message string) *GoDataError

func NotFoundError

func NotFoundError(message string) *GoDataError

func NotImplementedError

func NotImplementedError(message string) *GoDataError

func PreconditionFailedError

func PreconditionFailedError(message string) *GoDataError

func (*GoDataError) Error

func (err *GoDataError) Error() string

func (*GoDataError) SetCause

func (err *GoDataError) SetCause(e error) *GoDataError

func (*GoDataError) Unwrap

func (err *GoDataError) Unwrap() error

type GoDataExpandQuery

type GoDataExpandQuery struct {
	ExpandItems []*ExpandItem
}

func ParseExpandString

func ParseExpandString(expand string) (*GoDataExpandQuery, error)

type GoDataFilterQuery

type GoDataFilterQuery struct {
	Tree *ParseNode
	// The raw filter string
	RawValue string
}

Stores a parsed version of the filter query string. Can be used by providers to apply the filter based on their own implementation. The filter is stored as a parse tree that can be traversed.

func ParseFilterString

func ParseFilterString(filter string) (*GoDataFilterQuery, error)

Convert an input string from the $filter part of the URL into a parse tree that can be used by providers to create a response.

type GoDataFormatQuery

type GoDataFormatQuery struct {
}

type GoDataFunction

type GoDataFunction struct {
	XMLName       xml.Name `xml:"Function"`
	Name          string   `xml:"Name,attr"`
	IsBound       string   `xml:"IsBound,attr,omitempty"`
	IsComposable  string   `xml:"IsComposable,attr,omitempty"`
	EntitySetPath string   `xml:"EntitySetPath,attr,omitempty"`
	Parameters    []*GoDataParameter
	ReturnType    *GoDataReturnType
}

type GoDataFunctionImport

type GoDataFunctionImport struct {
	XMLName                  xml.Name `xml:"FunctionImport"`
	Name                     string   `xml:"Name,attr"`
	Function                 string   `xml:"Function,attr"`
	EntitySet                string   `xml:"EntitySet,attr,omitempty"`
	IncludeInServiceDocument string   `xml:"IncludeInServiceDocument,attr,omitempty"`
}

type GoDataIdentifier

type GoDataIdentifier map[string]string

func ParseIdentifiers

func ParseIdentifiers(segment string) *GoDataIdentifier

func (*GoDataIdentifier) Get

func (id *GoDataIdentifier) Get() string

Return the first key in the map. This is how you should get the identifier for single values, e.g. when the path is Employee(1), etc.

func (*GoDataIdentifier) GetKey

func (id *GoDataIdentifier) GetKey(key string) (string, bool)

Return a specific value for a specific key.

func (*GoDataIdentifier) HasMultiple

func (id *GoDataIdentifier) HasMultiple() bool

Check if this identifier has more than one key/value pair.

type GoDataInclude

type GoDataInclude struct {
	XMLName   xml.Name `xml:"edmx:Include"`
	Namespace string   `xml:"Namespace,attr"`
	Alias     string   `xml:"Alias,attr,omitempty"`
}

type GoDataIncludeAnnotations

type GoDataIncludeAnnotations struct {
	XMLName         xml.Name `xml:"edmx:IncludeAnnotations"`
	TermNamespace   string   `xml:"TermNamespace,attr"`
	Qualifier       string   `xml:"Qualifier,attr,omitempty"`
	TargetNamespace string   `xml:"TargetNamespace,attr,omitempty"`
}

type GoDataInlineCountQuery

type GoDataInlineCountQuery string

func ParseInlineCountString

func ParseInlineCountString(inlinecount string) (*GoDataInlineCountQuery, error)

type GoDataKey

type GoDataKey struct {
	XMLName     xml.Name `xml:"Key"`
	PropertyRef *GoDataPropertyRef
}

type GoDataMember

type GoDataMember struct {
	XMLName xml.Name `xml:"Member"`
	Name    string   `xml:"Name,attr"`
	Value   string   `xml:"Value,attr,omitempty"`
}

type GoDataMetadata

type GoDataMetadata struct {
	XMLName      xml.Name `xml:"edmx:Edmx"`
	XMLNamespace string   `xml:"xmlns:edmx,attr"`
	Version      string   `xml:"Version,attr"`
	DataServices *GoDataServices
	References   []*GoDataReference
}

func (*GoDataMetadata) Bytes

func (t *GoDataMetadata) Bytes() ([]byte, error)

type GoDataNavigationProperty

type GoDataNavigationProperty struct {
	XMLName                xml.Name `xml:"NavigationProperty"`
	Name                   string   `xml:"Name,attr"`
	Type                   string   `xml:"Type,attr"`
	Nullable               string   `xml:"Nullable,attr,omitempty"`
	Partner                string   `xml:"Partner,attr,omitempty"`
	ContainsTarget         string   `xml:"ContainsTarget,attr,omitempty"`
	ReferentialConstraints []*GoDataReferentialConstraint
}

type GoDataNavigationPropertyBinding

type GoDataNavigationPropertyBinding struct {
	XMLName xml.Name `xml:"NavigationPropertyBinding"`
	Path    string   `xml:"Path,attr"`
	Target  string   `xml:"Target,attr"`
}

type GoDataOnDelete

type GoDataOnDelete struct {
	XMLName xml.Name `xml:"OnDelete"`
	Action  string   `xml:"Action,attr"`
}

type GoDataOrderByQuery

type GoDataOrderByQuery struct {
	OrderByItems []*OrderByItem
	// The raw orderby string
	RawValue string
}

func ParseOrderByString

func ParseOrderByString(orderby string) (*GoDataOrderByQuery, error)

type GoDataParameter

type GoDataParameter struct {
	XMLName   xml.Name `xml:"Parameter"`
	Name      string   `xml:"Name,attr"`
	Type      string   `xml:"Type,attr"`
	Nullable  string   `xml:"Nullable,attr,omitempty"`
	MaxLength int      `xml:"MaxLength,attr,omitempty"`
	Precision int      `xml:"Precision,attr,omitempty"`
	Scale     int      `xml:"Scale,attr,omitempty"`
	SRID      string   `xml:"SRID,attr,omitempty"`
}

type GoDataProperty

type GoDataProperty struct {
	XMLName      xml.Name `xml:"Property"`
	Name         string   `xml:"Name,attr"`
	Type         string   `xml:"Type,attr"`
	Nullable     string   `xml:"Nullable,attr,omitempty"`
	MaxLength    int      `xml:"MaxLength,attr,omitempty"`
	Precision    int      `xml:"Precision, attr,omitempty"`
	Scale        int      `xml:"Scale,attr,omitempty"`
	Unicode      string   `xml:"Unicode,attr,omitempty"`
	SRID         string   `xml:"SRID,attr,omitempty"`
	DefaultValue string   `xml:"DefaultValue,attr,omitempty"`
}

type GoDataPropertyRef

type GoDataPropertyRef struct {
	XMLName xml.Name `xml:"PropertyRef"`
	Name    string   `xml:"Name,attr"`
}

type GoDataProvider

type GoDataProvider interface {
	// Request a single entity from the provider. Should return a response field
	// that contains the value mapping properties to values for the entity.
	GetEntity(*GoDataRequest) (*GoDataResponseField, error)
	// Request a collection of entities from the provider. Should return a
	// response field that contains the value of a slice of every entity in the
	// collection filtered by the request query parameters.
	GetEntityCollection(*GoDataRequest) (*GoDataResponseField, error)
	// Request the number of entities in a collection, disregarding any filter
	// query parameters.
	GetCount(*GoDataRequest) (int, error)
	// Get the object model representation from the provider.
	GetMetadata() *GoDataMetadata
}

The basic interface for a GoData provider. All providers must implement these functions.

type GoDataQuery

type GoDataQuery struct {
	Filter      *GoDataFilterQuery
	At          *GoDataFilterQuery
	Apply       *GoDataApplyQuery
	Expand      *GoDataExpandQuery
	Select      *GoDataSelectQuery
	OrderBy     *GoDataOrderByQuery
	Top         *GoDataTopQuery
	Skip        *GoDataSkipQuery
	Count       *GoDataCountQuery
	InlineCount *GoDataInlineCountQuery
	Search      *GoDataSearchQuery
	Format      *GoDataFormatQuery
}

func ParseUrlQuery

func ParseUrlQuery(query url.Values, lenient bool) (*GoDataQuery, error)

type GoDataReference

type GoDataReference struct {
	XMLName            xml.Name `xml:"edmx:Reference"`
	Uri                string   `xml:"Uri,attr"`
	Includes           []*GoDataInclude
	IncludeAnnotations []*GoDataIncludeAnnotations
}

type GoDataReferentialConstraint

type GoDataReferentialConstraint struct {
	XMLName            xml.Name        `xml:"ReferentialConstraint"`
	Property           string          `xml:"Property,attr"`
	ReferencedProperty string          `xml:"ReferencedProperty,attr"`
	OnDelete           *GoDataOnDelete `xml:"OnDelete,omitempty"`
}

type GoDataRequest

type GoDataRequest struct {
	FirstSegment *GoDataSegment
	LastSegment  *GoDataSegment
	Query        *GoDataQuery
	RequestKind  int
}

func ParseRequest

func ParseRequest(path string, query url.Values, lenient bool) (*GoDataRequest, error)

Parse a request from the HTTP server and format it into a GoDaataRequest type to be passed to a provider to produce a result.

type GoDataResponse

type GoDataResponse struct {
	Fields map[string]*GoDataResponseField
}

A response is a dictionary of keys to their corresponding fields. This will be converted into a JSON dictionary in the response to the web client.

func (*GoDataResponse) Json

func (r *GoDataResponse) Json() ([]byte, error)

Serialize the result as JSON for sending to the client. If an error occurs during the serialization, it will be returned.

type GoDataResponseField

type GoDataResponseField struct {
	Value interface{}
}

A response that is a primitive JSON type or a list or a dictionary. When writing to JSON, it is automatically mapped from the Go type to a suitable JSON data type. Any type can be used, but if the data type is not supported for serialization, then an error is thrown.

func (*GoDataResponseField) Json

func (f *GoDataResponseField) Json() ([]byte, error)

Convert the response field to a JSON serialized form. If the type is not string, []byte, int, float64, map[string]*GoDataResponseField, or []*GoDataResponseField, then an error will be thrown.

type GoDataReturnType

type GoDataReturnType struct {
	XMLName   xml.Name `xml:"ReturnType"`
	Name      string   `xml:"Name,attr"`
	Type      string   `xml:"Type,attr"`
	Nullable  string   `xml:"Nullable,attr,omitempty"`
	MaxLength int      `xml:"MaxLength,attr,omitempty"`
	Precision int      `xml:"Precision,attr,omitempty"`
	Scale     int      `xml:"Scale,attr,omitempty"`
	SRID      string   `xml:"SRID,attr,omitempty"`
}

type GoDataSchema

type GoDataSchema struct {
	XMLName          xml.Name `xml:"Schema"`
	Namespace        string   `xml:"Namespace,attr"`
	Alias            string   `xml:"Alias,attr,omitempty"`
	Actions          []*GoDataAction
	Annotations      []*GoDataAnnotations
	Annotation       []*GoDataAnnotation
	ComplexTypes     []*GoDataComplexType
	EntityContainers []*GoDataEntityContainer
	EntityTypes      []*GoDataEntityType
	EnumTypes        []*GoDataEnumType
	Functions        []*GoDataFunction
	Terms            []*GoDataTerm
	TypeDefinitions  []*GoDataTypeDefinition
}

type GoDataSearchQuery

type GoDataSearchQuery struct {
	Tree *ParseNode
	// The raw search string
	RawValue string
}

func ParseSearchString

func ParseSearchString(filter string) (*GoDataSearchQuery, error)

Convert an input string from the $filter part of the URL into a parse tree that can be used by providers to create a response.

type GoDataSegment

type GoDataSegment struct {
	// The raw segment parsed from the URI
	RawValue string

	// The kind of resource being pointed at by this segment
	SemanticType int

	// A pointer to the metadata type this object represents, as defined by a
	// particular service
	SemanticReference interface{}

	// The name of the entity, type, collection, etc.
	Name string

	// map[string]string of identifiers passed to this segment. If the identifier
	// is not key/value pair(s), then all values will be nil. If there is no
	// identifier, it will be nil.
	Identifier *GoDataIdentifier

	// The next segment in the path.
	Next *GoDataSegment
	// The previous segment in the path.
	Prev *GoDataSegment
}

Represents a segment (slash-separated) part of the URI path. Each segment has a link to the next segment (the last segment precedes nil).

type GoDataSelectQuery

type GoDataSelectQuery struct {
	SelectItems []*SelectItem
	// The raw select string
	RawValue string
}

func ParseSelectString

func ParseSelectString(sel string) (*GoDataSelectQuery, error)

type GoDataService

type GoDataService struct {
	// The base url for the service. Navigating to this URL will display the
	// service document.
	BaseUrl *url.URL
	// The provider for this service that is serving the data to the OData API.
	Provider GoDataProvider
	// Metadata cache taken from the provider.
	Metadata *GoDataMetadata
	// A mapping from schema names to schema references
	SchemaLookup map[string]*GoDataSchema
	// A bottom-up mapping from entity type names to schema namespaces to
	// the entity type reference
	EntityTypeLookup map[string]map[string]*GoDataEntityType
	// A bottom-up mapping from entity container names to schema namespaces to
	// the entity container reference
	EntityContainerLookup map[string]map[string]*GoDataEntityContainer
	// A bottom-up mapping from entity set names to entity collection names to
	// schema namespaces to the entity set reference
	EntitySetLookup map[string]map[string]map[string]*GoDataEntitySet
	// A lookup for entity properties if an entity type is given, lookup
	// properties by name
	PropertyLookup map[*GoDataEntityType]map[string]*GoDataProperty
	// A lookup for navigational properties if an entity type is given,
	// lookup navigational properties by name
	NavigationPropertyLookup map[*GoDataEntityType]map[string]*GoDataNavigationProperty
}

A GoDataService will spawn an HTTP listener, which will connect GoData requests with a backend provider given to it.

func BuildService

func BuildService(provider GoDataProvider, serviceUrl string) (*GoDataService, error)

Create a new service from a given provider. This step builds lookups for all parts of the data model, so constant time lookups can be performed. This step only happens once when the server starts up, so the overall cost is minimal. The given url will be treated as the base URL for all service requests, and used for building context URLs, etc.

func (*GoDataService) GoDataHTTPHandler

func (service *GoDataService) GoDataHTTPHandler(w http.ResponseWriter, r *http.Request)

The default handler for parsing requests as GoDataRequests, passing them to a GoData provider, and then building a response.

func (*GoDataService) ListenAndServe

func (service *GoDataService) ListenAndServe(addr string)

Start the service listening on the given address.

func (*GoDataService) LookupEntitySet

func (service *GoDataService) LookupEntitySet(name string) (*GoDataEntitySet, error)

Lookup an entity set from the service metadata. Accepts a fully qualified name, e.g., ODataService.ContainerName.EntitySetName, ContainerName.EntitySetName or, if unambiguous, accepts a simple identifier, e.g., EntitySetName.

func (*GoDataService) LookupEntityType

func (service *GoDataService) LookupEntityType(name string) (*GoDataEntityType, error)

Lookup an entity type from the service metadata. Accepts a fully qualified name, e.g., ODataService.EntityTypeName or, if unambiguous, accepts a simple identifier, e.g., EntityTypeName.

type GoDataServices

type GoDataServices struct {
	XMLName xml.Name `xml:"edmx:DataServices"`
	Schemas []*GoDataSchema
}

type GoDataSingleton

type GoDataSingleton struct {
	XMLName                    xml.Name `xml:"Singleton"`
	Name                       string   `xml:"Name,attr"`
	Type                       string   `xml:"Type,attr"`
	NavigationPropertyBindings []*GoDataNavigationPropertyBinding
}

type GoDataSkipQuery

type GoDataSkipQuery int

func ParseSkipString

func ParseSkipString(skip string) (*GoDataSkipQuery, error)

type GoDataTerm

type GoDataTerm struct {
	XMLName      xml.Name `xml:"Term"`
	Name         string   `xml:"Name,attr"`
	Type         string   `xml:"Type,attr"`
	BaseTerm     string   `xml:"BaseTerm,attr,omitempty"`
	DefaultValue string   `xml:"DefaultValue,attr,omitempty"`
	AppliesTo    string   `xml:"AppliesTo,attr,omitempty"`
}

type GoDataTopQuery

type GoDataTopQuery int

func ParseTopString

func ParseTopString(top string) (*GoDataTopQuery, error)

type GoDataTypeDefinition

type GoDataTypeDefinition struct {
	XMLName        xml.Name `xml:"TypeDefinition"`
	Name           string   `xml:"Name,attr"`
	UnderlyingType string   `xml:"UnderlyingTypeattr,omitempty"`
	Annotations    []*GoDataAnnotation
}

type Operator

type Operator struct {
	Token string
	// Whether the operator is left/right/or not associative
	Association int
	// The number of operands this operator operates on
	Operands int
	// Rank of precedence
	Precedence int
	// Specifies whether the right-side operand is single value (by default) or multi-value.
	// For example, "City in ('San Jose', 'Chicago', 'Dallas')"
	// For left-side operand, the parser algorithm needs to change to support backtracking.
	MultiValueOperand bool
}

type OrderByItem

type OrderByItem struct {
	Field *Token
	Order string
}

type ParseNode

type ParseNode struct {
	Token    *Token
	Parent   *ParseNode
	Children []*ParseNode
}

type Parser

type Parser struct {
	// Map from string inputs to operator types
	Operators map[string]*Operator
	// Map from string inputs to function types
	Functions map[string]*Function
}

func EmptyParser

func EmptyParser() *Parser

func FilterParser

func FilterParser() *Parser

func SearchParser

func SearchParser() *Parser

func (*Parser) DefineFunction

func (p *Parser) DefineFunction(token string, params []int)

Add a function to the language

func (*Parser) DefineOperator

func (p *Parser) DefineOperator(token string, operands, assoc, precedence int, multiValueOperand bool)

Add an operator to the language. Provide the token, the expected number of arguments, whether the operator is left, right, or not associative, and a precedence. The operandsCardinality specifies whether the operands are single-value or multi-value, which must be a comma-separated list enclosed in parenthesis.

func (*Parser) InfixToPostfix

func (p *Parser) InfixToPostfix(tokens []*Token) (*tokenQueue, error)

Parse the input string of tokens using the given definitions of operators and functions. (Everything else is assumed to be a literal.) Uses the Shunting-Yard algorithm.

func (*Parser) PostfixToTree

func (p *Parser) PostfixToTree(queue *tokenQueue) (*ParseNode, error)

Convert a Postfix token queue to a parse tree

type SelectItem

type SelectItem struct {
	Segments []*Token
}

type Token

type Token struct {
	Value string
	Type  int
	// Holds information about the semantic meaning of this token taken from the
	// context of the GoDataService.
	SemanticType      int
	SemanticReference interface{}
}

type TokenMatcher

type TokenMatcher struct {
	Pattern string         // The regular expression matching a ODATA query token, such as literal value, operator or function
	Re      *regexp.Regexp // The compiled regex
	Token   int
}

type Tokenizer

type Tokenizer struct {
	TokenMatchers  []*TokenMatcher
	IgnoreMatchers []*TokenMatcher
}

func ExpandTokenizer

func ExpandTokenizer() *Tokenizer

func FilterTokenizer

func FilterTokenizer() *Tokenizer

Create a tokenizer capable of tokenizing filter statements

func SearchTokenizer

func SearchTokenizer() *Tokenizer

Create a tokenizer capable of tokenizing filter statements

func (*Tokenizer) Add

func (t *Tokenizer) Add(pattern string, token int)

func (*Tokenizer) Ignore

func (t *Tokenizer) Ignore(pattern string, token int)

func (*Tokenizer) Tokenize

func (t *Tokenizer) Tokenize(target string) ([]*Token, error)

func (*Tokenizer) TokenizeBytes

func (t *Tokenizer) TokenizeBytes(target []byte) ([]*Token, error)

type UnsupportedQueryParameterError

type UnsupportedQueryParameterError struct {
	Parameter string
}

func (*UnsupportedQueryParameterError) Error

func (err *UnsupportedQueryParameterError) Error() string

Directories

Path Synopsis
example
providers