Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

can-query-logic

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

can-query-logic - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

15

can-query-logic-test.js

@@ -144,2 +144,8 @@ require("./src/comparators/enum-test");

index = algebra.index(
{sort: "-name"},
[{id: 1, name:"g"}, {id: 2, name:"j"}, {id: 3, name:"m"}, {id: 4, name:"s"}].reverse(),
{name: "k"});
equal(index, 2);
index = algebra.index(
{},

@@ -185,1 +191,10 @@ [{id: 1, name:"g"}, {id: 2, name:"j"}, {id: 3, name:"m"}, {id: 4, name:"s"}],

});
QUnit.test("filterMembers with reverse sort", function(){
var sortedMembers = algebra.filterMembers(
{sort: "-name"},
[{id: 1, name:"a"}, {id: 2, name:"z"}, {id: 3, name:"f"}, {id: 4, name:"s"}]);
QUnit.deepEqual(sortedMembers,
[{id: 2, name:"z"}, {id: 4, name:"s"}, {id: 3, name:"f"}, {id: 1, name:"a"}]);
});

46

compat/compat.js
// for can-set compat
var Query = require("../can-query-logic");
var canReflect = require("can-reflect");
var transform = require("can-get/transform/transform");
var transform = require("can-key/transform/transform");
var deleteKey = require("can-key/delete/delete");
var getKey = require("can-key/get/get");
var makeEnum = require("../src/types/make-enum");
var SET = require("../src/set");
var helpers = require("../src/helpers");

