Skip to content
Simon Y. Blackwell edited this page May 3, 2015 · 3 revisions

Introduction

There are only a few functions you need to be familiar with to develop with JOQULAR:

  1. It all starts with JOQULAR.enhance. The enhance function enhances whatever JavaScript constructor you wish to be at the root of matchable and searchable classes. For simplicity, most of the examples in this documentation assume it is Object, but you can make it anything you like. NOTE: If you do make it Object, then data constructed with {} will no longer be an instance of an Object, so be VERY careful. The enhance function will optionally enhance primitive object corollaries (Boolean, etc), Array, Set, and Date to support a normalized set of query predicates listed on the JOQULAR Expressions page. Finally, this call is used to configure data storage (currently only pseudo-blobs in IndexedDB).

  2. Once you have called JOQULAR.enhance any newly created instances and sub-class instances will have available .joqularMatch.

  3. If you turned indexing on with enhance, then JOQULAR.createIndex(constructor) will tell JOQULAR to start indexing instances of a given constructor.

  4. Once you call JOQULAR.createIndex on a constructor, that constructor will have available .joqularFind, .joqularIndex, .joqularSave and joqularLoad. If you configure a database with the enhance call, the methods joqularSave and joqularLoad will also be available.

  5. For convenience, JOQULAR also provides, Time, TimeSpan, and Duration classes.

API

JOQULAR provides a Three Way You Choose API. Almost all functions can return a value synchronously. When an asynch argument is provided as a function with signature function(err, result) { ... }, result is what would have been the return value. When true is provided for the value of asynch, then a Promise is returned that will resolve to what would have been the return value.

JOQULAR.enhance(constructor, config)

.enhance re-writes the passed in constructor and returns a new constructor. See the Internals page for more details on this process.

config has the following structure and keys:

{
enhancePrimitives: true | false,
enhanceArray: true | false,
enhanceSet: true | false,
enhanceDate: true | false,
index: true | false,
datastore: {
   name: <string>,
   type: "IndexedBD", (only value currently supported)
   format: "psuedo-blob" (only value currently supported)
}

enhancePrimitives = true

enhancePrimitives adds the lt, lte, eq, gte, gt to the prototype of Boolean, Number, and String. This slightly improves JOQULAR performance since deep inside all primitives are copied to their object corollaries and these methods are added if not present on the instance.

.lt, .lte, .gt, .gte operate as they would for primitives with <, <=, >=, >.

.eq(value) - True if value!=null && this.valueOf()===value.valueOf(). This is not the same as this==value for primitives because it compares the object references themselves, i.e. new Number(1) !== new Number(1).

enhanceArray = true

enhanceArray adds eq, count, min, max, sum, avg,'stddev_, variance, intersects, disjoint, coincident, contains/includes, excludes, bsearch to the Array prototype.

.eq(value) - True if _value instanceof Array and all elements in the same order are eq.

.count(type) - Returns number of elements of _type where type is a JavaScript type name. Object primitives are are treated like primitives; unless _type equal object. Returns .length if _type==null.

.min(type [,ignoreEnds]) - Returns the minimum element of type type. Type defaults to number if not specified. If ignoreEnds is true and a sorted copy of the array has .length > 2 then the first element is ignored, i.e. the true min is thrown out as an outlier.

.max(type [,ignoreEnds]) - Similar to _min, but returns maximum.

.sum(ignoreEnds) - Returns the sum of all elements of type 'number'. If _ignoreEnds is true and a sorted copy of the array has .length > 2 then the first and last elements are ignored, i.e. the min and max are thrown out.

.avg(ignoreEnds) - Similar to _.sum but returns the average.

.stdev(ignoreEnds) - Similar to _.sum but returns the standard deviation.

.variance(ignoreEnds) - Similar to _.sum but returns the variance.

.intersects(value), _.disjoint(value), _.coincident(value) - Returns true if the _value has the specified relationship to this. _value can be an Array or a Set.

.contains(value), _.includes(value), _.excludes(value) - Return true if the _value has the specified relationship to this. _.contains and _.includes return the same result, they are aliases. Object primitives are coerced down if necessary.

.bsearch(value [, sorter]) - Returns an array representing the start and end offsets of value in the array or [] if not found, e.g. [1,2,2,3].bsearch(2) returns [1,3]. If a sorting function, sorter, is provided, then a copy of the array sorted using sorter is searched.

enhanceSet = true

enhanceSet ensures that the Set prototype is enhanced in the same manner as Array, including the addition of support for every, some, and indexOf. A utility function toArray is also added.

.every(function(item,index) {...}), .some(function(item,index) {...}) - These behave the same way as their Array counterparts, except the item passed in is the [key, value] pair stored in the set, see MDN

.indexOf(value) - Returns the index of the value in the set or -1 if not found.

enhanceDate = true

enhanceDate extends the Date prototype with lt, lte, eq, gte, gt. Each of these can take a precision modifier and also allow comparison to TimeSpans (see TimeSpan documentation below). It also adds before, beforeOrAdjacent, after, afterOrAdjacent, coincident, disjoint, intersects.

The precision modifiers are: "Y" year, "M" month, "h" hour, "m" minute, "s" second, "ms" millisecond.

.lt(value, precision) - Returns true if the date is before value when measured at the provided precision. value can be a Date, Time, TimeSpan or integer representing milliseconds. If value is a TimeSpan then the date must be before the start of the TimeSpan.

.lte(value, precision) - Returns true if the date is before or equal to _value when measured at the provided precision. value can be a Date, Time, TimeSpan or integer representing milliseconds. If _value is a TimeSpan then the date must be before the start of the TimeSpan or equal to its start.

.eq(value, precision) - Dates must be equal at the provided precision. value can be a Date, Time, TimeSpan or integer representing milliseconds. If _value is a TimeSpan, it must be an instant, i.e. start and end at the same time.

.gte(value, precision) - Similar to .lte.

.gt(value, precision)- Similar to _.lt.

_.before, .beforeOrAdjacent, .afterOrAdjacent, .after are all aliased to their counterparts above.

.coincident(value, precision) - Returns true if this.eq(value, precision) or if value is a TimeSpan, value.startingTime and value.endingTime must be equal to the date with the given precision.

.disjoint(value, precision) - Returns true if value is a TimeSpan and the date is before value.startingTime or after the value.endingTime. Or, if value is not a TimeSpan returns the result of this.neq(value).

.intersects(value, precision) - Returns true if this.eq(value, precision) or if value is a TimeSpan, returns true when the date is between value.startingTime and value.endingTime with the given precision.

index = true

The constructor returned from ehance will include the methods joqularFind and joqularIndex_. NOTE: Additionally, regardless of the configuration parameters ehancePrimitives, enhanceArray, enhanceDate will be set to true.

datastore

name - Any string name for the database.

type - Currently the only supported value is "IndexedDB" and it must be provided.

format = "psuedo-blob" - stores everything as two values in the underlying database, a map of unique ids to objects and the index, at the terminal nodes of which are stored arrays of keys. See the Internals page for more detail.

format = "objects" (not yet implemented) - stores objects as separate entities in the underlying database and the index as a single entity. This may cause a performance penalty, but it also means the data can be queried using other means and other database services such as replication can be used.

.joqularMatch(joqularExpression[,asynch])

Returns true if the instance matches the expression, otherwise false. Extremely fast, so using async is provided only for stylistic consistency.

JOQULAR.createIndex(constructor [,autoindex,asynch,name])

Re-writes the constructor and returns a new one.

autoindex - creates the new constructor so that objects are automatically indexed

asynch - creates a constructor that asynchronously indexes, ignored if _autoindex is false. As a result, it will return null or a Promise of a new object not an actual new instance based on the constructor. Be very careful using this option since it is not normal for constructors to return null or Promises.

name - REQUIRED if using Internet Explorer. The re-written constructor uses the same name as the constructor provided as an argument. Internet Explorer does not support the .name attribute on functions, so you must provide it.

.joqularFind(joqularExpression [,waitOrAsynch])

Returns an array of objects as instances of that match the joqularExpression. If waitOrAsynch is a function, it will be called when running indexing operations have complete and the search is complete. If waitOrAsynch is true, a Promise will be returned that will resolve when current indexing operations and the search have completed. .joqularFind is usually fast enough you don’t need to use the asynch flag.

.joqularIndex(object [,asynch])

Adds the object to the index of . The object must either satisfy object instanceof or have as its constructor Object, in which case, when it is retrieved from the index it will be as an instance of . Indexing is very fast and only partial in nature. It is ultimately completed when the first query tries to access the terminal value node of an index. Hence, you can, and we suggest, avoid using the asynch option, your code will be easier to read.

.joqularSave(waitOrAsynch)

Passing in a number will wait the given milliseconds and then return the number of records saved, or -1 if there was timeout. Passing in a function will result in a callback and return null. Passing in true will return a Promise. The callback will get or the Promise will resolve with the record count.

.joqularLoad(waitOrAsynch)

Passing in a number will wait the given milliseconds and then return the number of records saved, or -1 if there was timeout. Passing in a function will result in a callback and return null. Passing in true will return a Promise. The callback will get or the Promise will resolve with the record count.

JOQULAR.Duration Constructor

_JOQULAR.Duration(count, period) - Creates an object whose _.valueOf() method returns the number of milliseconds in _count of _period. Period can be: "Y" year, "M" psuedo-month, "D" day, "h" hour, "m" minute, "s" second, "ms" millisecond. If _period is not provided, it defaults to "ms". "Y" is treated as 365.25 days. "M" is treated as 365.25/12.

The constructor is built dynamically to create sub-class instances of the root constructor returned from JOQULAR.enhance.

Additional undocumented functionality exists on Duration to supported planned temporal enhancements to JOQULAR.

JOQULAR.Time Constructor

JOQULAR.Time(value, precision) - Produces an object that is analogous to a Date with respect to all its methods and adds precision capability. See the Date enhancement documentation above for details on precision. value can be in milliseconds or can be an instance of a Date or Time. The _.valueOf() method returns milliseconds so that Time objects can be used easily in mathematical comparisons.

The constructor is built dynamically to create sub-class instances of the root constructor returned from JOQULAR.enhance.

JOQULAR.TimeSpan Constructor

This class provides the ability to reason about time periods with unspecified starts and ends, e.g. -Infinity and Infinity. TimeSpan supports the set predicates intersects, disjoint, coincident and the adjacency predicates before, adjacentOrBefore, adjacentOrAfter, after.

_JOQULAR.TimeSpan(startingTime [, endingTime]) - Coerces startingTime and endingTime from milliseconds, Date, or Time into a unified internal form. If endingTime is not specified it will be set to Infinity. If startingTime is null or undefined it will be set to -Infinity.