multiplexer

package
v0.1.11 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2020 License: MIT Imports: 11 Imported by: 0

README

Multiplexer Internals

This is high level overview of the internals of the multiplexer. The following structure is similar to a definition in Go. The angle bracket tags represent the internal type (type defined and used in the source code). For example, <EMux> declares that the next definition is for the internal type EMux. Similarly, <ptr_Entity> declares that the next definition is for the internally used type *Entity.

<EMux>struct{
    TypeMap  <TypeMap>map[reflect.Type]string
	Entities <EntityMap>map[string]<ptr_metaEntity>*struct{
		EntityID             string
		Entity   <ptr_Entity>*struct{
			SchemaDefinition reflect.Type
			PStorage        *mongo.Collection
		},
		FieldClassifications map[rune][]<ptr_condensedField>*struct{
			Name      string
			Type      reflect.Type
			RequestID string
			Value     interface{}
			Embedded  <Embedding>*struct{
				CFlag bool
				CType reflect.Type
				SFlag bool
				SType reflect.Type
				Meta  <ptr_metaEntity>
			},
		},	
	},
}

Quick Overview

This section provides a short description of the function and intent of every type used in the above structure.

The EMux is the multiplexer itself. It contains 2 fields. An Entities field, which contains a map of strings (which are the EntityIDs) to <ptr_metaEntity>. And an TypeMap is the inverse of the EntityMap. This one maps Entity types (reflect.Type) to a string containing the EntityID of the Entity.

The following narrows down to the Entities field specifically.

The metaEntity type is used to package information about an Entity being managed by the multiplexer. It provides access to pre-computed values to be used for the multiplexer's operations.

Quickly, the EntityID field is a string declaring an Entity's EntityID. Entity is a field which contains a pointer to an Entity type containing the type specifications (reflect.Type) of the Entity, as well as a pointer to the mongoDB collection being used for this Entity (nil if no collection).

The FieldClassifications field is a map mapping a character to a slice of pointers to a condensedFields. This is a short-hand representation of a field, also containing specific information needed by the multiplexer for its operations. The characters (runes) that map to these pointers are reserved tokens which represent a specific classification of a field. For example, currently, the rune '*' is a token which maps to a pointer to the condensedField which provided the EntityID being used.

Name is the field's name and Type is the field's type. RequestID is a string indicating the field's name in JSON payloads. Value stores additional information in special cases (e.g. EntityID).

The Embedded field conatins an Embedding type instance which indicates the nature of nesting for the field. CFlag and SFlag indicate whether the field stores a collection and a struct respectively. The Type analogs of these specify the embedded type and Meta stores a pointer to the metaEntity for that type.

Documentation

Overview

Package multiplexer defines the EMux type which is basically a multiplexer for Entity types.

The main goal is to enable users to be more productive by writing less repetitive boilerplate code for each entity. This is particularly true when writing API handlers for CRUD operations. For example, consider registering a User into the database. The request handler for this purpose would decode a JSON payload from the request and attempt to create and save a User entity instance, which will then be added to the database. When there are many such entities managed within an app, this can become repetitive and make larger changes harder to implement.

The multiplexer is able to handle such cases by providing middleware for pre-processing requests. For example, once the multiplexer has parsed schema definitions, the CreationMiddleware method can be used to generate middleware to pre-process incoming JSON payloads directly into the Entity intended. This way, the user only has to care about WHAT to do with the Entity.

Middleware generation is planned for the four CRUD operations: creation (as described above), retrieval, update and delete operations. This feature has not been fully completed but has been planned for implementation.

Entity definitions are expected to be of kind "struct". This package also makes use of a set of tags which can be used to provide Entity specifications to the multiplexer. These tags are discussed below.

Tags

Here are the eField tags that the EMux uses:

entity.IDTag - This tag is used to give a name to an Entity. This name specifies the mongo.Collection that will be created in the database for an Entity. It is also used by EMux to internally work with Entity types. This value must be unique amongst the Entity types that the EMux manages.

entity.HandleTag - This tag is used to provide configurations for middleware generation. The value for this tag is a string containing configuration tokens. These tokens are single characters (runes) which can be used to classify an eField. For example, the CreationFieldsToken token can be used used to specify which fields should be parsed from an http.Response body for the middleware generation.

entity.AxisTag - This tag is used to specify which fields can be considered to be unique (to an Entity) within a collection. The tag value which indicates that an eField is an axis eField is the string "true"-- all other values are rejected.

entity.IndexTag - This tag is used to specify the fields for which an index needs to be built in the database collection. This is used hand in hand with the entity.Axis tag; in order for a eField's index to be constructed, both these tags have to be set to "true".

Index

Constants

View Source
const (
	/*
		EntityIDToken maps to an array containing a
		single pointer (or none at all) to a condensedField
		whose RequestID is the Entity's EntityID. This is
		used within the creation stage.
	*/
	EntityIDToken rune = '*'
	/*
		AxisFieldToken maps to an array containing fields which
		are tagged as axis fields.
	*/
	AxisFieldToken rune = 'a'
	/*
		CreationFieldsToken maps to an array containing fields
		which were specified to be provided in an http.Request
		for creating an instance of an Entity.
	*/
	CreationFieldsToken rune = 'c'
)

The following constants define the tokens for eField classifications in a metaEntity. These tokens are to be used within the context of the entity.HandleTag.

Variables

HandleTokens defines the set of tokens which can be used in the entity.HandleTag of a struct eField for classification.

Functions

This section is empty.

Types

type EMux

type EMux struct {
	/*
		Entities is a collection of Entities which are
		used in an application.
		In the Entities map, the key is the EntityID.
	*/
	Entities EntityMap
	/*
		TypeMap provides a way of performing a reverse
		lookup for EntityID by a reflect.Type
	*/
	TypeMap TypeMap
}

EMux is a multiplexer for Entities. It is meant to manage multiple Entities within an application. This involves creating and linking a database collection for Entities, generating pre-processing middleware for CRUD requests, and verification.

See the Create function for more information about the EMux initialization.

func Create

func Create(db muxHandle.DBHandler, definitions ...interface{}) (*EMux, error)

Create uses the given definitions to create an EMux which manages the corresponding Entities. The definitions are expected to be an array of empty/zero struct Types. For example, consider the User entity defined in the "Getting Started" section of the documentation of the entity package. In order to create an EMux which manages the User Entity, the following line suffices:

eMux, err := multiplexer.Create(dbPtr, User{})

When internally registering Entities, a unique identifier is needed to refer to Entities. This identifier is called the EntityID and is defined using the IDTag. If the IDTag is not defined for any entity, the multiplexer may not be correctly initialized and an entityErrors.IncompleteEntityMetadata is returned.

Remember, when instantiating an Entity, it is important to have a defined location for persistent storage. In this case, it is a *mongo.Collection. For each definition, a collection in the database is initialized iff the IDTag does NOT start with a "!". The name of the collection created is exactly the same as the definition's EntityID (last IDTag value). Note, also, that the "!" used when avoiding collection creation does NOT could as part of the EntityID.

Entities for which a database collection has been created are then indexed against their axis fields which have been marked for indexing. A field can be specified as an axis field by using the entity.AxisTag while index creation is specified using the entity.IndexTag. Only fields with the AxisTag set to "true" and a non-empty IndexTag are indexed.

func (*EMux) Collection

func (em *EMux) Collection(entityID string) *mongo.Collection

Collection returns a pointer to the underlying mongo.Collection that the entity corresponding to the given entityID is using for persistent storage.

Alternatively, a handle to this collection can be obtained by using the go.mongodb.org/mongo-driver directly with the collection name as the EntityID given.

To modify the options for the collection, the client can use the db pointer used during initialization

func (*EMux) CreationMiddleware

func (em *EMux) CreationMiddleware(entityID string) (func(next http.HandlerFunc) http.HandlerFunc, error)

CreationMiddleware returns middleware which can be used to derive a template of an Entity/CRUD operation from an API request.

The creation fields for the Entity corresponding to the given entityID are used to pre-populate the response context with an pre-populated" Entity.

For each creation eField, the first non-empty value of JSON/BSON/eField name is used to check the incoming request payload for a corresponding value. This means that if the JSONTag is defined for the eField, it will be assumed to be the corresponding eField in the JSON payload. Otherwise, the BSONTag is checked next. If the BSONTag is also empty, the eField's name is used.

The returned function is middleware which can be used on an httprouter.Router so that when a request is received by the client's httprouter.DBHandler, an auto-completed version of the entity is present in the request context.

NOTE: This functionality does not yet support embedding of Entity types. This can be achieved through linking instead. This is a feature which has been planned for implementation.

func (*EMux) E

func (em *EMux) E(entityID string) *entity.Entity

E returns the Entity corresponding to the entityID given.

This Entity can be used normally to carry out CRUD operations for instances of the Entity.

type Embedding added in v0.1.1

type Embedding struct {
	/*
		SFlag is a boolean representing whether a field
		stores an internally managed Entity (kind struct).
	*/
	SFlag bool
	/*
		CFlag is a boolean representing whether a field
		stores collection-type data (slice, array, ...)
	*/
	CFlag bool
	/*
		EmbeddedType specifies the field's embedded type.
	*/
	EmbeddedType reflect.Type
	/*
		Meta is a pointer representing an internal link
		to an internally managed Entity.
	*/
	Meta *metaEntity
}

TODO: merge CType and SType fields; only 1 can be defined at a time

Embedding is a type used to store information about a field's
data type. It contains flags used to indicate whether the field
type is another Entity managed by the multiplexer or whether
it is a collection-kind field.

type EntityMap

type EntityMap map[string]*metaEntity

EntityMap is a type used to store Entities for look-up by their EntityID.

type TypeMap

type TypeMap map[reflect.Type]string

TypeMap is a type used to perform a reverse lookup for an Entity by type of an instance.

Directories

Path Synopsis
Package muxContext defines a simple context that can be used with HTTP requests to easily store multiple pieces of information within the same http.Request context.
Package muxContext defines a simple context that can be used with HTTP requests to easily store multiple pieces of information within the same http.Request context.
Package muxHandle defines an interface which specifies database behaviour required by the multiplexer.
Package muxHandle defines an interface which specifies database behaviour required by the multiplexer.

Jump to

Keyboard shortcuts

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