@@ -44,2 +47,13 @@ var IsBoolean = function(){

function convertToJSONAPISort(sortPropValue){
var parts = sortPropValue.split(' ');
var isDesc = (parts[1] || '').toLowerCase() === 'desc';
return isDesc ? "-"+parts[0] : parts[0];
}
function convertToLegacySort(value) {
var result = helpers.sortData(value);
return result.desc ? "-"+result.prop : result.prop;
}
var defaultAlgebra;

@@ -270,2 +284,9 @@

sort: function(prop, sortFunc){
/**
* var parts = sortPropValue.split(' ');
return {
prop: parts[0],
desc: (parts[1] || '').toLowerCase() === 'desc'
};
*/
if(!prop) {

@@ -277,15 +298,22 @@ prop = "sort";

}
var hydrateTransfomer = {};
hydrateTransfomer["filter."+prop] = "sort";
var serializeTransformer = {
"sort": prop
};
return {
hydrate: function(raw){
return transform(raw, hydrateTransfomer);
var clone = canReflect.serialize(raw);
var sort = getKey(clone,"filter."+prop);
if(sort !== undefined) {
deleteKey(clone,"filter."+prop);
clone.sort = convertToJSONAPISort(sort);
}
return clone;
},
serialize: function(raw){
// TODO: fix bug in transform so it doesn't delete props
return prop === "sort" ? raw : transform(raw, serializeTransformer);
var clone = canReflect.serialize(raw);
var sort = clone.sort;
if(sort !== undefined) {
delete clone.sort;
clone[prop] = convertToLegacySort(sort);
}
return clone;
}

@@ -292,0 +320,0 @@ };

128

doc/can-query-logic.md

@@ -53,3 +53,3 @@ @module {function} can-query-logic

},
sort: "name desc",
sort: "-name",
page: {start: 0, end: 19}

@@ -73,3 +73,3 @@ },[

// Sort the results of the selection
sort: "name desc",
sort: "-name",
// Selects a range of the sorted result

@@ -97,3 +97,3 @@ page: {start: 0, end: 19}

```js
new Query({
new QueryLogic({
// keys that uniquely represent this type

@@ -110,5 +110,5 @@ identity: ["id"],

By default, filter properties like `status` in `{filter: {status: "complete"}}`
are hydrated to one of the [can-query/types/comparisons comparison types] like
are used to create to one of the [can-query/types/comparisons comparison instances] like
`GreaterThan`. A matching schema key will overwrite this behavior. How this
works is explained in the _Special Comparison Logic_ section below.
works is explained in the [Defining filter properties with special logic](#Definingfilterpropertieswithspeciallogic) section below.

@@ -123,4 +123,3 @@ @param {Object} [options] The following _optional_ options are used to translate

The _Special Comparison Logic_ section below describes how to use these
options to match your query's logic to your servers.
The [Changing the query structure](#Changingthequerystructure) section below describes how to use these options to match your query's logic to your servers.

@@ -143,6 +142,7 @@

```
/api/todos?filter[complete]=true&sort=name+asc
/api/todos?filter[complete]=true&sort=name
```
The values after the `?` are used to control the data that comes back. Those values [can-deparam]-ed into
The values after the `?` are used to control the data that comes back. Those values are
[can-deparam deserialized] into
a query object look like this:

@@ -153,8 +153,7 @@

filter: {complete: true},
sort: "name asc"
sort: "name"
}
```
This object represents a [can-query-logic/query Query]. This specific query indicates to
request completed todos and have the todos sorted by their _name_.
This object represents a [can-query-logic/query Query]. This specific query is for requesting completed todos and have the todos sorted by their _name_.

@@ -183,6 +182,23 @@ A `QueryLogic` instance _understands_ what a `Query` represents. For example, it can filter items

A [can-query-logic.prototype.isMember] to see if a particular item
belongs to a query and [can-query-logic.prototype.index] to get the location where that
item should be inserted. This is particularly useful for creating real-time behaviors.
The [can-query-logic.prototype.filterMembers] method allows `QueryLogic` to be used similar to a database. `QueryLogic` instances methods help solve other problems too:
- __real-time__ - [can-query-logic.prototype.isMember] returns if a particular item
belongs to a query and [can-query-logic.prototype.index] returns the location where that item belongs.
- __caching__ - [can-query-logic.prototype.isSubset] can tell you if you've already loaded
data you are looking for. [can-query-logic.prototype.difference] can tell you what data
you need to load that already isn't in your cache.
In fact, `can-query-logic`'s most unique ability is to be able to directly compare
queries that represent sets of data instead of having to compare
the data itself. For example, if you already loaded all completed todos,
`can-query-logic` can tell you how to get all remaining todos:
```js
var completedTodosQuery = {filter: {complete: false}};
var allTodosQuery = {};
var remainingTodosQuery = queryLogic.difference(allTodosQuery, completedTodosQuery);
remainingTodosQuery //-> {filter: {complete: {$ne: false}}}
```
## Use

@@ -214,6 +230,6 @@

filter: {
complete: false
complete: {$in: [false, null]}
},
// Sort the results of the selection
sort: "name desc",
sort: "-name",
// Selects a range of the sorted result

@@ -224,8 +240,13 @@ page: {start: 0, end: 19}

This structures follows the [Fetching Data JSONAPI specification](http://jsonapi.org/format/#fetching).
There's:
- a `filter` property for filtering records,
- a `sort` property for specifying the order to sort records, and
- a `page` property that selects a range of the sorted result.
- a [filter](http://jsonapi.org/format/#fetching-filtering) property for filtering records,
- a [sort](http://jsonapi.org/format/#fetching-sorting) property for specifying the order to sort records, and
- a [page](http://jsonapi.org/format/#fetching-pagination) property that selects a range of the sorted result. _The range indexes are inclusive_.
> __NOTE__: [can-connect] does not follow the rest of the JSONAPI specification. Specifically
> [can-connect] expects your server to send back JSON data in a different format.
If you control the service layer, we __encourage__ you to make it match the default

@@ -307,6 +328,9 @@ [can-query-logic/query]. The default query structure also supports the following [can-query-logic/comparison-operators]: `$eq`, `$gt`, `$gte`, `$in`, `$lt`, `$lte`, `$ne`, `$nin`.

```js
// 1. DEFINE YOUR TYPE
// DEFINE YOUR TYPE
const Todo = DefineMap.extend({...});
// CREATE YOUR QUERY LOGIC
var todoQueryLogic = new QueryLogic(Todo, {
// Takes what your service expects: {where: {...}}
// Returns what QueryLogic expects: {filter: {...}}
toQuery(params){

@@ -318,2 +342,4 @@ var where = params.where;

},
// Takes what QueryLogic expects: {filter: {...}}
// Returns what your service expects: {where: {...}}
toParams(query){

@@ -327,3 +353,3 @@ var where = query.filter;

// 2. CREATE YOUR CONNECTION
// PASS YOUR QueryLogic TO YOUR CONNECTION
realTimeRest({

@@ -340,3 +366,3 @@ url: "/todos",

If the logic of the [can-query-logic/query default query] is not adequate to represent
the behavior of your service layer queries, you can define special behaviors called `SetType`s to
the behavior of your service layer queries, you can define special classes called `SetType`s to
provide the additional logic.

@@ -348,6 +374,4 @@

Before reading the following sections, it's useful to have some background information on
how `can-query-logic` works.
how `can-query-logic` works. We suggest reading the [How it works](#Howitworks) section.
`can-query-logic` uses [set theory](https://en.wikipedia.org/wiki/Set_theory)
#### Built-in special types

@@ -373,8 +397,13 @@

const todoLogic = new QueryLogic(Todo);
todoLogic.union(
var unionQuery = todoLogic.union(
{filter: {status: ["new","assigned"] }},
{filter: {status: "complete" }}
) //-> {}
)
unionQuery //-> {}
```
> NOTE: `unionQuery` is empty because if we loaded all todos that
> are new, assigned, and complete, we've loaded every todo.
> The `{}` query would load every todo.

@@ -507,24 +536,36 @@ #### Custom types that work with the comparison operators

QueryLogic.defineComparison(SearchableStringSet,SearchableStringSet,{
// Return a set that would load all items in searchA and searchB.
union(searchA, searchB){
// if searchA's text contains searchB's text, then
// If searchA's text contains searchB's text, then
// searchB will include searchA's results.
if(searchA.value.includes(searchB.value)) {
// A:`food` ∪ B:`foo` => `foo`
return searchB;
}
if(searchB.value.includes(searchA.value)) {
// A:`foo` ∪ B:`food` => `foo`
return searchA;
}
// A:`ice` ∪ B:`cream` => `ice` || `cream`
return new QueryLogic.Or([searchA, searchB]);
},
// Return a set that would load items shared by searchA and searchB.
intersection(searchA, searchB){
// if searchA's text contains searchB's text, then
// If searchA's text contains searchB's text, then
// searchA is the shared search results.
if(searchA.value.includes(searchB.value)) {
// A:`food` ∩ B:`foo` => `food`
return searchA;
}
if(searchB.value.includes(searchA.value)) {
// A:`foo` ∩ B:`food` => `food`
return searchB;
}
// A:`ice` ∩ B:`cream` => `ice` && `cream`
// But there is no `QueryLogic.AndValues`,
// So we return `UNDEFINABLE`.
return QueryLogic.UNDEFINABLE;
},
// Return a set that would load items in searchA that are not in
// searchB.
difference(searchA, searchB){

@@ -534,2 +575,3 @@ // if searchA's text contains searchB's text, then

if(searchA.value.includes(searchB.value)) {
// A:`food` \ B:`foo` => ∅
return QueryLogic.EMPTY;

@@ -541,7 +583,11 @@ }

if(searchB.value.includes(searchA.value)) {
// A:`foo` \ B:`food` => UNDEFINABLE
return QueryLogic.UNDEFINABLE;
}
// A:`ice` \ B:`cream` => `ice` && !`cream`
// If there's another situation, we
// aren't able to tell if there is a difference.
return QueryLogic.UNKNOWABLE;
// aren't able to express the difference
// so we return UNDEFINABLE.
return QueryLogic.UNDEFINABLE;
}

@@ -632,3 +678,3 @@ });

[can-define/map/map]'s expose this type information as a schema:
[can-define/map/map]s expose this type information as a schema:

@@ -661,3 +707,3 @@ ```js

The queries (ex: `{ filter: {name: "assigned"} }`) are hydrated to set types like:
The queries (ex: `{ filter: {name: "assigned"} }`) are hydrated to `SetType`s like:

@@ -672,2 +718,6 @@ ```js

> NOTE: __hydrated__ is the opposite of serialization. It means we take
> a plain JavaScript object like `{ filter: {name: "assigned"} }` and
> create instances of types with it.
The following is a more complex query and what it gets hydrated to:

@@ -681,3 +731,3 @@

},
sort: "name desc",
sort: "-name",
page: {start: 0, end: 9}

@@ -691,3 +741,3 @@ }

}),
sort: "name desc",
sort: "-name",
page: new RealNumberRangeInclusive(0,9)

@@ -721,2 +771,6 @@ });

