From 1c6210915469d1b4fb3e843e604f3d7ab87c1f9b Mon Sep 17 00:00:00 2001 From: Dwight Date: Mon, 2 Jun 2008 22:33:42 -0400 Subject: handle array case properly --- db/jsobj.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- db/jsobj.h | 5 ++++ db/testdb.js | 2 ++ 3 files changed, 84 insertions(+), 9 deletions(-) diff --git a/db/jsobj.cpp b/db/jsobj.cpp index a45d0eb4570..56cd9aa8722 100644 --- a/db/jsobj.cpp +++ b/db/jsobj.cpp @@ -399,6 +399,62 @@ inline int JSMatcher::valuesMatch(Element& l, Element& r, int op) { return (op & z); } +/* return value + -1 mismatch + 0 missing element + 1 match +*/ +int JSMatcher::matchesDotted(const char *fieldName, Element& toMatch, JSObj& obj, int compareOp, bool *deep, bool isArr = false) { + { + const char *p = strchr(fieldName, '.'); + if( p ) { + string left(fieldName, p-fieldName); + + Element e = obj.getField(left.c_str()); + if( e.eoo() ) + return 0; + if( e.type() != Object && e.type() != Array ) + return -1; + + return matchesDotted(p+1, toMatch, e.embeddedObject(), compareOp, deep, e.type() == Array); + } + } + + Element e = obj.getField(fieldName); + + if( valuesMatch(e, toMatch, compareOp) ) { + return 1; + } + else if( e.type() == Array ) { + JSElemIter ai(e.embeddedObject()); + while( ai.more() ) { + Element z = ai.next(); + if( valuesMatch( z, toMatch, compareOp) ) { + if( deep ) + *deep = true; + return 1; + } + } + } + else if( isArr ) { + JSElemIter ai(obj); + while( ai.more() ) { + Element z = ai.next(); + if( z.type() == Object ) { + int cmp = matchesDotted(fieldName, toMatch, z.embeddedObject(), compareOp, deep); + if( cmp > 0 ) { + if( deep ) *deep = true; + return 1; + } + } + } + } + else if( e.eoo() ) { + return 0; + } + return -1; +} + /* deep means we looked into arrays for a match */ bool JSMatcher::matches(JSObj& jsobj, bool *deep) { if( deep ) @@ -435,8 +491,18 @@ bool JSMatcher::matches(JSObj& jsobj, bool *deep) { // check normal non-regex cases: for( int i = 0; i < n; i++ ) { Element& m = toMatch[i]; + + int cmp = matchesDotted(toMatch[i].fieldName(), toMatch[i], jsobj, compareOp[i], deep); + + /* missing is ok iff we were looking for null */ + if( cmp < 0 ) + return false; + if( cmp == 0 && (m.type() != jstNULL && m.type() != Undefined ) ) + return false; + } - Element e = jsobj.getFieldDotted(m.fieldName()); +/* + Element e = jsobj.getFieldDotted(m.fieldName(), arrayElName); if( !e.eoo() ) { if( valuesMatch(e, m, compareOp[i]) ) { goto ok; @@ -454,15 +520,16 @@ bool JSMatcher::matches(JSObj& jsobj, bool *deep) { } return false; } +*/ /* missing. that is ok iff we were looking for null */ - if( m.type() == jstNULL || m.type() == Undefined ) - ; - else - return false; -ok: - ; - } +// if( m.type() == jstNULL || m.type() == Undefined ) +// ; +////// else +// return false; +//ok: +// ; +// } if( where ) { if( where->func == 0 ) @@ -601,7 +668,8 @@ const char * JSObj::getStringField(const char *name) { JSObj JSObj::getObjectField(const char *name) { Element e = getField(name); - return e.type() == Object ? e.embeddedObject() : JSObj(); + JSType t = e.type(); + return t == Object || t == Array ? e.embeddedObject() : JSObj(); } int JSObj::getFieldNames(set& fields) { diff --git a/db/jsobj.h b/db/jsobj.h index cd00b0387d3..cf19609e995 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -399,6 +399,11 @@ class Where; */ class JSMatcher { + int matchesDotted( + const char *fieldName, + Element& toMatch, JSObj& obj, + int compareOp, bool *deep, bool isArr); + public: enum { Equality = 0, diff --git a/db/testdb.js b/db/testdb.js index 3b7709c5650..46fe05b72ea 100644 --- a/db/testdb.js +++ b/db/testdb.js @@ -34,6 +34,7 @@ function noresult(c) { function testdots() { t.dots.remove({}); t.dots.save( { a: 3, b: { y: 4, z : 5 } } ); + t.dots.save( { a: 9, b: [ { y:88, z:0 } ] } ); oneresult( t.dots.find( { a:3 } ) ); oneresult( t.dots.find( { b: { y:4,z:5} } ) ); oneresult( t.dots.find( { a:3, b: { y:4,z:5} } ) ); @@ -41,6 +42,7 @@ function testdots() { oneresult( t.dots.find( { "b.y":4 } ) ); oneresult( t.dots.find( { "b.z":5 } ) ); noresult( t.dots.find( { "b.z":55 } ) ); + oneresult( t.dots.find( { "b.y":88 } ) ); } function testkeys() { -- cgit v1.2.1