hails- Multi-app web platform framework

Safe HaskellTrustworthy




This module exports the basic types used to create queries and selections. Different from standard MongoDB, Hails queries are limited to SearchableFields (similarly, ordering a query result is limited to such fields) and projections are carried out by this library and not the database. The later is a result of allowing policy modules to express a labeling policy as a function of a document -- hence we cannot determine at compile time if a field is used in a policy and thus must be included in the projection.



class InsertLike doc where Source

Class used to generalize insertion and saving of documents. Specifically, it permits reusing function names when inserting/saving both already-labeled and unlabeled documents. Minimal definition: insertP and saveP.

Minimal complete definition

insertP, saveP


insert :: CollectionName -> doc -> DBAction ObjectId Source

Insert document into collection and return its _id value. When performing an insert it is required that the computation be able to write to both the database and collection. To this end, insert internally applies guardWrite on the database label and collection label. Of course, the computation must be able to name the collection in the database, and thus must be able to read the database collection map as verified by applying taint to the collections label.

When inserting an unlabeled document, all policies must be succesfully applied using applyCollectionPolicyP and the document must be "well-typed" (see applyCollectionPolicyP).

When inserting an already-labeled document, the labels on fields and the document itself are compared against the policy-generated labels. Note that this approach allows an untrusted piece of code to insert a document it could not label according to the policy module.

insert_ :: CollectionName -> doc -> DBAction () Source

Same as insert except it does not return _id

insertP :: DCPriv -> CollectionName -> doc -> DBAction ObjectId Source

Same as insert, but uses privileges when applying the policies and performing label comparisons.

insertP_ :: DCPriv -> CollectionName -> doc -> DBAction () Source

Same as insertP except it does not return the _id.

save :: CollectionName -> doc -> DBAction () Source

Update a document according to its _id value. The IFC requirements subsume those of insert. Specifically, in addition to being able to apply all the policies and requiring that the current label flow to the label of the collection and database, save requires that the current label flow to the label of the existing database record (i.e, the existing document can be overwritten).

saveP :: DCPriv -> CollectionName -> doc -> DBAction () Source

Same as save, but uses privileges when applying the policies and performing label comparisons. Note that a find is performed if the provided document contains an _id field. This lookup does _not_ leak timing information since the _id field is always searchable and thus solely protected by the collection label (which the computation is tainted by).



class Select selectionOrQuery where Source

Class used to simplicy the creation of a 'Selection'/'Query'. Specifically, select can be used to create a Section in a straight foward manner, but similarly can be used to create a Query with a set of default options.


select :: Selector -> CollectionName -> selectionOrQuery Source

Given a selector and collection name create a Query. The resultant type depends on the use case, for example, in find select mySel myCol is a Query, but in delete it is a Selection.

data Selection Source

A Section is a Selector query on a Collection. In other words, a Selection is the necessary information for performing a database query.




selectionSelector :: Selector

Selection query.

selectionCollection :: CollectionName

Collection to perform query on.

type Selector = BsonDocument Source

Filter for a query, analogous to the WHERE clause in SQL. [] matches all documents in collection. For example, [x -: a, y -: b] is analogous to WHERE x = a AND y = b in SQL.

Note: only FieldNames of SearchableFields may be used in selections, and thus all other fields are ignored.


data Query Source

Use select to create a basic query with defaults, then modify if desired. Example: (select sel col) {limit =: 10}. For simplicity, and since policies may be specified in terms of arbitrary fields, The selection and sort fields are restricted to SearchableFields, or the "_id" field that is implicitly a SearchableField.




options :: [QueryOption]

Query options, default [].

selection :: Selection

WHERE clause,default []. Non-SearchableFields ignored.

project :: [FieldName]

The fields to project. Default [] corresponds to all.

skip :: Word32

Number of documents to skip, default 0.

limit :: Limit

Max number of documents to return. Default, 0, means no limit.

sort :: [Order]

Sort result by given order, default []. Non-SearchableFields ignored.

batchSize :: BatchSize

The number of document to return in each batch response from the server. 0 means MongoDB default.

hint :: [FieldName]

Force mongoDB to use this index, default [], no hint. Non-SearchableFields ignored.


data QueryOption :: *



Tailable means cursor is not closed when the last data is retrieved. Rather, the cursor marks the final object's position. You can resume using the cursor later, from where it was located, if more data were received. Like any "latent cursor", the cursor may become invalid at some point – for example if the final object it references were deleted. Thus, you should be prepared to requery on CursorNotFound exception.


The server normally times out idle cursors after 10 minutes to prevent a memory leak in case a client forgets to close a cursor. Set this option to allow a cursor to live forever until it is closed.