`can-query-logic`s methods reflect [set theory](https://en.wikipedia.org/wiki/Set_theory)
operations. That's why most types need a `union`, `intersection`, and `difference`
method. With that, other methods like `isEqual` and `isSubset` can be derived.
In this case, `set.union` will call `BasicQuery`'s union with

@@ -754,2 +808,2 @@ itself. This will see that the `sort` and `page` results match

And this is what is returned as a result of the union.
The serialized output above is what is returned as a result of the union.
{
"name": "can-query-logic",
"version": "0.2.0",
"version": "0.3.0",
"description": "query data",

@@ -49,3 +49,3 @@ "homepage": "",

"can-define-lazy-value": "^1.0.2",
"can-get": "<2.0.0",
"can-key": "<2.0.0",
"can-reflect": "^1.13.3",

@@ -52,0 +52,0 @@ "can-symbol": "^1.6.1"

@@ -46,7 +46,7 @@ var helpers = {

sortData: function (sortPropValue) {
var parts = sortPropValue.split(' ');
return {
prop: parts[0],
desc: (parts[1] || '').toLowerCase() === 'desc'
};
if(sortPropValue[0] === "-") {
return {prop: sortPropValue.slice(1), desc: true};
} else {
return {prop: sortPropValue, desc: false};
}
},

@@ -53,0 +53,0 @@ sorter: function (sortPropValue) {

@@ -109,3 +109,3 @@ var canSymbol = require("can-symbol");

if(basicQuery.sort !== id+" ASC") {
if(basicQuery.sort !== id) {
res.sort = basicQuery.sort;

@@ -149,3 +149,3 @@ }

} else {
query.sort = id+" ASC";
query.sort = id;
}

@@ -152,0 +152,0 @@ return new BasicQuery(query);

@@ -5,3 +5,3 @@ var set = require("../set");

var canReflect = require("can-reflect");
var canGet = require("can-get");
var canGet = require("can-key/get/get");
var canSymbol = require("can-symbol");

@@ -8,0 +8,0 @@

@@ -71,3 +71,3 @@ var BasicQuery = require("./basic-query");

page: new BasicQuery.RecordRange(1,3),
sort: 'note AsC'
sort: 'note'
});

@@ -98,3 +98,3 @@ var res = query.filterFrom(items);

page: new BasicQuery.RecordRange(1,3),
sort: 'note deSc'
sort: '-note'
});

@@ -101,0 +101,0 @@ var res = query.filterFrom(items);

@@ -28,3 +28,3 @@ var set = require("../set");

if(!this.sort) {
this.sort = "id ASC";
this.sort = "id";
}

@@ -31,0 +31,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc