BSONObj DocumentSourceLookUp::queryForInput(const Document& input,
                                            const FieldPath& localFieldPath,
                                            const std::string& foreignFieldName,
                                            const BSONObj& additionalFilter) {
    Value localFieldVal = input.getNestedField(localFieldPath);

    // Missing values are treated as null.
    if (localFieldVal.missing()) {
        localFieldVal = Value(BSONNULL);
    }

    // We are constructing a query of one of the following forms:
    // {$and: [{<foreignFieldName>: {$eq: <localFieldVal>}}, <additionalFilter>]}
    // {$and: [{<foreignFieldName>: {$in: [<value>, <value>, ...]}}, <additionalFilter>]}
    // {$and: [{$or: [{<foreignFieldName>: {$eq: <value>}},
    //                {<foreignFieldName>: {$eq: <value>}}, ...]},
    //         <additionalFilter>]}

    BSONObjBuilder query;

    BSONArrayBuilder andObj(query.subarrayStart("$and"));
    BSONObjBuilder joiningObj(andObj.subobjStart());

    if (localFieldVal.isArray()) {
        // Assume an array value logically corresponds to many documents, rather than logically
        // corresponding to one document with an array value.
        const vector<Value>& localArray = localFieldVal.getArray();
        const bool containsRegex = std::any_of(
            localArray.begin(), localArray.end(), [](Value val) { return val.getType() == RegEx; });

        if (containsRegex) {
            // A regex inside of an $in will not be treated as an equality comparison, so use an
            // $or.
            BSONObj orQuery = buildEqualityOrQuery(foreignFieldName, localFieldVal.getArray());
            joiningObj.appendElements(orQuery);
        } else {
            // { _foreignFieldFieldName : { "$in" : localFieldValue } }
            BSONObjBuilder subObj(joiningObj.subobjStart(foreignFieldName));
            subObj << "$in" << localFieldVal;
            subObj.doneFast();
        }
    } else {
        // { _foreignFieldFieldName : { "$eq" : localFieldValue } }
        BSONObjBuilder subObj(joiningObj.subobjStart(foreignFieldName));
        subObj << "$eq" << localFieldVal;
        subObj.doneFast();
    }

    joiningObj.doneFast();

    BSONObjBuilder additionalFilterObj(andObj.subobjStart());
    additionalFilterObj.appendElements(additionalFilter);
    additionalFilterObj.doneFast();

    andObj.doneFast();

    return query.obj();
}
Example #2
0
/**
 * Retrieves a quaternion, scaled to an associated angle unit.
 * 
 * The quaternion is specified in the catalog file in axis-angle format as follows:
 * \verbatim {PropertyName} [ angle axisX axisY axisZ ] \endverbatim
 * 
 * @param[in] key Hash key for the rotation.
 * @param[out] val A quaternion representing the value if present, unaffected if not.
 * @return True if the key exists in the hash, false otherwise.
 */