Use with TailableCursor. If we are at the end of the data, block for a while rather than returning no data. After a timeout period, we do return as normal. | Exhaust -- ^ Stream the data down full blast in multiple "more" packages, on the assumption that the client will fully read all data queried. Faster when you are pulling a lot of data and know you want to pull it all down. Note: the client is not allowed to not read all the data unless it closes the connection. Exhaust commented out because not compatible with current Pipeline implementation


Get partial results from a _mongos_ if some shards are down, instead of throwing an error.

type Limit = Word32

Maximum number of documents to return, i.e. cursor will close after iterating over this number of documents. 0 means no limit.

type BatchSize = Word32

The number of document to return in each batch response from the server. 0 means use Mongo default.

data Order Source

Sorting fields in Ascending or Descending order.


Asc FieldName

Ascending order

Desc FieldName

Descending order


orderName :: Order -> FieldName Source

Get the field name in the order.


data Cursor Source

A labeled cursor. The cursor is labeled with the join of the database and collection it reads from. The collection policies are "carried" along since they are applied on-demand.

curLabel :: Cursor -> DCLabel Source

Cursor label

find :: Query -> DBAction Cursor Source

Fetch documents satisfying query. A labeled Cursor is returned, which can be used to retrieve the actual HsonDocuments. For this function to succeed the current computation must be able to read from the database and collection (implicilty the database's collection-set). This is satisfied by applying taint to the join join of the collection, database, and ccollection-set label. The curor label is labeled by the upperBound of the database and collection labels and must be used within the same withPolicyModule block.

Note that this function is quite permissive in the queries it accepts. Specifically, any non-SearchableFields used in sort, order, or hint are ignored (as opposed to throwing an exception).

findP :: DCPriv -> Query -> DBAction Cursor Source

Same as find, but uses privileges when reading from the collection and database.

next :: Cursor -> DBAction (Maybe LabeledHsonDocument) Source

Return next HsonDocument in the query result, or Nothing if finished. Note that the current computation must be able to read from the labeled Cursor. To enforce this, next uses taint to raise the current label to join of the current label and 'Cursor'\'s label. The returned document is labeled according to the underlying Collection policy.

nextP :: DCPriv -> Cursor -> DBAction (Maybe LabeledHsonDocument) Source

Same as next, but usess privileges when raising the current label.

findOne :: Query -> DBAction (Maybe LabeledHsonDocument) Source

Fetch the first document satisfying query, or Nothing if not documents matched the query.

findOneP :: DCPriv -> Query -> DBAction (Maybe LabeledHsonDocument) Source

Same as findOne, but uses privileges when performing label comparisons.


deleteP :: DCPriv -> Selection -> DBAction () Source

Same as delete, but uses privileges.

delete :: Selection -> DBAction () Source

Delete documents according to the selection. It must be that the current computation can overwrite the existing documents. That is, the current label must flow to the label of each document that matches the selection.

Query failures

data DBError Source

Exceptions thrown by invalid database queries.



Collection does not exist


Policy module not found

ExecFailure Failure

Execution of action failed

Applying policies

applyCollectionPolicyP Source


:: MonadLIO DCLabel m 
=> DCPriv


-> Collection

Collection and policies

-> HsonDocument

Document to apply policies to

-> m LabeledHsonDocument 

Apply a collection policy the given document, using privileges when labeling the document and performing label comparisons. The labeling proceeds as follows:

  • If two fields have the same FieldName, only the first is kept. This filtering is only perfomed at the top level.
  • Each policy labeled value (HsonLabeled) is labled if the policy has not been applied. If the value is already labeled, then the label is checked to be equivalent to that generated by the policy. In both cases a failure results in PolicyViolation being thrown; the actual error must be hidden to retain the opaqueness of PolicyLabeled.

Note: For each FieldNamed in the policy there must be a field in the document corresponding to it. Moreover its "type" must be correct: all policy labeled values must be HsonLabeled values and all searchable fields must be HsonValues. The _id field is always treated as a SearchableField.

  • The resulting document (from the above step) is labeled according to the collection policy.

The labels on PolicyLabeled values and the document must be bounded by the current label and clearance as imposed by guardAllocP. Additionally, these labels must flow to the label of the collection clearance. (Of course, in both cases privileges are used to allow for more permissive flows.)

Policy errors

data PolicyError Source

A document policy error.


TypeError String

Document is not "well-typed"


Policy has been violated


typeCheckDocument :: Map FieldName FieldPolicy -> HsonDocument -> DC () Source

This function "type-checks" a document against a set of policies. Specifically, it checks that the set of policy labeled values is the same between the policy and document, searchable fields are not policy labeled, and all searchable/policy-labeled fields named in the collection policy are present in the document (except for _id).