Пример #1
0
MojErr MojDbQuery::addClause(WhereMap& map, const MojChar* propName, CompOp op, const MojObject& val, MojDbCollationStrength coll)
{
	MojAssert(propName);

	// only allow valid ops
    if (!(op >= OpEq && op <= OpSubString))
		MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: invalid query op"));
    // only allow array values for = or % or %% ops
    if (val.type() == MojObject::TypeArray && op != OpEq && op != OpPrefix && op != OpSubString)
		MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: query contains array value for non-eq op"));

	// check to see if the prop is referenced in a prior clause
	WhereMap::Iterator iter;
	MojErr err = map.find(propName, iter);
	MojErrCheck(err);
	if (iter == map.end()) {
		// create new clause
		err = createClause(map, propName, op, val, coll);
		MojErrCheck(err);
	} else {
		// add clause to previously referenced prop.
		err = updateClause(iter.value(), op, val, coll);
		MojErrCheck(err);
	}
	return MojErrNone;
}
Пример #2
0
MojErr MojDbQuery::validate() const
{
	bool hasInequalityOp = false;
	bool hasArrayVal = false;
	for (WhereMap::ConstIterator i = m_whereClauses.begin(); i != m_whereClauses.end(); ++i) {
		// verify that we only have inequality op on one prop
		if (i->lowerOp() != OpEq) {
			if (hasInequalityOp)
				MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: query contains inequality operations on multiple properties"));
			hasInequalityOp = true;
		}
		// verify that we only have one array val and it's on an = or % op
		if (i->lowerVal().type() == MojObject::TypeArray && i.key() != DelKey) {
			if (hasArrayVal)
				MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: query contains array values on multiple properties"));
			hasArrayVal = true;
		}
	}
	for (WhereMap::ConstIterator i = m_filterClauses.begin(); i != m_filterClauses.end(); ++i) {
		// verify that we only have inequality op on one prop
		if (i->lowerOp() == OpPrefix) {
			MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: query contains prefix operator in filter"));
		}
		if (i->lowerOp() == OpSearch) {
			MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: query contains search operator in filter"));
		}
	}
	return MojErrNone;
}
Пример #3
0
MojErr MojDbIndex::validateName(const MojString& name)
{
	if (name.length() > MaxIndexNameLen) {
		MojErrThrowMsg(MojErrDbInvalidIndexName, _T("db: index name '%s' invalid: length is %zd chars, max is %zd"), name.data(), name.length(), MaxIndexNameLen);
	}
	for (MojString::ConstIterator i = name.begin(); i < name.end(); ++i) {
		if (!MojIsAlNum(*i) && *i != _T('_')) {
			MojErrThrowMsg(MojErrDbInvalidIndexName, _T("db: index name '%s' invalid: char at position %zd not allowed"), name.data(), (MojSize) (i - name.begin()));
		}
	}
	return MojErrNone;
}
Пример #4
0
MojErr MojDbServiceHandler::handleMerge(MojServiceMessage* msg, MojObject& payload, MojDbReq& req)
{
	MojAssert(msg);
	MojLogTrace(s_log);

	MojErr err = MojErrNone;
	MojUInt32 count = 0;
	MojObject obj;
	

	if (payload.get(MojDbServiceDefs::ObjectsKey, obj)) {
		if (payload.contains(MojDbServiceDefs::QueryKey))
			MojErrThrowMsg(MojErrInvalidArg, _T("db: cannot have both an objects param and a query param"));
		MojObject::ArrayIterator begin;
		bool ignoreM = false;
		payload.get(MojDbServiceDefs::IgnoreMissingKey, ignoreM);
		MojUInt32 mflags = MojDb::FlagNone;
		if (ignoreM)
			mflags = mflags | MojDb::FlagIgnoreMissing;
		err = obj.arrayBegin(begin);
		MojErrCheck(err);
		MojObject::ConstArrayIterator end = obj.arrayEnd();
		err = m_db.merge(begin, end, mflags, req);
		MojErrCheck(err);
		err = formatPut(msg, begin, end); // TO DO: we need to drop non-existing objects
		MojErrCheck(err);
	}
	else if (payload.get(MojDbServiceDefs::QueryKey, obj)) {
		MojObject props;
		err = payload.getRequired(MojDbServiceDefs::PropsKey, props);
		MojErrCheck(err);
		bool ignoreM = false;
		if (payload.get(MojDbServiceDefs::IgnoreMissingKey, ignoreM))
			MojErrThrowMsg(MojErrInvalidArg, _T("db: ignoreMissing - invalid option for merge query"));

		MojDbQuery query;
		err = query.fromObject(obj);
		MojErrCheck(err);
		MojUInt32 queryCount = 0;
		err = m_db.merge(query, props, queryCount, MojDb::FlagNone, req);
		MojErrCheck(err);
		count += queryCount;
		err = formatCount(msg, count);
		MojErrCheck(err);
	}
	else {
		MojErrThrowMsg(MojErrInvalidArg, _T("db: either objects or query param required for merge"));
	}

	return MojErrNone;
}
Пример #5
0
MojErr MojDbQuery::validateFind() const
{
	for (WhereMap::ConstIterator i = m_whereClauses.begin(); i != m_whereClauses.end(); ++i) {
		// if clause is order-defining, verify that it matches the order specified
		if (i->definesOrder() && !(m_orderProp.empty() || m_orderProp == i.key()))
			MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: query order not compatible with where clause"));
		// disallow search operator
		if (i->lowerOp() == OpSearch) {
			MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: search operator not allowed in find"));
		}
	}
	if (!m_filterClauses.empty()) {
		MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: filter not allowed in find"));
	}
	return MojErrNone;
}
Пример #6
0
MojErr MojService::CategoryHandler::invoke(const MojChar* method, MojServiceMessage* msg, MojObject& payload)
{
	MojAssert(method && msg);
	MojLogTrace(s_log);

	MojTime startTime;
	MojErr err = MojGetCurrentTime(startTime);
	MojErrCheck(err);

	// lookup callback
	CallbackInfo cb;
	if (!m_callbackMap.get(method, cb)) {
		MojErrThrow(MojErrMethodNotFound);
	}
	// validate schema
	if (cb.m_schema.get()) {
		MojSchema::Result res;
		err = cb.m_schema->validate(payload, res);
		MojErrCheck(err);
		if (!res.valid()) {
			MojErrThrowMsg(MojErrInvalidArg, _T("invalid parameters: caller='%s' error='%s'"), msg->senderName(), res.msg().data());
		}
	}
	// invoke method
	err = invoke(cb.m_callback, msg, payload);
	MojErrCheck(err);

	// log timing
	MojTime endTime;
	err = MojGetCurrentTime(endTime);
	MojErrCheck(err);
	MojLogInfo(s_log, _T("%s invoked: %.3fms"), method, (double) (endTime.microsecs() - startTime.microsecs()) / 1000);

	return MojErrNone;
}
Пример #7
0
MojErr MojDbIndex::addProp(const MojObject& propObj, bool pushFront)
{
    LOG_TRACE("Entering function %s", __FUNCTION__);
	MojAssert(!isOpen());

	// create extractor
	MojRefCountedPtr<MojDbExtractor> extractor;
	MojErr err = createExtractor(propObj, extractor);
	MojErrCheck(err);
	const MojString& name = extractor->name();

	// check for repeats
	if (m_propNames.find(name) != MojInvalidSize) {
		MojErrThrowMsg(MojErrDbInvalidIndex, _T("db: invalid index '%s' - property '%s' repeated"), m_name.data(), name.data());
	}

	// add to vecs
	if (pushFront) {
		err = m_propNames.insert(0, 1, name);
		MojErrCheck(err);
		err = m_props.insert(0, 1, extractor);
		MojErrCheck(err);
	} else {
		err = m_propNames.push(name);
		MojErrCheck(err);
		err = m_props.push(extractor);
		MojErrCheck(err);
	}
	return MojErrNone;
}
Пример #8
0
MojErr MojDbKind::configureRevSets(const MojObject& obj)
{
	MojLogTrace(s_log);

	m_revSets.clear();
	MojSet<MojString> setNames;
	MojObject array;
	if (obj.get(RevisionSetsKey, array)) {
		MojObject::ConstArrayIterator end = array.arrayEnd();
		for (MojObject::ConstArrayIterator i = array.arrayBegin(); i != end; ++i) {
			MojRefCountedPtr<MojDbRevisionSet> set(new MojDbRevisionSet());
			MojAllocCheck(set.get());

			MojErr err = set->fromObject(*i);
			MojErrCheck(err);
			if (setNames.contains(set->name())) {
				MojErrThrowMsg(MojErrDbInvalidRevisionSet, _T("db: cannot repeat revSet name: '%s'"), set->name().data());
			}
			err = setNames.put(set->name());
			MojErrCheck(err);
			err = m_revSets.push(set);
			MojErrCheck(err);
		}
	}
	return MojErrNone;
}
Пример #9
0
/**
 * is kind exist?
 */