bool AssociativeArray::getRotation(const string& key, Eigen::Quaternionf& val) const
{
    Value* v = getValue(key);
    if (v == NULL || v->getType() != Value::ArrayType)
        return false;

    Array* arr = v->getArray();
    if (arr->size() != 4)
        return false;

    Value* w = (*arr)[0];
    Value* x = (*arr)[1];
    Value* y = (*arr)[2];
    Value* z = (*arr)[3];

    if (w->getType() != Value::NumberType ||
        x->getType() != Value::NumberType ||
        y->getType() != Value::NumberType ||
        z->getType() != Value::NumberType)
        return false;

    Vector3f axis((float) x->getNumber(),
                  (float) y->getNumber(),
                  (float) z->getNumber());

    double ang = w->getNumber();
    double angScale = 1.0;
    getAngleScale(key, angScale);
    float angle = degToRad((float) (ang * angScale));

    val = Quaternionf(AngleAxisf(angle, axis.normalized()));

    return true;
}
Example #3
0
bool AssociativeArray::getRotation(const string& key, Quatf& val) const
{
    Value* v = getValue(key);
    if (v == NULL || v->getType() != Value::ArrayType)
        return false;

    Array* arr = v->getArray();
    if (arr->size() != 4)
        return false;

    Value* w = (*arr)[0];
    Value* x = (*arr)[1];
    Value* y = (*arr)[2];
    Value* z = (*arr)[3];

    if (w->getType() != Value::NumberType ||
        x->getType() != Value::NumberType ||
        y->getType() != Value::NumberType ||
        z->getType() != Value::NumberType)
        return false;

    Vec3f axis((float) x->getNumber(),
               (float) y->getNumber(),
               (float) z->getNumber());
    axis.normalize();
    float angle = degToRad((float) w->getNumber());
    val.setAxisAngle(axis, angle);

    return true;
}
Value DocumentSourceRedact::redactValue(const Value& in) {
    const BSONType valueType = in.getType();
    if (valueType == Object) {
        _variables->setValue(_currentId, in);
        const boost::optional<Document> result = redactObject();
        if (result) {
            return Value(*result);
        } else {
            return Value();
        }
    } else if (valueType == Array) {
        // TODO dont copy if possible
        vector<Value> newArr;
        const vector<Value>& arr = in.getArray();
        for (size_t i = 0; i < arr.size(); i++) {
            if (arr[i].getType() == Object || arr[i].getType() == Array) {
                const Value toAdd = redactValue(arr[i]);
                if (!toAdd.missing()) {
                    newArr.push_back(toAdd);
                }
            } else {
                newArr.push_back(arr[i]);
            }
        }
        return Value(std::move(newArr));
    } else {
        return in;
    }
}
Value DocumentSourceRedact::redactValue(const Variables& vars, const Value& in) {
    const BSONType valueType = in.getType();
    if (valueType == Object) {
        Variables recurse = vars;
        recurse.current = in;
        const boost::optional<Document> result = redactObject(recurse);
        if (result) {
            return Value(*result);
        }
        else {
            return Value();
        }
    }
    else if (valueType == Array) {
        // TODO dont copy if possible
        vector<Value> newArr;
        const vector<Value>& arr = in.getArray();
        for (size_t i = 0; i < arr.size(); i++) {
            if (arr[i].getType() == Object || arr[i].getType() == Array) {
                const Value toAdd = redactValue(vars, arr[i]) ;
                if (!toAdd.missing()) {
                    newArr.push_back(toAdd);
                }
            }
        }
        return Value::consume(newArr);
    }
    else {
        return in;
    }
}
Example #6
0
AsterismList* ReadAsterismList(istream& in, const StarDatabase& stardb)
{
    AsterismList* asterisms = new AsterismList();
    Tokenizer tokenizer(&in);
    Parser parser(&tokenizer);

    while (tokenizer.nextToken() != Tokenizer::TokenEnd)
    {
        if (tokenizer.getTokenType() != Tokenizer::TokenString)
        {
            DPRINTF(0, "Error parsing asterism file.\n");
            for_each(asterisms->begin(), asterisms->end(), deleteFunc<Asterism*>());
            delete asterisms;
            return NULL;
        }

        string name = tokenizer.getStringValue();
        Asterism* ast = new Asterism(name);

        Value* chainsValue = parser.readValue();
        if (chainsValue == NULL || chainsValue->getType() != Value::ArrayType)
        {
            DPRINTF(0, "Error parsing asterism %s\n", name.c_str());
            for_each(asterisms->begin(), asterisms->end(), deleteFunc<Asterism*>());
            delete asterisms;
            delete chainsValue;
            return NULL;
        }

        Array* chains = chainsValue->getArray();

        for (int i = 0; i < (int) chains->size(); i++)
        {
            if ((*chains)[i]->getType() == Value::ArrayType)
            {
                Array* a = (*chains)[i]->getArray();
                Asterism::Chain* chain = new Asterism::Chain();
                for (Array::const_iterator iter = a->begin(); iter != a->end(); iter++)
                {
                    if ((*iter)->getType() == Value::StringType)
                    {
                        Star* star = stardb.find((*iter)->getString());
                        if (star != NULL)
                            chain->insert(chain->end(), star->getPosition());
                    }
                }

                ast->addChain(*chain);
            }
        }

        asterisms->insert(asterisms->end(), ast);

        delete chainsValue;
    }

    return asterisms;
}
Example #7
0
vector<string> Connection::listDatabases(){
   Value val = comm.getData("/_all_dbs");
   Array   arr = val.getArray();

   vector<string> dbs;

   Array::iterator        db     = arr.begin();
   const Array::iterator &db_end = arr.end();
   for(; db != db_end; ++db)
      dbs.push_back((*db).getString());

   return dbs;
}
Example #8
0
TEST(ValueTest, SetValue)
{
    Value b;
    b.set(true);
    EXPECT_EQ(true, b.getBoolean());

    Value i1;
    i1.set(42);
    EXPECT_EQ(42, i1.getInteger());

    Value i2;
    i2.set(42L);
    EXPECT_EQ(42, i2.getInteger());

    Value f1;
    f1.set(0.42F);
    EXPECT_NEAR(0.42, f1.getFloat(), 0.000001);

    Value f2;
    f2.set(0.42);
    EXPECT_NEAR(0.42, f2.getFloat(), 0.000001);

    Value s1;
    s1.set("foobar");
    EXPECT_EQ("foobar", s1.getString());

    Value s2;
    s2.set(std::string("foobar"));
    EXPECT_EQ("foobar", s2.getString());

    Value s3;
    s3.set(QString("foobar"));
    EXPECT_EQ("foobar", s3.getString());

    Value::Array arr;
    arr.push_back(Value(42));
    Value a;
    a.set(arr);
    EXPECT_EQ(arr, a.getArray());

    Value::Object obj;
    obj["foobar"] = Value(42);
    Value o1;
    o1.set(obj);
    EXPECT_EQ(obj, o1.getObject());

    Value o2;
    o2.set(o1);
    EXPECT_EQ(o1, o2);
}
BSONObj DocumentSourceLookUp::queryForInput(const Document& input,
                                            const FieldPath& localFieldPath,
                                            const std::string& foreignFieldName) {
    Value localFieldVal = input.getNestedField(localFieldPath);

    // Missing values are treated as null.
    if (localFieldVal.missing()) {
        localFieldVal = Value(BSONNULL);
    }

    BSONObjBuilder query;
    BSONObjBuilder subObj(query.subobjStart(foreignFieldName));

    if (localFieldVal.isArray()) {
        // Assume an array value logically corresponds to many documents, rather than logically
        // corresponding to one document with an array value.
        const vector<Value>& localArray = localFieldVal.getArray();
        const bool containsRegex = std::any_of(
            localArray.begin(), localArray.end(), [](Value val) { return val.getType() == RegEx; });

        if (containsRegex) {
            // A regex inside of an $in will not be treated as an equality comparison, so use an
            // $or.
            return buildEqualityOrQuery(foreignFieldName, localFieldVal.getArray());
        }

        // { _foreignFieldFieldName : { "$in" : localFieldValue } }
        subObj << "$in" << localFieldVal;
    } else {
        // { _foreignFieldFieldName : { "$eq" : localFieldValue } }
        subObj << "$eq" << localFieldVal;
    }

    subObj.doneFast();
    return query.obj();
}
bool DocumentSourceGraphLookUp::addToVisitedAndFrontier(BSONObj result, long long depth) {
    Value _id = Value(result.getField("_id"));

    if (_visited.find(_id) != _visited.end()) {
        // We've already seen this object, don't repeat any work.
        return false;
    }

    // We have not seen this node before. If '_depthField' was specified, add the field to the
    // object.
    BSONObj fullObject =
        _depthField ? addDepthFieldToObject(_depthField->fullPath(), depth, result) : result;

    // Add the object to our '_visited' list.
    _visited[_id] = fullObject;

    // Update the size of '_visited' appropriately.
    _visitedUsageBytes += _id.getApproximateSize();
    _visitedUsageBytes += static_cast<size_t>(fullObject.objsize());

    // Add the 'connectFrom' field of 'result' into '_frontier'. If the 'connectFrom' field is an
    // array, we treat it as connecting to multiple values, so we must add each element to
    // '_frontier'.
    BSONElementSet recurseOnValues;
    dps::extractAllElementsAlongPath(result, _connectFromField.fullPath(), recurseOnValues);

    for (auto&& elem : recurseOnValues) {
        Value recurseOn = Value(elem);
        if (recurseOn.isArray()) {
            for (auto&& subElem : recurseOn.getArray()) {
                _frontier->insert(subElem);
                _frontierUsageBytes += subElem.getApproximateSize();
            }
        } else if (!recurseOn.missing()) {
            // Don't recurse on a missing value.
            _frontier->insert(recurseOn);
            _frontierUsageBytes += recurseOn.getApproximateSize();
        }
    }

    // We inserted into _visited, so return true.
    return true;
}
Value ExclusionNode::applyProjectionToValue(Value val) const {
    switch (val.getType()) {
        case BSONType::Object:
            return Value(applyProjection(val.getDocument()));
        case BSONType::Array: {
            // Apply exclusion to each element of the array. Note that numeric paths aren't treated
            // specially, and we will always apply the projection to each element in the array.
            //
            // For example, applying the projection {"a.1": 0} to the document
            // {a: [{b: 0, "1": 0}, {b: 1, "1": 1}]} will not result in {a: [{b: 0, "1": 0}]}, but
            // instead will result in {a: [{b: 0}, {b: 1}]}.
            std::vector<Value> values = val.getArray();
            for (auto it = values.begin(); it != values.end(); it++) {
                *it = applyProjectionToValue(*it);
            }
            return Value(std::move(values));
        }
        default:
            return val;
    }
}
Example #12
0
void AccumulatorPush::processInternal(const Value& input, bool merging) {
    if (!merging) {
        if (!input.missing()) {
            vpValue.push_back(input);
            _memUsageBytes += input.getApproximateSize();
        }
    } else {
        // If we're merging, we need to take apart the arrays we
        // receive and put their elements into the array we are collecting.
        // If we didn't, then we'd get an array of arrays, with one array
        // from each merge source.
        verify(input.getType() == Array);

        const vector<Value>& vec = input.getArray();
        vpValue.insert(vpValue.end(), vec.begin(), vec.end());

        for (size_t i = 0; i < vec.size(); i++) {
            _memUsageBytes += vec[i].getApproximateSize();
        }
    }
}
void DocumentSourceGraphLookUp::performSearch() {
    // Make sure _input is set before calling performSearch().
    invariant(_input);

    _variables->setRoot(*_input);
    Value startingValue = _startWith->evaluateInternal(_variables.get());
    _variables->clearRoot();

    // If _startWith evaluates to an array, treat each value as a separate starting point.
    if (startingValue.isArray()) {
        for (auto value : startingValue.getArray()) {
            _frontier->insert(value);
            _frontierUsageBytes += value.getApproximateSize();
        }
    } else {
        _frontier->insert(startingValue);
        _frontierUsageBytes += startingValue.getApproximateSize();
    }

    doBreadthFirstSearch();
}
Value ProjectionNode::applyProjectionsToValue(Value inputValue) const {
    if (inputValue.getType() == BSONType::Object) {
        MutableDocument outputSubDoc{initializeOutputDocument(inputValue.getDocument())};
        applyProjections(inputValue.getDocument(), &outputSubDoc);
        return outputSubDoc.freezeToValue();
    } else if (inputValue.getType() == BSONType::Array) {
        std::vector<Value> values = inputValue.getArray();
        for (auto& value : values) {
            // If this is a nested array and our policy is to not recurse, skip the array.
            // Otherwise, descend into the array and project each element individually.
            const bool shouldSkip = value.isArray() &&
                _policies.arrayRecursionPolicy == ArrayRecursionPolicy::kDoNotRecurseNestedArrays;
            value = (shouldSkip ? transformSkippedValueForOutput(value)
                                : applyProjectionsToValue(value));
        }
        return Value(std::move(values));
    } else {
        // This represents the case where we are projecting children of a field which does not have
        // any children; for instance, applying the projection {"a.b": true} to the document {a: 2}.
        return transformSkippedValueForOutput(inputValue);
    }
}
Example #15
0
TEST(ValueTest, CreateValue)
{
    Value b = true;
    EXPECT_EQ(true, b.getBoolean());

    Value i1 = 42;
    EXPECT_EQ(42, i1.getInteger());

    Value i2 = 42L;
    EXPECT_EQ(42, i2.getInteger());

    Value f1 = 0.42F;
    EXPECT_NEAR(0.42, f1.getFloat(), 0.000001);

    Value f2 = 0.42;
    EXPECT_NEAR(0.42, f2.getFloat(), 0.000001);

    Value s1 = "foobar";
    EXPECT_EQ("foobar", s1.getString());

    Value s2 = std::string("foobar");
    EXPECT_EQ("foobar", s2.getString());

    Value s3 = QString("foobar");
    EXPECT_EQ("foobar", s3.getString());

    Value::Array arr;
    arr.push_back(Value(42));
    Value a = arr;
    EXPECT_EQ(arr, a.getArray());

    Value::Object obj;
    obj["foobar"] = Value(42);
    Value o1 = obj;
    EXPECT_EQ(obj, o1.getObject());

    Value o2 = o1;
    EXPECT_EQ(o1, o2);
}
Example #16
0
bool AssociativeArray::getVector(const string& key, Vec3d& val) const
{
    Value* v = getValue(key);
    if (v == NULL || v->getType() != Value::ArrayType)
        return false;

    Array* arr = v->getArray();
    if (arr->size() != 3)
        return false;

    Value* x = (*arr)[0];
    Value* y = (*arr)[1];
    Value* z = (*arr)[2];

    if (x->getType() != Value::NumberType ||
        y->getType() != Value::NumberType ||
        z->getType() != Value::NumberType)
        return false;

    val = Vec3d(x->getNumber(), y->getNumber(), z->getNumber());

    return true;
}
Example #17
0
TEST(ValueTest, ValueMap)
{
  boost::shared_ptr<Scalar> s(new Scalar(NTA_BasicType_Int32));
  s->value.int32 = 10;
  boost::shared_ptr<Array> a(new Array(NTA_BasicType_Real32));
  boost::shared_ptr<std::string> str(new std::string("hello world"));
  
  ValueMap vm;
  vm.add("scalar", s);
  vm.add("array", a);
  vm.add("string", str);
  ASSERT_ANY_THROW(vm.add("scalar", s));

  ASSERT_TRUE(vm.contains("scalar"));
  ASSERT_TRUE(vm.contains("array"));
  ASSERT_TRUE(vm.contains("string"));
  ASSERT_TRUE(!vm.contains("foo"));
  ASSERT_TRUE(!vm.contains("scalar2"));
  ASSERT_TRUE(!vm.contains("xscalar"));
  
  boost::shared_ptr<Scalar> s1 = vm.getScalar("scalar");
  ASSERT_TRUE(s1 == s);
  
  boost::shared_ptr<Array> a1 = vm.getArray("array");
  ASSERT_TRUE(a1 == a);
  
  boost::shared_ptr<Scalar> def(new Scalar(NTA_BasicType_Int32));
  Int32 x = vm.getScalarT("scalar", (Int32)20);
  ASSERT_EQ((Int32)10, x);
  
  x = vm.getScalarT("scalar2", (Int32)20);
  ASSERT_EQ((Int32)20, x);

  Value v = vm.getValue("array");
  ASSERT_EQ(Value::arrayCategory, v.getCategory());
  ASSERT_TRUE(v.getArray() == a);
}
void AccumulatorAddToSet::processInternal(const Value& input, bool merging) {
    if (!merging) {
        if (!input.missing()) {
            bool inserted = set.insert(input).second;
            if (inserted) {
                _memUsageBytes += input.getApproximateSize();
            }
        }
    } else {
        // If we're merging, we need to take apart the arrays we
        // receive and put their elements into the array we are collecting.
        // If we didn't, then we'd get an array of arrays, with one array
        // from each merge source.
        verify(input.getType() == Array);

        const vector<Value>& array = input.getArray();
        for (size_t i = 0; i < array.size(); i++) {
            bool inserted = set.insert(array[i]).second;
            if (inserted) {
                _memUsageBytes += array[i].getApproximateSize();
            }
        }
    }
}
Value ProjectionNode::applyExpressionsToValue(const Document& root, Value inputValue) const {
    if (inputValue.getType() == BSONType::Object) {
        MutableDocument outputDoc(inputValue.getDocument());
        applyExpressions(root, &outputDoc);
        return outputDoc.freezeToValue();
    } else if (inputValue.getType() == BSONType::Array) {
        std::vector<Value> values = inputValue.getArray();
        for (auto& value : values) {
            value = applyExpressionsToValue(root, value);
        }
        return Value(std::move(values));
    } else {
        if (subtreeContainsComputedFields()) {
            // Our semantics in this case are to replace whatever existing value we find with a new
            // document of all the computed values. This case represents applying a projection like
            // {"a.b": {$literal: 1}} to the document {a: 1}. This should yield {a: {b: 1}}.
            MutableDocument outputDoc;
            applyExpressions(root, &outputDoc);
            return outputDoc.freezeToValue();
        }
        // We didn't have any expressions, so just skip this value.
        return transformSkippedValueForOutput(inputValue);
    }
}
int main ()
     {



         string resposta;
         string codigoCupom;
         string productID;
         bool desejoAdicionarProduto = true;
         bool questionResolved = false;
         bool firstProductAdded = false;
         Shoppingcart* shoppingCart = new Shoppingcart;
         Value v;
         Value v2;
         Array ar;
         Array ar2;

         v.loadFromFile("product.json");
         v2.loadFromFile("discounts.json");

         ar = Array(v.getArray());         
         ar2 = Array(v2.getArray()); 

     
       
  // Primeira parte do programa referente aa adicao de produtos ao carrinho
  while(desejoAdicionarProduto)
   {
                      
                   
                  

                   
     cout<<"Digite a ID do produto que deseja adicionar"<<endl;
     cin>>productID;
 // Toda a execucao de codigo referente aa adicao de um produto pelo ID somente tem sentido se o usuario tiver digitado corretamente
       if(shoppingCart->validateProductID(productID))
         {   
                     
   // Este if de baixo serve para validar se a entrada e um inteiro sem sinal , o codigo so seque naturalmente se validarID = true   
              cout<<"Esta certo disso (S/N) ?"<<endl;
              cin>>resposta;

              do
              {          
                            if(!(resposta == "S") && !(resposta == "s") && !(resposta == "n") && !(resposta == "N")) 
                            {
                              cout<<"Voce so pode responder com (s/S/n/N)"<<endl;
                              cout<<endl;
                              cout<<"Esta certo disso (S/N) ?"<<endl;
                              cin>>resposta;
                            }
  
               }
                                   
               while(!(resposta == "S") && !(resposta == "s") && !(resposta == "n") && !(resposta == "N"));

            if(resposta == "S" || resposta == "s")
             if(shoppingCart->adicionarAoCarrinho(Atoi(productID),ar) == 0)     
                 if(resposta != "N" && resposta != "n")
                  {
                            cout<<"Deseja adicionar mais algum produto (S/N) ?"<<endl;
                            cin>>resposta;
   
                  // Este looping ai de baixo trata a possibilidade do usuario na responder som um caracter s/S/n/N
                            do
                            {
                              if(resposta == "S" || resposta == "s");
                              else if(resposta == "N" || resposta == "n");
                              else 
                                  {
                                   cout<<endl;
                                   cout<<"Voce so pode responder com (s/S/n/N)"<<endl;
                                   cout<<endl;
                                   cout<<"Deseja adicionar mais algum produto (S/N) ?"<<endl;
                                   cin>>resposta;
                                  }
                            }
                           while(!(resposta == "S") && !(resposta == "s") && !(resposta == "n") && !(resposta == "N"));


                            do
                            {
                              if(resposta == "S" || resposta == "s")
                                  desejoAdicionarProduto = true;
                              else if(resposta == "N" || resposta == "n")
                                  desejoAdicionarProduto = false;
                              else 
                                  {
                                   cout<<endl;
                                   cout<<"Voce so pode responder com (s/S/n/N)"<<endl;
                                   cout<<endl;
                                   cout<<"Deseja adicionar mais algum produto (S/N) ?"<<endl;
                                   cin>>resposta;
                                  }
                            }
                           while(!(resposta == "S") && !(resposta == "s") && !(resposta == "n") && !(resposta == "N"));

                          



                 }

         }
Example #21
0
BSONObj DocumentSourceLookUp::makeMatchStageFromInput(const Document& input,
                                                      const FieldPath& localFieldPath,
                                                      const std::string& foreignFieldName,
                                                      const BSONObj& additionalFilter) {
    Value localFieldVal = input.getNestedField(localFieldPath);

    // Missing values are treated as null.
    if (localFieldVal.missing()) {
        localFieldVal = Value(BSONNULL);
    }

    // We construct a query of one of the following forms, depending on the contents of
    // 'localFieldVal'.
    //
    //   {$and: [{<foreignFieldName>: {$eq: <localFieldVal>}}, <additionalFilter>]}
    //     if 'localFieldVal' isn't an array value.
    //
    //   {$and: [{<foreignFieldName>: {$in: [<value>, <value>, ...]}}, <additionalFilter>]}
    //     if 'localFieldVal' is an array value but doesn't contain any elements that are regular
    //     expressions.
    //
    //   {$and: [{$or: [{<foreignFieldName>: {$eq: <value>}},
    //                  {<foreignFieldName>: {$eq: <value>}}, ...]},
    //           <additionalFilter>]}
    //     if 'localFieldVal' is an array value and it contains at least one element that is a
    //     regular expression.

    // We wrap the query in a $match so that it can be parsed into a DocumentSourceMatch when
    // constructing a pipeline to execute.
    BSONObjBuilder match;
    BSONObjBuilder query(match.subobjStart("$match"));

    BSONArrayBuilder andObj(query.subarrayStart("$and"));
    BSONObjBuilder joiningObj(andObj.subobjStart());

    if (localFieldVal.isArray()) {
        // A $lookup on an array value corresponds to finding documents in the foreign collection
        // that have a value of any of the elements in the array value, rather than finding
        // documents that have a value equal to the entire array value. These semantics are
        // automatically provided to us by using the $in query operator.
        const vector<Value>& localArray = localFieldVal.getArray();
        const bool containsRegex = std::any_of(
            localArray.begin(), localArray.end(), [](Value val) { return val.getType() == RegEx; });

        if (containsRegex) {
            // A regular expression inside the $in query operator will perform pattern matching on
            // any string values. Since we want regular expressions to only match other RegEx types,
            // we write the query as a $or of equality comparisons instead.
            BSONObj orQuery = buildEqualityOrQuery(foreignFieldName, localFieldVal.getArray());
            joiningObj.appendElements(orQuery);
        } else {
            // { <foreignFieldName> : { "$in" : <localFieldVal> } }
            BSONObjBuilder subObj(joiningObj.subobjStart(foreignFieldName));
            subObj << "$in" << localFieldVal;
            subObj.doneFast();
        }
    } else {
        // { <foreignFieldName> : { "$eq" : <localFieldVal> } }
        BSONObjBuilder subObj(joiningObj.subobjStart(foreignFieldName));
        subObj << "$eq" << localFieldVal;
        subObj.doneFast();
    }

    joiningObj.doneFast();

    BSONObjBuilder additionalFilterObj(andObj.subobjStart());
    additionalFilterObj.appendElements(additionalFilter);
    additionalFilterObj.doneFast();

    andObj.doneFast();

    query.doneFast();
    return match.obj();
}
Example #22
0
static bool CreateTimeline(Body* body,
                           PlanetarySystem* system,
                           Universe& universe,
                           Hash* planetData,
                           const string& path,
                           Disposition disposition,
                           BodyType bodyType)
{
    FrameTree* parentFrameTree = NULL;
    Selection parentObject = GetParentObject(system);
    bool orbitsPlanet = false;
    if (parentObject.body())
    {
        parentFrameTree = parentObject.body()->getOrCreateFrameTree();
        orbitsPlanet = true;
    }
    else if (parentObject.star())
    {
        SolarSystem* solarSystem = universe.getSolarSystem(parentObject.star());
        if (solarSystem == NULL)
            solarSystem = universe.createSolarSystem(parentObject.star());
        parentFrameTree = solarSystem->getFrameTree();
    }
    else
    {
        // Bad orbit barycenter specified
        return false;
    }

    ReferenceFrame* defaultOrbitFrame = NULL;
    ReferenceFrame* defaultBodyFrame = NULL;
    if (bodyType == SurfaceObject)
    {
        defaultOrbitFrame = new BodyFixedFrame(parentObject, parentObject);
        defaultBodyFrame = CreateTopocentricFrame(parentObject, parentObject, Selection(body));
        defaultOrbitFrame->addRef();
        defaultBodyFrame->addRef();
    }
    else
    {
        defaultOrbitFrame = parentFrameTree->getDefaultReferenceFrame();
        defaultBodyFrame = parentFrameTree->getDefaultReferenceFrame();
    }
    
    // If there's an explicit timeline definition, parse that. Otherwise, we'll do
    // things the old way.
    Value* value = planetData->getValue("Timeline");
    if (value != NULL)
    {
        if (value->getType() != Value::ArrayType)
        {
            clog << "Error: Timeline must be an array\n";
            return false;
        }

        Timeline* timeline = CreateTimelineFromArray(body, universe, value->getArray(), path,
                                                     defaultOrbitFrame, defaultBodyFrame);
        if (timeline == NULL)
        {
            return false;
        }
        else
        {
            body->setTimeline(timeline);
            return true;
        }
    }

    // Information required for the object timeline.
    ReferenceFrame* orbitFrame   = NULL;
    ReferenceFrame* bodyFrame    = NULL;
    Orbit* orbit                 = NULL;
    RotationModel* rotationModel = NULL;
    double beginning             = -numeric_limits<double>::infinity();
    double ending                =  numeric_limits<double>::infinity();

    // If any new timeline values are specified, we need to overrideOldTimeline will
    // be set to true.
    bool overrideOldTimeline = false;

    // The interaction of Modify with timelines is slightly complicated. If the timeline
    // is specified by putting the OrbitFrame, Orbit, BodyFrame, or RotationModel directly
    // in the object definition (i.e. not inside a Timeline structure), it will completely
    // replace the previous timeline if it contained more than one phase. Otherwise, the
    // properties of the single phase will be modified individually, for compatibility with
    // Celestia versions 1.5.0 and earlier.
    if (disposition == ModifyObject)
    {
        const Timeline* timeline = body->getTimeline();
        if (timeline->phaseCount() == 1)
        {
            const TimelinePhase* phase = timeline->getPhase(0);
            orbitFrame    = phase->orbitFrame();
            bodyFrame     = phase->bodyFrame();
            orbit         = phase->orbit();
            rotationModel = phase->rotationModel();
            beginning     = phase->startTime();
            ending        = phase->endTime();
        }
    }

    // Get the object's orbit reference frame.
    bool newOrbitFrame = false;
    Value* frameValue = planetData->getValue("OrbitFrame");
    if (frameValue != NULL)
    {
        ReferenceFrame* frame = CreateReferenceFrame(universe, frameValue, parentObject, body);
        if (frame != NULL)
        {
            orbitFrame = frame;
            newOrbitFrame = true;
            overrideOldTimeline = true;
        }
    }

    // Get the object's body frame.
    bool newBodyFrame = false;
    Value* bodyFrameValue = planetData->getValue("BodyFrame");
    if (bodyFrameValue != NULL)
    {
        ReferenceFrame* frame = CreateReferenceFrame(universe, bodyFrameValue, parentObject, body);
        if (frame != NULL)
        {
            bodyFrame = frame;
            newBodyFrame = true;
            overrideOldTimeline = true;
        }
    }

    // If no orbit or body frame was specified, use the default ones
    if (orbitFrame == NULL)
        orbitFrame = defaultOrbitFrame;
    if (bodyFrame == NULL)
        bodyFrame = defaultBodyFrame;

    // If the center of the is a star, orbital element units are
    // in AU; otherwise, use kilometers.
    if (orbitFrame->getCenter().star() != NULL)
        orbitsPlanet = false;
    else
        orbitsPlanet = true;

    Orbit* newOrbit = CreateOrbit(orbitFrame->getCenter(), planetData, path, !orbitsPlanet);
    if (newOrbit == NULL && orbit == NULL)
    {
        if (body->getTimeline() && disposition == ModifyObject)
        {
            // The object definition is modifying an existing object with a multiple phase
            // timeline, but no orbit definition was given. This can happen for completely
            // sensible reasons, such a Modify definition that just changes visual properties.
            // Or, the definition may try to change other timeline phase properties such as
            // the orbit frame, but without providing an orbit. In both cases, we'll just
            // leave the original timeline alone.
            return true;
        }
        else
        {
            clog << "No valid orbit specified for object '" << body->getName() << "'. Skipping.\n";
            return false;
        }
    }

    // If a new orbit was given, override any old orbit
    if (newOrbit != NULL)
    {
        orbit = newOrbit;
        overrideOldTimeline = true;
    }

    // Get the rotation model for this body
    double syncRotationPeriod = orbit->getPeriod();
    RotationModel* newRotationModel = CreateRotationModel(planetData, path, syncRotationPeriod);

    // If a new rotation model was given, override the old one
    if (newRotationModel != NULL)
    {
        rotationModel = newRotationModel;
        overrideOldTimeline = true;
    }

    // If there was no rotation model specified, nor a previous rotation model to
    // override, create the default one.
    if (rotationModel == NULL)
    {
        // If no rotation model is provided, use a default rotation model--
        // a uniform rotation that's synchronous with the orbit (appropriate
        // for nearly all natural satellites in the solar system.)
        rotationModel = CreateDefaultRotationModel(syncRotationPeriod);
    }
    
    if (ParseDate(planetData, "Beginning", beginning))
        overrideOldTimeline = true;
    if (ParseDate(planetData, "Ending", ending))
        overrideOldTimeline = true;

    // Something went wrong if the disposition isn't modify and no timeline
    // is to be created.
    assert(disposition == ModifyObject || overrideOldTimeline);

    if (overrideOldTimeline)
    {
        if (beginning >= ending)
        {
            clog << "Beginning time must be before Ending time.\n";
            return false;
        }

        // We finally have an orbit, rotation model, frames, and time range. Create
        // the object timeline.
        TimelinePhase* phase = TimelinePhase::CreateTimelinePhase(universe,
                                                                  body,
                                                                  beginning, ending,
                                                                  *orbitFrame,
                                                                  *orbit,
                                                                  *bodyFrame,
                                                                  *rotationModel);

        // We've already checked that beginning < ending; nothing else should go
        // wrong during the creation of a TimelinePhase.
        assert(phase != NULL);
        if (phase == NULL)
        {
            clog << "Internal error creating TimelinePhase.\n";
            return false;
        }

        Timeline* timeline = new Timeline();
        timeline->appendPhase(phase);

        body->setTimeline(timeline);

        // Check for circular references in frames; this can only be done once the timeline
        // has actually been set.
        // TIMELINE-TODO: This check is not comprehensive; it won't find recursion in
        // multiphase timelines.
        if (newOrbitFrame && isFrameCircular(*body->getOrbitFrame(0.0), ReferenceFrame::PositionFrame))
        {
            clog << "Orbit frame for " << body->getName() << " is nested too deep (probably circular)\n";
            return false;
        }

        if (newBodyFrame && isFrameCircular(*body->getBodyFrame(0.0), ReferenceFrame::OrientationFrame))
        {
            clog << "Body frame for " << body->getName() << " is nested too deep (probably circular)\n";
            return false;
        }
    }

    return true;
}
Example #23
0
void ValueTest::RunTests()
{
  // scalar
  {
    boost::shared_ptr<Scalar>  s(new Scalar(NTA_BasicType_Int32));
    s->value.int32 = 10;
    Value v(s);
    TEST(v.isScalar());
    TEST(! v.isString());
    TEST(! v.isArray());
    TESTEQUAL(Value::scalarCategory, v.getCategory());
    TESTEQUAL(NTA_BasicType_Int32, v.getType());
      
    boost::shared_ptr<Scalar> s1 = v.getScalar();
    TEST(s1 == s);
      
    SHOULDFAIL(v.getArray());
    SHOULDFAIL(v.getString());
      
    TESTEQUAL("Scalar of type Int32", v.getDescription());
      
    
    Int32 x = v.getScalarT<Int32>();
    TESTEQUAL(10, x);
    
    SHOULDFAIL(v.getScalarT<UInt32>());

  }

  // array
  {
    boost::shared_ptr<Array>  s(new Array(NTA_BasicType_Int32));
    s->allocateBuffer(10);
    Value v(s);
    TEST(v.isArray());
    TEST(! v.isString());
    TEST(! v.isScalar());
    TESTEQUAL(Value::arrayCategory, v.getCategory());
    TESTEQUAL(NTA_BasicType_Int32, v.getType());
      
    boost::shared_ptr<Array> s1 = v.getArray();
    TEST(s1 == s);
      
    SHOULDFAIL(v.getScalar());
    SHOULDFAIL(v.getString());
    SHOULDFAIL(v.getScalarT<Int32>());

    TESTEQUAL("Array of type Int32", v.getDescription());
  }

  // string
  {
    boost::shared_ptr<std::string> s(new std::string("hello world"));
    Value v(s);
    TEST(! v.isArray());
    TEST(v.isString());
    TEST(! v.isScalar());
    TESTEQUAL(Value::stringCategory, v.getCategory());
    TESTEQUAL(NTA_BasicType_Byte, v.getType());
      
    boost::shared_ptr<std::string> s1 = v.getString();
    TESTEQUAL("hello world", s1->c_str());
      
    SHOULDFAIL(v.getScalar());
    SHOULDFAIL(v.getArray());
    SHOULDFAIL(v.getScalarT<Int32>());
      
    TESTEQUAL("string (hello world)", v.getDescription());
  }

  // ValueMap
  {
    boost::shared_ptr<Scalar> s(new Scalar(NTA_BasicType_Int32));
    s->value.int32 = 10;
    boost::shared_ptr<Array> a(new Array(NTA_BasicType_Real32));
    boost::shared_ptr<std::string> str(new std::string("hello world"));
    
    ValueMap vm;
    vm.add("scalar", s);
    vm.add("array", a);
    vm.add("string", str);
    SHOULDFAIL(vm.add("scalar", s));

    TEST(vm.contains("scalar"));
    TEST(vm.contains("array"));
    TEST(vm.contains("string"));
    TEST(!vm.contains("foo"));
    TEST(!vm.contains("scalar2"));
    TEST(!vm.contains("xscalar"));
    
    boost::shared_ptr<Scalar> s1 = vm.getScalar("scalar");
    TEST(s1 == s);
    
    boost::shared_ptr<Array> a1 = vm.getArray("array");
    TEST(a1 == a);
    
    boost::shared_ptr<Scalar> def(new Scalar(NTA_BasicType_Int32));
    Int32 x = vm.getScalarT("scalar", (Int32)20);
    TESTEQUAL((Int32)10, x);
    
    x = vm.getScalarT("scalar2", (Int32)20);
    TESTEQUAL((Int32)20, x);

    Value v = vm.getValue("array");
    TESTEQUAL(Value::arrayCategory, v.getCategory());
    TEST(v.getArray() == a);
  }
}