package module
Version: v1.0.5 Latest Latest

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

Go to latest
Published: Nov 11, 2021 License: MIT Imports: 11 Imported by: 11


Go golangci-lint


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.


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.




View Source
const (
	ALLPAGES = "allpages"
	NONE     = "none"
View Source
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"
View Source
const (
	ASC  = "asc"
	DESC = "desc"
View Source
const (
	OpAssociationLeft int = iota
View Source
const (
	TokenListExpr = "list"

	// TokenComma is the default separator for function arguments.
	TokenComma      = ","
	TokenOpenParen  = "("
	TokenCloseParen = ")"
View Source
const (
	ODataFieldContext string = "@odata.context"
	ODataFieldCount   string = "@odata.count"
	ODataFieldValue   string = "value"


View Source
var GlobalExpandTokenizer = ExpandTokenizer()
View Source
var GlobalExpressionParser = NewExpressionParser()
View Source
var GlobalExpressionTokenizer = NewExpressionTokenizer()
View Source
var GlobalFilterParser = NewExpressionParser()
View Source
var GlobalFilterTokenizer = NewExpressionTokenizer()
View Source
var GlobalSearchParser = SearchParser()
View Source
var GlobalSearchTokenizer = SearchTokenizer()


func ParseExpandOption

func ParseExpandOption(ctx context.Context, queue *tokenQueue, item *ExpandItem) error

func ParseName

func ParseName(segment string) string

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 SemanticizeSelectQuery

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

func WithOdataComplianceConfig added in v1.0.5

func WithOdataComplianceConfig(ctx context.Context, cfg OdataComplianceConfig) context.Context

If the lenient mode is set, the 'failOnConfig' bits are used to determine the ODATA compliance. This is mostly for historical reasons because the original parser had compliance issues. If the lenient mode is not set, the parser returns an error.


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(ctx context.Context, input tokenQueue) (*ExpandItem, error)

type ExpandTokenType added in v1.0.5

type ExpandTokenType int
const (
	ExpandTokenOpenParen ExpandTokenType = iota

func (ExpandTokenType) Value added in v1.0.5

func (e ExpandTokenType) Value() int

type ExpressionParser added in v1.0.5

type ExpressionParser struct {
	ExpectBoolExpr bool // Request expression to validate it is a boolean expression.
	// contains filtered or unexported fields

ExpressionParser is a ODATA expression parser.

func NewExpressionParser added in v1.0.5

func NewExpressionParser() *ExpressionParser

func (*ExpressionParser) ParseExpressionString added in v1.0.5

func (p *ExpressionParser) ParseExpressionString(ctx context.Context, expression string) (*GoDataExpression, error)

ParseExpressionString converts a ODATA expression input string into a parse tree that can be used by providers to create a response. Expressions can be used within $filter and $orderby query options.

func (*ExpressionParser) ParseOrderByString added in v1.0.5

func (p *ExpressionParser) ParseOrderByString(ctx context.Context, orderby string) (*GoDataOrderByQuery, error)

The value of the $orderby System Query option contains a comma-separated list of expressions whose primitive result values are used to sort the items. The service MUST order by the specified property in ascending order. 4.01 services MUST support case-insensitive values for asc and desc.

func (*ExpressionParser) SemanticizeExpression added in v1.0.5

func (p *ExpressionParser) SemanticizeExpression(
	expression *GoDataExpression,
	service *GoDataService,
	entity *GoDataEntityType,
) error

type ExpressionTokenType added in v1.0.5

type ExpressionTokenType int
const (
	ExpressionTokenOpenParen        ExpressionTokenType = iota // Open parenthesis - parenthesis expression, list expression, or path segment selector.
	ExpressionTokenCloseParen                                  // Close parenthesis
	ExpressionTokenWhitespace                                  // white space token
	ExpressionTokenNav                                         // Property navigation
	ExpressionTokenColon                                       // Function arg separator for 'any(v:boolExpr)' and 'all(v:boolExpr)' lambda operators
	ExpressionTokenComma                                       // [5] List delimiter and function argument delimiter.
	ExpressionTokenLogical                                     // eq|ne|gt|ge|lt|le|and|or|not|has|in
	ExpressionTokenOp                                          // add|sub|mul|divby|div|mod
	ExpressionTokenFunc                                        // Function, e.g. contains, substring...
	ExpressionTokenLambdaNav                                   // "/" token when used in lambda expression, e.g. tags/any()
	ExpressionTokenLambda                                      // [10] any(), all() lambda functions
	ExpressionTokenNull                                        //
	ExpressionTokenIt                                          // The '$it' token
	ExpressionTokenRoot                                        // The '$root' token
	ExpressionTokenFloat                                       // A floating point value.
	ExpressionTokenInteger                                     // [15] An integer value
	ExpressionTokenString                                      // SQUOTE *( SQUOTE-in-string / pchar-no-SQUOTE ) SQUOTE
	ExpressionTokenDate                                        // A date value
	ExpressionTokenTime                                        // A time value
	ExpressionTokenDateTime                                    // A date-time value
	ExpressionTokenBoolean                                     // [20]
	ExpressionTokenLiteral                                     //
	ExpressionTokenDuration                                    // duration      = [ "duration" ] SQUOTE durationValue SQUOTE
	ExpressionTokenGuid                                        // A 128-bit GUID
	ExpressionTokenAssignement                                 // The '=' assignement for function arguments.
	ExpressionTokenGeographyPolygon                            // [25]
	ExpressionTokenGeometryPolygon                             //


func (ExpressionTokenType) String added in v1.0.5

func (e ExpressionTokenType) String() string

func (ExpressionTokenType) Value added in v1.0.5

func (e ExpressionTokenType) Value() int

type Function

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

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(ctx context.Context, 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(ctx context.Context, 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(ctx context.Context, expand string) (*GoDataExpandQuery, error)

type GoDataExpression added in v1.0.5

type GoDataExpression struct {
	Tree *ParseNode
	// The raw string representing an expression
	RawValue string

GoDataExpression encapsulates the tree representation of an expression as defined in the OData ABNF grammar.

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(ctx context.Context, filter string) (*GoDataFilterQuery, error)

ParseFilterString converts 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(ctx context.Context, 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)

func (*GoDataMetadata) String

func (t *GoDataMetadata) String() string

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(ctx context.Context, 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 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  RequestKind

func ParseRequest

func ParseRequest(ctx context.Context, path string, query url.Values) (*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.

func (*GoDataRequest) ParseUrlPath added in v1.0.5

func (req *GoDataRequest) ParseUrlPath(path string) error

func (*GoDataRequest) ParseUrlQuery added in v1.0.5

func (req *GoDataRequest) ParseUrlQuery(ctx context.Context, query url.Values) error

ParseUrlQuery parses the URL query, applying optional logic specified in the context.

func (*GoDataRequest) SemanticizeRequest added in v1.0.5

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

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

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(ctx context.Context, 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 SemanticType

	// 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(ctx context.Context, 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(ctx context.Context, 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(ctx context.Context, 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 ListExprToken added in v1.0.5

type ListExprToken int
const (
	// TokenTypeListExpr represents a parent node for a variadic listExpr.
	// "list"
	//   "item1"
	//   "item2"
	//   ...
	TokenTypeListExpr ListExprToken = iota
	// TokenTypeArgCount is used to specify the number of arguments of a function or listExpr
	// This is used to handle variadic functions and listExpr.

func (ListExprToken) String added in v1.0.5

func (l ListExprToken) String() string

func (ListExprToken) Value added in v1.0.5

func (l ListExprToken) Value() int

type OdataComplianceConfig added in v1.0.5

type OdataComplianceConfig int
const (
	ComplianceStrict OdataComplianceConfig = 0
	// Ignore duplicate ODATA keywords in the URL query.
	ComplianceIgnoreDuplicateKeywords OdataComplianceConfig = 1 << iota
	// Ignore unknown ODATA keywords in the URL query.
	// Ignore extraneous comma as the last character in a list of function arguments.
	ComplianceIgnoreAll OdataComplianceConfig = ComplianceIgnoreDuplicateKeywords |
		ComplianceIgnoreUnknownKeywords |

type Operator

type Operator struct {
	Token string
	// Whether the operator is left/right/or not associative.
	// Determines how operators of the same precedence are grouped in the absence of parentheses.
	Association int
	// The number of operands this operator operates on
	Operands int
	// Rank of precedence. A higher value indicates higher precedence.
	Precedence int
	// Determine if the operands should be interpreted as a ListExpr or parenExpr according
	// to ODATA ABNF grammar.
	// This is only used when a listExpr has zero or one items.
	// When a listExpr has 2 or more items, there is no ambiguity between listExpr and parenExpr.
	// For example:
	//    2 + (3) ==> the right operand is a parenExpr.
	//    City IN ('Seattle', 'Atlanta') ==> the right operand is unambiguously a listExpr.
	//    City IN ('Seattle') ==> the right operand should be a listExpr.
	PreferListExpr bool

func (*Operator) WithListExprPreference added in v1.0.5

func (o *Operator) WithListExprPreference(v bool) *Operator

type OrderByItem

type OrderByItem struct {
	Field *Token            // The raw value of the orderby field or expression.
	Tree  *GoDataExpression // The orderby expression parsed as a tree.
	Order string            // Ascending or descending order.

type ParseNode

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

func (*ParseNode) String

func (p *ParseNode) String() string

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

	LiteralToken TokenType

func EmptyParser

func EmptyParser() *Parser

func SearchParser

func SearchParser() *Parser

func (*Parser) DefineFunction

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

DefineFunction adds a function to the language params is the number of parameters this function accepts

func (*Parser) DefineOperator

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

DefineOperator adds 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.

func (*Parser) InfixToPostfix

func (p *Parser) InfixToPostfix(ctx context.Context, tokens []*Token) (*tokenQueue, error)

InfixToPostfix parses 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.

Infix notation for variadic functions and operators: f ( a, b, c, d ) Postfix notation with wall notation: | a b c d f Postfix notation with count notation: a b c d 4 f

func (*Parser) PostfixToTree

func (p *Parser) PostfixToTree(ctx context.Context, queue *tokenQueue) (*ParseNode, error)

PostfixToTree converts a Postfix token queue to a parse tree

func (*Parser) WithLiteralToken added in v1.0.5

func (p *Parser) WithLiteralToken(token TokenType) *Parser

type RequestKind added in v1.0.5

type RequestKind int
const (
	RequestKindUnknown RequestKind = iota

type SearchTokenType added in v1.0.5

type SearchTokenType int
const (
	SearchTokenLiteral SearchTokenType = iota

func (SearchTokenType) Value added in v1.0.5

func (s SearchTokenType) Value() int

type SelectItem

type SelectItem struct {
	Segments []*Token

type SemanticType

type SemanticType int
const (
	SemanticTypeUnknown SemanticType = iota

type Token

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

type TokenHandler added in v1.0.5

type TokenHandler func(token *Token, stack tokenStack) error

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           TokenType              // The token identifier
	CaseInsensitive bool                   // Regex is case-insensitive
	Subst           func(in string) string // A function that substitutes the raw input token with another representation. By default it is the identity.

type TokenType added in v1.0.5

type TokenType interface {
	Value() int

TokenType is the interface that must be implemented by all token types.

type Tokenizer

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

func ExpandTokenizer

func ExpandTokenizer() *Tokenizer

func NewExpressionTokenizer added in v1.0.5

func NewExpressionTokenizer() *Tokenizer

ExpressionTokenizer creates a tokenizer capable of tokenizing ODATA expressions. 4.01 Services MUST support case-insensitive operator names. See https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#_Toc31360955

func SearchTokenizer

func SearchTokenizer() *Tokenizer

Create a tokenizer capable of tokenizing filter statements

func (*Tokenizer) Add

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

func (*Tokenizer) AddWithSubstituteFunc

func (t *Tokenizer) AddWithSubstituteFunc(pattern string, token TokenType, subst func(string) string)

func (*Tokenizer) Ignore

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

func (*Tokenizer) Tokenize

func (t *Tokenizer) Tokenize(ctx context.Context, target string) ([]*Token, error)

func (*Tokenizer) TokenizeBytes

func (t *Tokenizer) TokenizeBytes(ctx context.Context, target []byte) ([]*Token, error)

TokenizeBytes takes the input byte array and returns an array of tokens. Return an empty array if there are no tokens.

type UnsupportedQueryParameterError

type UnsupportedQueryParameterError struct {
	Parameter string

func (*UnsupportedQueryParameterError) Error


Path Synopsis

Jump to

Keyboard shortcuts

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