MojErr MojDbShardManagerTest::verifyKindExistance (MojString kindId, MojDb& db)
{
    bool foundOurKind = false;
    MojString str; //for debug

    //kinds map
    MojDbKindEngine::KindMap& map = db.kindEngine()->kindMap();

    for (MojDbKindEngine::KindMap::ConstIterator it = map.begin();
         it != map.end();
         ++it)
    {
        str = it.key();
        if(kindId == str)
        {
            foundOurKind = true;
            break;
        }
    }

    if (!foundOurKind)
        MojErrThrowMsg(MojErrDbKindNotRegistered, "Kind %s not found in kindMap", kindId.data());

    return MojErrNone;
}
Пример #10
0
MojErr MojDbKind::update(MojObject* newObj, const MojObject* oldObj, MojDbOp op, MojDbReq& req, bool checkSchema)
{
	MojLogTrace(s_log);

	MojErr err = checkPermission(op, req);
	MojErrCheck(err);
	err = req.curKind(this);
	MojErrCheck(err);

#if defined(TESTDBKIND)
	MojString s;
	MojErr e2;
	
	if (oldObj) {
		e2 = oldObj->toJson(s);
		MojLogInfo(s_log, _T("Kind_Update_OldObj: %s ;\n"), s.data());
	}
	if (newObj) {
		e2 = newObj->toJson(s);
		MojLogInfo(s_log, _T("Kind_Update_NewObj: %s ;\n"), s.data());
	}
#endif
	if (newObj) {
		// add the _backup property if not set
		if (m_backup && !newObj->contains(MojDb::SyncKey)) {
			err = newObj->putBool(MojDb::SyncKey, true);
			MojErrCheck(err);
		}

		// TEMPORARY!!! This should be done in pre-update to also check parent kinds
        	// warning message comes from preUpdate
		if(checkSchema)
		{
		   
		   MojSchema::Result res;
		   err = m_schema.validate(*newObj, res);
		   MojErrCheck(err);
		   if (!res.valid())
		   {
		      MojErrThrowMsg(MojErrSchemaValidation, _T("schema validation failed for kind '%s': %s"),
		                     m_id.data(), res.msg().data());
		   }
		}
        
	}

	// update revSets and validate schema
	err = preUpdate(newObj, oldObj, req);
	MojErrCheck(err);
	// update indexes
	MojVector<MojDbKind*> kindVec;
	MojInt32 idxcount = 0;
	err = updateIndexes(newObj, oldObj, req, op, kindVec, idxcount);
	MojLogInfo(s_log, _T("Kind_UpdateIndexes_End: %s; supers = %zu; indexcount = %zu; updated = %d \n"), this->id().data(), 
				m_supers.size(), m_indexes.size(), idxcount);

	MojErrCheck(err);

	return MojErrNone;
}
Пример #11
0
MojErr MojDb::requireOpen()
{
    if (!m_isOpen) {
		MojErrThrowMsg(MojErrNotOpen, _T("db not open"));
    }
	return MojErrNone;
}
Пример #12
0
TEST(SignalTest, easy_peasy)
{
    int signaled = -1;
    MojEasySignal<int> signal;
    decltype(signal)::EasySlot slot([&](int x) { signaled = x; return MojErrNone; });

    signal.connect(slot.slot());

    MojExpectNoErr( signal.call(42) );
    EXPECT_EQ(42, signaled);

    MojExpectNoErr( signal.fire(45) );
    EXPECT_EQ(45, signaled);

    MojExpectNoErr( signal.fire(41) );
    EXPECT_EQ(45, signaled);

    MojEasySlot<int> badSlot([&](int x) { signaled = x; MojErrThrowMsg(MojErrUnknown, "intentional"); });

    signal.connect(badSlot.slot());

    EXPECT_EQ( MojErrUnknown, signal.call(41) );
    EXPECT_EQ(41, signaled);

    EXPECT_EQ( MojErrUnknown, signal.call(41) );
    EXPECT_EQ(41, signaled);
}
Пример #13
0
MojErr MojDbKindEngine::getKind(const MojChar* kindName, MojDbKind*& kind)
{
	MojLogTrace(s_log);

	KindMap::ConstIterator iter = m_kinds.find(kindName);
	if (iter == m_kinds.end())
		MojErrThrowMsg(MojErrDbKindNotRegistered, _T("kind not registered: '%s'"), kindName);
	kind = iter.value().get();

	return MojErrNone;
}
Пример #14
0
MojErr MojLogger::levelFromString(const MojChar* str, Level& levelOut)
{
	MojAssertNoLog(str);

	for (int i = 0; i <= LevelMax; ++i) {
		if (!MojStrCmp(str, s_levelNames[i])) {
			levelOut = (Level) i;
			return MojErrNone;
		}
	}
	MojErrThrowMsg(MojErrLogLevelNotFound, _T("log: level not found: '%s'"), str);
}
Пример #15
0
MojErr MojDbPutHandler::validateWildcard(const MojString& val, MojErr errToThrow)
{
    LOG_TRACE("Entering function %s", __FUNCTION__);

    if (val.empty())
        MojErrThrow(errToThrow);
    MojSize wildcardPos = val.find(_T('*'));
    if (wildcardPos != MojInvalidSize) {
        if (wildcardPos != val.length() - 1 ||
                (wildcardPos != 0 && val.at(wildcardPos - 1) != _T('.'))) {
            MojErrThrowMsg(errToThrow, _T("db: invalid wildcard in - '%s'"), val.data());
        }
    }
    return MojErrNone;
}
Пример #16
0
MojErr MojLogEngine::createAppender(const MojObject& conf, const MojChar* name, MojAutoPtr<MojLogAppender>& appenderOut)
{
	MojString type;
	MojErr err = conf.getRequired(TypeKey, type);
	MojErrCheck(err);

	// TODO: use some sort of factory registry to do this
	if (type == _T("file")) {
		MojString path;
		err = conf.getRequired(PathKey, path);
		MojErrCheck(err);
		MojAutoPtr<MojFileAppender> appender(new MojFileAppender());
		MojAllocCheck(appender.get());
		err = appender->open(path.data());
		MojErrCheck(err);
		appenderOut = appender;
	} else if (type == _T("stderr")) {
		MojAutoPtr<MojFileAppender> appender(new MojFileAppender());
		MojAllocCheck(appender.get());
		appender->open(MojStdErrFile);
		appenderOut = appender;
	} else if (type == _T("stdout")) {
		MojAutoPtr<MojFileAppender> appender(new MojFileAppender());
		MojAllocCheck(appender.get());
		appender->open(MojStdOutFile);
		appenderOut = appender;
	}
#ifdef MOJ_USE_SYSLOG
	else if (type == _T("syslog")) {
		MojAutoPtr<MojSyslogAppender> appender(new MojSyslogAppender());
		MojAllocCheck(appender.get());
		appender->open(name);
		appenderOut = appender;
	}
#endif // MOJ_USE_SYSLOG
#ifdef MOJ_USE_PMLOG
	else if (type == _T("pmlog")) {
		MojAutoPtr<MojPmLogAppender> appender(new MojPmLogAppender());
		MojAllocCheck(appender.get());
		appenderOut = appender;
	}
#endif // MOJ_USE_PMLOG
	else {
		MojErrThrowMsg(MojErrLogAppenderNotFound, _T("log: appender not found '%s'"), type.data());
	}
	return MojErrNone;
}
Пример #17
0
// although we might have only 1 real Level DB - just to be safe and consistent
// provide interface to add/drop multiple DB
MojErr MojDbSandwichEngine::drop(const MojChar* path, MojDbStorageTxn* txn)
{
    MojAssert(m_isOpen);

    MojThreadGuard guard(m_dbMutex);

    // close sequences
    for (SequenceVec::ConstIterator i = m_seqs.begin(); i != m_seqs.end(); ++i) {
        MojErr err = (*i)->close();
        MojErrCheck(err);
    }
    m_seqs.clear();

    // TODO: drop transaction
	// Must drop database by path! Throw as not implemented error

	MojErrThrowMsg(MojErrNotImplemented, _T("Not fully implemented")) ;
}
Пример #18
0
MojErr MojDbServiceHandler::handleReserveIds(MojServiceMessage* msg, MojObject& payload, MojDbReq& req)
{
	MojAssert(msg);
	MojLogTrace(s_log);

    // check space level
    if( MojDbServiceHandlerInternal::spaceAlertLevel() == MojDbServiceHandlerInternal::AlertLevelHigh)
       return MojErrDbQuotaExceeded;

	MojInt64 count;
	MojErr err = payload.getRequired(MojDbServiceDefs::CountKey, count);
	MojErrCheck(err);

	MojObjectVisitor& writer = msg->writer();
	err = writer.beginObject();
	MojErrCheck(err);
	err = writer.boolProp(MojServiceMessage::ReturnValueKey, true);
	MojErrCheck(err);
	err = writer.propName(MojDbServiceDefs::IdsKey);
	MojErrCheck(err);
	err = writer.beginArray();
	MojErrCheck(err);

	if (count > (MojInt64) MaxReserveIdCount) {
		MojErrThrowMsg(MojErrDbMaxCountExceeded, _T("cannot reserve more than %d ids"), MaxReserveIdCount);
	}
	for (MojInt64 i = 0; i < count; ++i) {
		MojObject id;
		err = m_db.reserveId(id);
		MojErrCheck(err);
		err = id.visit(writer);
		MojErrCheck(err);
	}

	err = writer.endArray();
	MojErrCheck(err);
	err = writer.endObject();
	MojErrCheck(err);

	return MojErrNone;
}
Пример #19
0
MojErr MojDbIndex::fromObject(const MojObject& obj, const MojString& locale) 
{
    LOG_TRACE("Entering function %s", __FUNCTION__);

	// check name
	MojString name;
	MojErr err = obj.getRequired(NameKey, name);
	MojErrCheck(err);
	err = validateName(name);
	MojErrCheck(err);
	m_name = name;
	m_locale = locale;
    if(m_locale == _T("en_CN"))
       m_locale = locale;

	// get deleted flag
	bool includeDel = false;
	if (obj.get(IncludeDeletedKey, includeDel)) {
		incDel(includeDel);
	}
	// add props
	MojObject props;
	err = obj.getRequired(PropsKey, props);
	MojErrCheck(err);
	MojObject propObj;
	MojSize j = 0;
	while (props.at(j++, propObj)) {
		err = addProp(propObj);
		MojErrCheck(err);
	}
	if (m_props.empty()) {
		MojErrThrowMsg(MojErrDbInvalidIndex, _T("db: no properties specified in index '%s'"), name.data());
	}
	m_obj = obj;

	return MojErrNone;
}
Пример #20
0
MojErr MojDbServiceHandler::handleDel(MojServiceMessage* msg, MojObject& payload, MojDbReq& req)
{
	MojAssert(msg);
	MojLogTrace(s_log);

	MojErr err = MojErrNone;
	MojUInt32 count = 0;
	MojUInt32 flags = MojDb::FlagNone;

	bool purge = false;
	if (payload.get(MojDbServiceDefs::PurgeKey, purge) && purge) {
		flags |= MojDb::FlagPurge;
	}

	MojObject obj;
	if (payload.get(MojDbServiceDefs::IdsKey, obj)) {
		if (payload.contains(MojDbServiceDefs::QueryKey))
			MojErrThrowMsg(MojErrInvalidArg, _T("db: cannot have both an objects argument and a query argument"));
		MojObject deletedObjects;
		err = m_db.del(obj.arrayBegin(), obj.arrayEnd(), count, deletedObjects, flags, req);
		MojErrCheck(err);
		err = formatPut(msg, deletedObjects.arrayBegin(), deletedObjects.arrayEnd());
		MojErrCheck(err);
	}
	else if (payload.get(MojDbServiceDefs::QueryKey, obj)) {
		MojDbQuery query;
		err = query.fromObject(obj);
		MojErrCheck(err);
		MojUInt32 queryCount = 0;
		err = m_db.del(query, queryCount, flags, req);
		MojErrCheck(err);
		count += queryCount;
		err = formatCount(msg, count);
		MojErrCheck(err);
	}
	return MojErrNone;
}
Пример #21
0
MojErr MojDbKind::init(const MojString& id)
{
	MojLogTrace(s_log);

	// parse name and version out of id
	if (id.length() > KindIdLenMax)
		MojErrThrowMsg(MojErrDbMalformedId, _T("db: kind id too long"));
	MojSize sepIdx = id.rfind(VersionSeparator);
	if (sepIdx == MojInvalidIndex)
		MojErrThrow(MojErrDbMalformedId);
	MojErr err = id.substring(0, sepIdx, m_name);
	MojErrCheck(err);
	MojString str;
	err = id.substring(sepIdx + 1, id.length() - sepIdx - 1, str);
	MojErrCheck(err);
	const MojChar* end = NULL;
	MojInt64 ver = MojStrToInt64(str.data(), &end, 0);
	if (*end != '\0' || ver < 0 || ver > MojUInt32Max)
		MojErrThrow(MojErrDbMalformedId);
	m_version = (MojUInt32) ver;
	m_id = id;

	return MojErrNone;
}
Пример #22
0
MojErr MojDbServiceHandler::findImpl(MojServiceMessage* msg, MojObject& payload, MojDbReq& req, MojDbCursor& cursor, bool doCount)
{
	MojAssert(msg);
	MojLogTrace(s_log);

	MojObject queryObj;
	MojErr err = payload.getRequired(MojDbServiceDefs::QueryKey, queryObj);
	MojErrCheck(err);
	bool doWatch = false;
	payload.get(MojDbServiceDefs::WatchKey, doWatch);

	MojDbQuery query;
	err = query.fromObject(queryObj);
	MojErrCheck(err);
	MojUInt32 limit = query.limit();
	if (limit == MojDbQuery::LimitDefault){
		query.limit(MaxQueryLimit);
	} else if (limit > MaxQueryLimit) {
		MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: limit greater than %d not allowed"), MaxQueryLimit);
	}

	if (doWatch) {
		MojRefCountedPtr<Watcher> watcher(new Watcher(msg));
		MojAllocCheck(watcher.get());
		err = m_db.find(query, cursor, watcher->m_watchSlot, req);
		MojErrCheck(err);
	} else {
		err = m_db.find(query, cursor, req);
		MojErrCheck(err);
	}

	// append results
	MojObjectVisitor& writer = msg->writer();
	err = writer.beginObject();
	MojErrCheck(err);
	err = writer.boolProp(MojServiceMessage::ReturnValueKey, true);
	MojErrCheck(err);
	err = writer.propName(MojDbServiceDefs::ResultsKey);
	MojErrCheck(err);
	err = writer.beginArray();
	MojErrCheck(err);
	err = cursor.visit(writer);
	MojErrCheck(err);
	err = writer.endArray();
	MojErrCheck(err);

	// append next page
	MojDbQuery::Page page;
	err = cursor.nextPage(page);
	MojErrCheck(err);
	if (!page.empty()) {
		MojObject pageObj;
		err = page.toObject(pageObj);
		MojErrCheck(err);
		err = writer.objectProp(MojDbServiceDefs::NextKey, pageObj);
		MojErrCheck(err);
	}

	// append count
	if (doCount) {
		MojUInt32 count = 0;
		err = cursor.count(count);
		MojErrCheck(err);
		err = writer.intProp(MojDbServiceDefs::CountKey, (MojInt64) count);
		MojErrCheck(err);
	}

	err = writer.endObject();
	MojErrCheck(err);

	if (doWatch) {
		// if this is a watched query, it cannot be part of a batch so it's safe to reply here
		err = msg->reply();
		MojErrCheck(err);
	}

	// notifications can fire any time after the cursor is closed,
	// so don't close it until after sending the reply.
	err = cursor.close();
	MojErrCheck(err);

	return MojErrNone;
}
Пример #23
0
MojErr MojDbKind::configureIndexes(const MojObject& obj, const MojString& locale, MojDbReq& req)
{
	MojLogTrace(s_log);

	// make sure indexes changes count against our usage
	MojErr err = req.curKind(this);
	MojErrCheck(err);

	// add default id index to set
	MojObject idIndex;
	err = idIndex.fromJson(IdIndexJson);
	MojErrCheck(err);
	ObjectSet newIndexObjects;
	err = newIndexObjects.put(idIndex);
	MojErrCheck(err);
	// change back to a set and use contains
	MojSet<MojString> indexNames;
	MojString defaultIdxName;
	err = defaultIdxName.assign(IdIndexName);
	MojErrCheck(err);
	err = indexNames.put(defaultIdxName);
	MojErrCheck(err);
	// add indexes to set to uniquify and order them
	MojObject indexArray;
	if (obj.get(IndexesKey, indexArray)) {
		MojObject::ConstArrayIterator end = indexArray.arrayEnd();
		for (MojObject::ConstArrayIterator i = indexArray.arrayBegin(); i != end; ++i) {
			MojString indexName;
			err = i->getRequired(MojDbIndex::NameKey, indexName);
			MojErrCheck(err);
			err = indexName.toLower();
			MojErrCheck(err);
			if (!indexNames.contains(indexName)) {
				MojObject idx = *i;
				// make sure we keep the lower-cased index name
				err = idx.putString(MojDbIndex::NameKey, indexName);
				MojErrCheck(err);
				err = newIndexObjects.put(idx);
				MojErrCheck(err);
				err = indexNames.put(indexName);
				MojErrCheck(err);
			} else {
				MojErrThrowMsg(MojErrDbInvalidIndexName, _T("db: cannot repeat index name: '%s'"), indexName.data());
			}
		}
	}
	// figure out what to add and what to delete
	ObjectSet toDrop;
	err = m_indexObjects.diff(newIndexObjects, toDrop);
	MojErrCheck(err);
	ObjectSet toAdd;
	err = newIndexObjects.diff(m_indexObjects, toAdd);
	MojErrCheck(err);
	// drop deleted indexes
	IndexVec newIndexes;
	for (IndexVec::ConstIterator i = m_indexes.begin(); i != m_indexes.end(); ++i) {
		if (toDrop.contains((*i)->object())) {
			err = dropIndex(i->get(), req);
			MojErrCheck(err);
		} else {
			err = newIndexes.push(*i);
			MojErrCheck(err);
		}
	}
	// add new indexes
	for (ObjectSet::ConstIterator i = toAdd.begin(); i != toAdd.end(); ++i) {
		// create index
		MojRefCountedPtr<MojDbIndex> index(new MojDbIndex(this, m_kindEngine));
		MojAllocCheck(index.get());
		err = index->fromObject(*i, locale);
		MojErrCheck(err);
		// open index
		err = openIndex(index.get(), req);
		MojErrCheck(err);
		err = newIndexes.push(index);
		MojErrCheck(err);
	}
	// sort indexes by the prop vec so that for indexes that share prop prefixes, the shortest one comes first
	err = newIndexes.sort();
	MojErrCheck(err);
	// update members
	m_indexObjects = newIndexObjects;
	m_indexes = newIndexes;

	return MojErrNone;
}
Пример #24
0
MojErr MojDbQuery::fromObject(const MojObject& obj)
{
	// TODO: validate against query schema

	bool found;
	MojErr err;
	MojObject array;
	MojString str;

	// distinct
	found = false;
	err = obj.get(DistinctKey, str, found);
	MojErrCheck(err);
	if (found) {
		err = distinct(str);
		MojErrCheck(err);
		// if "distinct" is set, force "distinct" column into "select".
		err = select(str);
		MojErrCheck(err);
		// order
		err = order(str);
		MojErrCheck(err);
	} else {
		// select
		if (obj.get(SelectKey, array)) {
			if(array.empty()) {
				MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: select clause but no selected properties"));
			}
			MojObject prop;
			MojSize i = 0;
			while (array.at(i++, prop)) {
				MojErr err = prop.stringValue(str);
				MojErrCheck(err);
				err = select(str);
				MojErrCheck(err);
			}
		}
		// order
		found = false;
		err = obj.get(OrderByKey, str, found);
		MojErrCheck(err);
		if (found) {
			err = order(str);
			MojErrCheck(err);
		}
	}
	// from
	err = obj.getRequired(FromKey, str);
	MojErrCheck(err);
	err = from(str);
	MojErrCheck(err);
	// where
	if (obj.get(WhereKey, array)) {
		err = addClauses(m_whereClauses, array);
		MojErrCheck(err);
	}
	// filter
	if (obj.get(FilterKey, array)) {
		err = addClauses(m_filterClauses, array);
		MojErrCheck(err);
	}
	// desc
	bool descVal;
	if (obj.get(DescKey, descVal)) {
		desc(descVal);
	}
	// limit
	MojInt64 lim;
	if (obj.get(LimitKey, lim)) {
		if (lim < 0)
			MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: negative query limit"));
	} else {
		lim = LimitDefault;
	}
	limit((MojUInt32) lim);
	// page
	MojObject pageObj;
	if (obj.get(PageKey, pageObj)) {
		Page pagec;
		err = pagec.fromObject(pageObj);
		MojErrCheck(err);
		page(pagec);
	}
	bool incDel = false;
	if (obj.get(IncludeDeletedKey, incDel) && incDel) {
		err = includeDeleted();
		MojErrCheck(err);
	}
	return MojErrNone;
}
Пример #25
0
MojErr MojDb::putImpl(MojObject& obj, MojUInt32 flags, MojDbReq& req, bool checkSchema)
{
	MojLogTrace(s_log);

	MojRefCountedPtr<MojDbStorageItem> prevItem;
	MojObject id;
	if (obj.get(IdKey, id)) {
		// get previous revision if we have an id
		MojErr err = m_objDb->get(id, req.txn(), true, prevItem);
		MojErrCheck(err);
	}
	if (MojFlagGet(flags, FlagIgnoreMissing) && MojFlagGet(flags, FlagMerge)) {
		if (!prevItem.get()) {
			MojErr err = obj.putBool(MojDb::IgnoreIdKey, true);	// so that we can drop it in output
			MojErrCheck(err);
			return MojErrNone;
		}
	}

	MojDbOp op = OpCreate;
	MojObject* prevPtr = NULL;
	MojObject prev;
	if (prevItem.get()) {
		// deal with prev, if it exists
		op = OpUpdate;
		prevPtr = &prev;
		MojErr err = prevItem->toObject(prev, m_kindEngine);
		MojErrCheck(err);

		if (MojFlagGet(flags, FlagMerge)) {
			// do merge
			MojObject merged;
			err = mergeInto(merged, obj, prev);
			MojErrCheck(err);
			obj = merged;
		} else if (!MojFlagGet(flags, FlagForce)) {
			// if the force flag is not set, throw error if we are updating
			// an existing, non-deleted object and no rev was specified
			MojInt64 rev;
			if (obj.get(RevKey, rev) == false) {
				bool deleted = false;
				if (!prev.get(DelKey, deleted) || !deleted)
					MojErrThrow(MojErrDbRevNotSpecified);
			}
		}
	}

	// if the new object has a rev and it doesn't match the old rev, don't do the update
	MojInt64 newRev;
	if (prevPtr != NULL && obj.get(RevKey, newRev)) {
		MojInt64 oldRev;
		MojErr err = prevPtr->getRequired(RevKey, oldRev);
		MojErrCheck(err);
		if (!MojFlagGet(flags, FlagForce) && newRev != oldRev)
			MojErrThrowMsg(MojErrDbRevisionMismatch, _T("db: revision mismatch - expected %lld, got %lld"), oldRev, newRev);
	}

	// save it
	MojErr err = putObj(id, obj, prevPtr, prevItem.get(), req, op, checkSchema);
	MojErrCheck(err);

	if (prevItem.get()) {
		err = prevItem->close();
		MojErrCheck(err);
	}
	return MojErrNone;
}
Пример #26
0
MojErr MojDb::requireNotOpen()
{
	if (m_isOpen)
		MojErrThrowMsg(MojErrAlreadyOpen, _T("db already open"));
	return MojErrNone;
}