Skip to content

Commit 64d65d8

Browse files
author
mdkwock
committed
Implemented LIKE operator with escape char for PropertyFilter coresmart#145 - Jaux
1 parent 475740c commit 64d65d8

File tree

3 files changed

+138
-59
lines changed

3 files changed

+138
-59
lines changed

lib/persistence.js

Lines changed: 96 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,37 @@
2424
*/
2525

2626
if (typeof exports !== 'undefined') {
27-
exports.createPersistence = function() {
28-
return initPersistence({})
29-
}
30-
var singleton;
31-
if (typeof (exports.__defineGetter__) === 'function') {
32-
exports.__defineGetter__("persistence", function () {
33-
if (!singleton)
34-
singleton = exports.createPersistence();
35-
return singleton;
36-
});
37-
} else {
38-
Object.defineProperty(exports, "persistence", {
39-
get: function () {
40-
if (!singleton)
41-
singleton = exports.createPersistence();
42-
return singleton;
43-
},
44-
enumerable: true, configurable: true
45-
});
46-
}
27+
exports.createPersistence = function() {
28+
return initPersistence({});
29+
};
30+
var singleton;
31+
if (typeof (exports.__defineGetter__) === 'function') {
32+
exports.__defineGetter__("persistence", function () {
33+
if (!singleton)
34+
singleton = exports.createPersistence();
35+
return singleton;
36+
});
37+
} else {
38+
Object.defineProperty(exports, "persistence", {
39+
get: function () {
40+
if (!singleton)
41+
singleton = exports.createPersistence();
42+
return singleton;
43+
},
44+
enumerable: true, configurable: true
45+
});
46+
}
4747

4848
}
4949
else {
50-
window = window || {};
51-
window.persistence = initPersistence(window.persistence || {});
50+
window = window || {};
51+
window.persistence = initPersistence(window.persistence || {});
5252
}
5353

5454

5555
function initPersistence(persistence) {
56-
if (persistence.isImmutable) // already initialized
57-
return persistence;
56+
if (persistence.isImmutable) // already initialized
57+
return persistence;
5858

5959
/**
6060
* Check for immutable fields
@@ -104,7 +104,7 @@ persistence.get = function(arg1, arg2) {
104104
(function () {
105105
var entityMeta = {};
106106
var entityClassCache = {};
107-
persistence.getEntityMeta = function() { return entityMeta; }
107+
persistence.getEntityMeta = function() { return entityMeta; };
108108

109109
// Per-session data
110110
persistence.trackedObjects = {};
@@ -137,7 +137,7 @@ persistence.get = function(arg1, arg2) {
137137
} else {
138138
this.globalPropertyListeners[key] = [coll];
139139
}
140-
}
140+
};
141141

142142
persistence.unsubscribeFromGlobalPropertyListener = function(coll, entityName, property) {
143143
var key = entityName + '__' + property;
@@ -148,7 +148,7 @@ persistence.get = function(arg1, arg2) {
148148
return;
149149
}
150150
}
151-
}
151+
};
152152

153153
persistence.propertyChanged = function(obj, property, oldValue, newValue) {
154154
if(!this.trackedObjects[obj.id]) return; // not yet added, ignore for now
@@ -169,7 +169,7 @@ persistence.get = function(arg1, arg2) {
169169
}
170170
}
171171
}
172-
}
172+
};
173173

174174
persistence.objectRemoved = function(obj) {
175175
var entityName = obj._type;
@@ -184,7 +184,7 @@ persistence.get = function(arg1, arg2) {
184184
}
185185
}
186186
}
187-
}
187+
};
188188

189189
/**
190190
* Retrieves metadata about entity, mostly for internal use
@@ -247,7 +247,7 @@ persistence.get = function(arg1, arg2) {
247247
*/
248248
persistence.isDefined = function (entityName) {
249249
return !!entityMeta[entityName];
250-
}
250+
};
251251

252252
/**
253253
* Define a mixin
@@ -745,7 +745,7 @@ persistence.get = function(arg1, arg2) {
745745
}, function() {
746746
callback(item);
747747
});
748-
}; // End of buildJson
748+
} // End of buildJson
749749

750750
Entity.prototype.fetch = function(tx, rel, callback) {
751751
var args = argspec.getArgs(arguments, [
@@ -932,7 +932,7 @@ persistence.get = function(arg1, arg2) {
932932
Entity.all(session).filter(property, "=", value).one(tx, function(obj) {
933933
callback(obj);
934934
});
935-
}
935+
};
936936

937937

938938
Entity.index = function(cols,options) {
@@ -991,7 +991,7 @@ persistence.get = function(arg1, arg2) {
991991
if (meta.isMixin)
992992
otherMeta.fields[invRel + "_class"] = persistence.typeMapper ? persistence.typeMapper.classNameType : "TEXT";
993993
}
994-
}
994+
};
995995

996996
Entity.hasOne = function (refName, otherEntity, inverseProperty) {
997997
meta.hasOne[refName] = {
@@ -1024,7 +1024,7 @@ persistence.get = function(arg1, arg2) {
10241024
meta.hasMany[it] = mixinMeta.hasMany[it];
10251025
}
10261026
}
1027-
}
1027+
};
10281028

10291029
// Allow decorator functions to add more stuff
10301030
var fns = persistence.entityDecoratorHooks;
@@ -1327,6 +1327,44 @@ persistence.get = function(arg1, arg2) {
13271327
}
13281328
}
13291329

1330+
function stringLike(s, pattern, escapeChar) {
1331+
escapeChar = escapeChar || '';
1332+
1333+
function isSpecial(c) {
1334+
return c === '%' || c === '_';
1335+
}
1336+
1337+
function isEscapeChar(c) {
1338+
return escapeChar && c === escapeChar;
1339+
}
1340+
1341+
function patternToRe() {
1342+
var re = '^';
1343+
var c;
1344+
for (var i = 0, len = pattern.length; i < len; i++) {
1345+
c = pattern[i];
1346+
if (isEscapeChar(c)) {
1347+
c = pattern[i + 1];
1348+
if (isSpecial(c) || isEscapeChar(c)) {
1349+
re += c;
1350+
i++;
1351+
}
1352+
} else if (isSpecial(c)) {
1353+
re += '.';
1354+
if (c === '%') {
1355+
re += '*';
1356+
}
1357+
} else {
1358+
re += '[' + c + ']';
1359+
}
1360+
}
1361+
re += '$';
1362+
return new RegExp(re, 'i');
1363+
}
1364+
1365+
return patternToRe().test(s);
1366+
}
1367+
13301368
////////////////// QUERY COLLECTIONS \\\\\\\\\\\\\\\\\\\\\\\
13311369

13321370
function Subscription(obj, eventType, fn) {
@@ -1496,10 +1534,11 @@ persistence.get = function(arg1, arg2) {
14961534
* @param operator the operator to compare with
14971535
* @param value the literal value to compare to
14981536
*/
1499-
function PropertyFilter (property, operator, value) {
1537+
function PropertyFilter (property, operator, value, escapeChar) {
15001538
this.property = property;
15011539
this.operator = operator.toLowerCase();
15021540
this.value = value;
1541+
this.escapeChar = escapeChar;
15031542
}
15041543

15051544
PropertyFilter.prototype.match = function (o) {
@@ -1537,6 +1576,12 @@ persistence.get = function(arg1, arg2) {
15371576
case 'not in':
15381577
return !arrayContains(value, propValue);
15391578
break;
1579+
case 'like':
1580+
return stringLike(propValue, value, this.escapeChar);
1581+
break;
1582+
case 'not like':
1583+
return !stringLike(propValue, value, this.escapeChar);
1584+
break;
15401585
}
15411586
};
15421587

@@ -1593,7 +1638,7 @@ persistence.get = function(arg1, arg2) {
15931638
this.queryCollectionCache[entityName][uniqueString] = coll;
15941639
}
15951640
return this.queryCollectionCache[entityName][uniqueString];
1596-
}
1641+
};
15971642

15981643
/**
15991644
* The constructor function of the _abstract_ QueryCollection
@@ -1653,7 +1698,7 @@ persistence.get = function(arg1, arg2) {
16531698
this._session = session || persistence;
16541699
// For observable
16551700
this.subscribers = {};
1656-
}
1701+
};
16571702

16581703
QueryCollection.prototype.toUniqueString = function() {
16591704
var s = this._constructor.name + ": " + this._entityName;
@@ -1713,12 +1758,13 @@ persistence.get = function(arg1, arg2) {
17131758
* @param property the property to filter on
17141759
* @param operator the operator to use
17151760
* @param value the literal value that the property should match
1761+
* @param escapeChar the escape character in pattern
17161762
* @return the query collection with the filter added
17171763
*/
1718-
QueryCollection.prototype.filter = function (property, operator, value) {
1764+
QueryCollection.prototype.filter = function (property, operator, value, escapeChar) {
17191765
var c = this.clone(true);
17201766
c._filter = new AndFilter(this._filter, new PropertyFilter(property,
1721-
operator, value));
1767+
operator, value, escapeChar));
17221768
// Add global listener (TODO: memory leak waiting to happen!)
17231769
var session = this._session;
17241770
c = session.uniqueQueryCollection(c);
@@ -1866,7 +1912,7 @@ persistence.get = function(arg1, arg2) {
18661912
this._filter.makeFit(obj);
18671913
this.triggerEvent('add', this, obj);
18681914
this.triggerEvent('change', this, obj);
1869-
}
1915+
};
18701916

18711917
/**
18721918
* Adds an an array of objects to a collection
@@ -1880,7 +1926,7 @@ persistence.get = function(arg1, arg2) {
18801926
this.triggerEvent('add', this, obj);
18811927
}
18821928
this.triggerEvent('change', this);
1883-
}
1929+
};
18841930

18851931
/**
18861932
* Removes an object from a collection
@@ -1893,7 +1939,7 @@ persistence.get = function(arg1, arg2) {
18931939
this._filter.makeNotFit(obj);
18941940
this.triggerEvent('remove', this, obj);
18951941
this.triggerEvent('change', this, obj);
1896-
}
1942+
};
18971943

18981944

18991945
/**
@@ -1923,7 +1969,7 @@ persistence.get = function(arg1, arg2) {
19231969
eachFn(results[i]);
19241970
}
19251971
});
1926-
}
1972+
};
19271973

19281974
// Alias
19291975
QueryCollection.prototype.forEach = QueryCollection.prototype.each;
@@ -1945,7 +1991,7 @@ persistence.get = function(arg1, arg2) {
19451991
oneFn(results[0]);
19461992
}
19471993
});
1948-
}
1994+
};
19491995

19501996
DbQueryCollection.prototype = new QueryCollection();
19511997

@@ -2009,7 +2055,7 @@ persistence.get = function(arg1, arg2) {
20092055
}
20102056
}
20112057
this.triggerEvent('change', this);
2012-
}
2058+
};
20132059

20142060
ManyToManyDbQueryCollection.prototype.clone = function() {
20152061
var c = DbQueryCollection.prototype.clone.call(this);
@@ -2064,7 +2110,7 @@ persistence.get = function(arg1, arg2) {
20642110
}
20652111
}
20662112
this.triggerEvent('change', this);
2067-
}
2113+
};
20682114

20692115
LocalQueryCollection.prototype.remove = function(obj) {
20702116
var items = this._items;
@@ -2199,25 +2245,25 @@ var argspec = {};
21992245
}
22002246
}
22012247
return argObj;
2202-
}
2248+
};
22032249

22042250
argspec.hasProperty = function(name) {
22052251
return function(obj) {
22062252
return obj && obj[name] !== undefined;
22072253
};
2208-
}
2254+
};
22092255

22102256
argspec.hasType = function(type) {
22112257
return function(obj) {
22122258
return typeof obj === type;
22132259
};
2214-
}
2260+
};
22152261

22162262
argspec.isCallback = function() {
22172263
return function(obj) {
22182264
return obj && obj.apply;
22192265
};
2220-
}
2266+
};
22212267
}());
22222268

22232269
persistence.argspec = argspec;

0 commit comments

Comments
 (0)