/*
* query-comparison
* https://www.mongodb.com/docs/manual/reference/operator/query-comparison/
* Equal => Eq
* Not Equal => Ne
* Greater => Gt
* Greater or Equal => Gte
* Less => Lt
* Less or Equal => Lte
* Matches a value in array => In
* Matches no values in array => Nin
*
* https://www.mongodb.com/docs/manual/reference/operator/query/eq/
* https://www.mongodb.com/docs/manual/reference/operator/query/ne/
* https://www.mongodb.com/docs/manual/reference/operator/query/gt/
* https://www.mongodb.com/docs/manual/reference/operator/query/gte/
* https://www.mongodb.com/docs/manual/reference/operator/query/lt/
* https://www.mongodb.com/docs/manual/reference/operator/query/lt/
* https://www.mongodb.com/docs/manual/reference/operator/query/nin/
*/ template<typename T>
struct Eq {
using CType = ConstructorType<T>;
Eq(CType init): $eq{std::move(init)} {}
T $eq;
};
// Same pattern for Ne, Gt, Gte, Lt, Lte (are basically the same as Eq)
template<typename T>
struct In
{
using CType = std::vector<T>;
In(CType init): $in{std::move(init)} {}
std::vector<T> $in;
}
// Same pattern for Nin (is basically the same as In)
/*
* query-logical
* https://www.mongodb.com/docs/manual/reference/operator/query-logical/
* Logical AND of two Values => And
* Logical OR of two Values => Or
* Logical NOR of two Values => Nor => NOR(A, B) => !(OR(A,B))
* Logical NOT => Not
*
* https://www.mongodb.com/docs/manual/reference/operator/query/and/
* https://www.mongodb.com/docs/manual/reference/operator/query/or/
* https://www.mongodb.com/docs/manual/reference/operator/query/nor/
* https://www.mongodb.com/docs/manual/reference/operator/query/not/
*/
template<typename LHS, typename RHS>
struct And
{
using CType = And<LHS, RHS>;
using LP = ConstructorType<LHS>;
using RP = ConstructorType<RHS>;
And(LP lhs, RP rhs)
: $and(std::move(lhs), std::move(rhs))
{}
std::tuple<LHS, RHS> $and;
};
// Same pattern for Or and Nor
template<typename T>
struct Not
{
using CType = ConstructorType<T>;
Not(CType init)
: $not(std::move(init))
{}
T $not;
};
/*
* query-element
* https://www.mongodb.com/docs/manual/reference/operator/query-element/
* An element exists in the object => Exists
* https://www.mongodb.com/docs/manual/reference/operator/query/exists/
* An element has a specific Type => Type
* https://www.mongodb.com/docs/manual/reference/operator/query/exists/
*/
struct Exists
{
using CType = bool;
Exists(bool init)
: $exists(init)
{}
bool $exists;
};
enum class BsonType { Double = 1, String = 2, Object = 3, Array = 4,
BinaryData = 5, ObjectId = 7, Boolean = 8, Date = 9,
Null = 10, RegularExpression = 11, JavaScript = 13, Int32 = 16,
Timestamp = 17, Int64 = 18, Decimal128 = 19, MinKey = -1,
MaxKey = 127
};
struct Type
{
using CType = BsonType;
Type(BsonType type)
: $type(static_cast<std::int32_t>(type))
{}
std::int32_t $type;
};
/*
* query-evaluation
* https://www.mongodb.com/docs/manual/reference/operator/query-evaluation/
* Mod field and test remainder => Mod
* https://www.mongodb.com/docs/manual/reference/operator/query/mod/
* Regular Expression => RegEx
* https://www.mongodb.com/docs/manual/reference/operator/query/regex/
* Text search of whole object => Text
* https://www.mongodb.com/docs/manual/reference/operator/query/text/
* Can't seem to get his working.
*
*/
struct Mod
{
using CType = std::pair<std::uint32_t, std::uint32_t>;
Mod(CType init)
: $mod({init.first, init.second})
{}
std::array<std::uint32_t, 2> $mod;
};
struct RegEx
{
using CType = std::pair<std::string, std::string>;
RegEx(CType init)
: $regex(std::move(init.first))
, $options(std::move(init.second))
{}
std::string $regex;
std::string $options;
};
struct TextSearch
{
std::string $search;
std::optional<std::string> $language;
std::optional<bool> $caseSensitive;
std::optional<bool> $diacriticSensitive;
};
struct Text
{
Text(std::string search, std::optional<std::string> language = {}, std::optional<bool> cs = {}, std::optional<bool> ds = {})
: $text{std::move(search), std::move(language), std::move(cs), std::move(ds)}
{}
TextSearch $text;
};
/*
* query-array
* https://www.mongodb.com/docs/manual/reference/operator/query-array/
* Has all the following elements: => All
* An array has an element that matches multiple considitions: => ElemMatch
* An array has a specific size: => Size
*
* https://www.mongodb.com/docs/manual/reference/operator/query/all/
* https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/
* https://www.mongodb.com/docs/manual/reference/operator/query/size/
*/
template<typename T>
struct All
{
using CType = std::vector<T>;
All(CType init)
: $all(std::move(init))
{}
std::vector<T> $all;
};
template<typename T>
struct Elements
{
std::optional<T> $eq;
std::optional<T> $ne;
std::optional<T> $gt;
std::optional<T> $gte;
std::optional<T> $lt;
std::optional<T> $lte;
};
template<typename T>
struct ElemMatch
{
ElemMatch(std::optional<T> eq, std::optional<T> ne, std::optional<T> gt, std::optional<T> gte, std::optional<T> lt, std::optional<T> lte)
: $elemMatch{std::move(eq), std::move(ne), std::move(gt), std::move(gte), std::move(lt), std::move(lte)}
{}
Elements<T> $elemMatch;
};
struct Size
{
using CType = std::uint32_t;
Size(std::uint32_t init)
: $size{init}
{}
std::uint32_t $size;
};
/*
* Bitwise Query operator
* https://www.mongodb.com/docs/manual/reference/operator/query-bitwise/
* AllClear
* AllSet
* AnyClear
* AnySet
*
*
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAllClear/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAllSet/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAnyClear/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAnySet/
*/
struct AllClear
{
using CType = std::uint32_t;
AllClear(CType init)
: $bitsAllClear{std::move(init)}
{}
std::uint32_t $bitsAllClear;
};
struct AllSet
{
using CType = std::uint32_t;
AllSet(CType init)
: $bitsAllSet{std::move(init)}
{}
std::uint32_t $bitsAllSet;
};
struct AnyClear
{
using CType = std::uint32_t;
AnyClear(CType init)
: $bitsAnyClear{std::move(init)}
{}
std::uint32_t $bitsAnyClear;
};
struct AnySet
{
using CType = std::uint32_t;
AnySet(CType init)
: $bitsAnySet{std::move(init)}
{}
std::uint32_t $bitsAnySet;
};
Tests:
TEST(IntegrationConnectionMongoTest, queryEq)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameEQ = Query<FindByName<Eq<std::string>>>;
using VEQ = std::vector<QNameEQ>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VEQ{{"Tom"}});
RemoveResult r2Result = mongo["test"]["People"].remove(VEQ{{"Sam"}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryNe)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameNE = Query<FindByName<Ne<std::string>>>;
using VNE = std::vector<QNameNE>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VNE{{"Sam"}});
RemoveResult r2Result = mongo["test"]["People"].remove(VNE{{"Tom"}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryGt)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameGT = Query<FindByAge<Gt<int>>>;
using VGT = std::vector<QNameGT>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VGT{{56}});
RemoveResult r2Result = mongo["test"]["People"].remove(VGT{{20}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryGte)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameGTE = Query<FindByAge<Gte<int>>>;
using VGTE = std::vector<QNameGTE>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VGTE{{57}});
RemoveResult r2Result = mongo["test"]["People"].remove(VGTE{{22}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryLt)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameLT = Query<FindByAge<Lt<int>>>;
using VLT = std::vector<QNameLT>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VLT{22});
RemoveResult r2Result = mongo["test"]["People"].remove(VLT{58});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryLte)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameLTE = Query<FindByAge<Lte<int>>>;
using VLTE = std::vector<QNameLTE>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VLTE{21});
RemoveResult r2Result = mongo["test"]["People"].remove(VLTE{56});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryIn)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameIN = Query<FindByAge<In<int>>>;
using VIN = std::vector<QNameIN>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VIN{std::vector<int>{25,26,48}});
RemoveResult r2Result = mongo["test"]["People"].remove(VIN{std::vector<int>{23,22,45}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryNin)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameNIN = Query<FindByAge<Nin<int>>>;
using VNIN = std::vector<QNameNIN>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VNIN{std::vector<int>{22,23,45}});
RemoveResult r2Result = mongo["test"]["People"].remove(VNIN{std::vector<int>{25,26,48}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAnd)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameAND = Query<And<FindByName<std::string>, FindByAge<Lt<int>>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameAND{{"Sam", 23}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameAND{{"Sam", 58}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(1, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(2, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryOr)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameOR = Query<Or<FindByName<std::string>, FindByAge<Lt<int>>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameOR{{"Tom", 23}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameOR{{"Sam", 18}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(1, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(2, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryNor)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameNOR = Query<Nor<FindByName<std::string>, FindByAge<Lt<int>>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOR{{"Sam", 22}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOR{{"Tom", 30}}));
RemoveResult r3Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOR{{"Tom", 12}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(1, r2Result.n);
EXPECT_EQ(1, r3Result.ok);
EXPECT_EQ(2, r3Result.n);
}
TEST(IntegrationConnectionMongoTest, queryNot)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameNOT = Query<FindByName<Not<Eq<std::string>>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOT{"Sam"}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOT{"Tom"}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryExists)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameEXISTS = Query<FindByName<Exists>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameEXISTS{false}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameEXISTS{true}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryType)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameEXISTS = Query<FindByName<Type>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameEXISTS{BsonType::Double}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameEXISTS{BsonType::String}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryMod)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 25, {"Court", "NY", 12}}, {"Sam", 37, {"Jester", "FW", 23}}, {"Sam", 49, {"Limbo", "FG", 56}}};
using QNameMod = Query<FindByAge<Mod>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameMod{{12, 0}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameMod{{12, 1}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryRegEx)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Samual", 25, {"Court", "NY", 12}}, {"Samantha", 37, {"Jester", "FW", 23}}, {"Samtra", 49, {"Limbo", "FG", 56}}};
using QNameRegEx = Query<FindByName<RegEx>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameRegEx{{"Samp.*", "i"}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameRegEx{{"Sam.*", "i"}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryText)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 25, {"Cour terror", "NY", 12}}, {"Sam", 37, {"Jes terror", "FW", 23}}, {"Sam", 49, {"Limbo terror", "FG", 56}}};
using QNameText = Query<FindByName<Text>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameText{{"Anikin"}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameText{{"Sam"}}));
RemoveResult r3Result = mongo["test"]["People"].remove(std::make_tuple(Query<FindByName<std::string>>{"Sam"}));
std::cerr << ThorsAnvil::Serialize::jsonExporter(QNameText{{" Sam "}}) << "\n";
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
std::cerr << "Cleanup: " << r3Result.ok << " Count: " << r3Result.n << "\n";
}
TEST(IntegrationConnectionMongoTest, queryAll)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{
{"Sam", 25, {"Cour terror", "NY", 12}, {{10, 13, 14, 15}}},
{"Sam", 37, {"Jes terror", "FW", 23}, {{13, 14, 15}}},
{"Sam", 49, {"Limbo terror", "FG", 56}, {{10, 14, 15}}}
};
using QDataAll = Query<FindByData<All<int>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QDataAll{{10, 12, 13, 14}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QDataAll{{14, 15}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryElemMatch)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{
{"Sam", 25, {"Cour terror", "NY", 12}, {{10, 13, 14, 15}}},
{"Sam", 37, {"Jes terror", "FW", 23}, {{13, 14, 15}}},
{"Sam", 49, {"Limbo terror", "FG", 56}, {{10, 14, 15}}}
};
using QDataElemMatch = Query<FindByData<ElemMatch<int>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QDataElemMatch{{25, 14, {}, {}, {}, {}}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QDataElemMatch{{14, 15, {}, {}, {}, {}}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryElemSize)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{
{"Sam", 25, {"Cour terror", "NY", 12}, {{10, 13, 14}}},
{"Sam", 37, {"Jes terror", "FW", 23}, {{13, 14, 15}}},
{"Sam", 49, {"Limbo terror", "FG", 56}, {{10, 14, 15}}}
};
using QDataSize = Query<FindByData<Size>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QDataSize{2}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QDataSize{3}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAllClear)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 17, {"Cour terror", "NY", 12}}, {"Sam", 25, {"Jes terror", "FW", 23}}, {"Sam", 33, {"Limbo terror", "FG", 56}}};
using QAgeAllClear = Query<FindByAge<AllClear>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAllClear{0b11000111}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAllClear{0b11000110}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAllSet)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 17, {"Cour terror", "NY", 12}}, {"Sam", 25, {"Jes terror", "FW", 23}}, {"Sam", 33, {"Limbo terror", "FG", 56}}};
using QAgeAllSet = Query<FindByAge<AllSet>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAllSet{0b00111001}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAllSet{0b00000001}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAnyClear)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 17, {"Cour terror", "NY", 12}}, {"Sam", 25, {"Jes terror", "FW", 23}}, {"Sam", 33, {"Limbo terror", "FG", 56}}};
using QAgeAnyClear = Query<FindByAge<AnyClear>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAnyClear{0b00000001}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAnyClear{0b11111110}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAnySet)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 17, {"Cour terror", "NY", 12}}, {"Sam", 25, {"Jes terror", "FW", 23}}, {"Sam", 33, {"Limbo terror", "FG", 56}}};
using QAgeAnySet = Query<FindByAge<AnySet>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAnySet{0b10000110}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAnySet{0b11111111}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
/*
* query-comparison
* https://www.mongodb.com/docs/manual/reference/operator/query-comparison/
* Equal => Eq
* Not Equal => Ne
* Greater => Gt
* Greater or Equal => Gte
* Less => Lt
* Less or Equal => Lte
* Matches a value in array => In
* Matches no values in array => Nin
*
* https://www.mongodb.com/docs/manual/reference/operator/query/eq/
* https://www.mongodb.com/docs/manual/reference/operator/query/ne/
* https://www.mongodb.com/docs/manual/reference/operator/query/gt/
* https://www.mongodb.com/docs/manual/reference/operator/query/gte/
* https://www.mongodb.com/docs/manual/reference/operator/query/lt/
* https://www.mongodb.com/docs/manual/reference/operator/query/lt/
* https://www.mongodb.com/docs/manual/reference/operator/query/nin/
*/ template<typename T>
struct Eq {
using CType = ConstructorType<T>;
Eq(CType init): $eq{std::move(init)} {}
T $eq;
};
// Same pattern for Ne, Gt, Gte, Lt, Lte (are basically the same as Eq)
template<typename T>
struct In
{
using CType = std::vector<T>;
In(CType init): $in{std::move(init)} {}
std::vector<T> $in;
}
// Same pattern for Nin (is basically the same as In)
/*
* query-logical
* https://www.mongodb.com/docs/manual/reference/operator/query-logical/
* Logical AND of two Values => And
* Logical OR of two Values => Or
* Logical NOR of two Values => Nor => NOR(A, B) => !(OR(A,B))
* Logical NOT => Not
*
* https://www.mongodb.com/docs/manual/reference/operator/query/and/
* https://www.mongodb.com/docs/manual/reference/operator/query/or/
* https://www.mongodb.com/docs/manual/reference/operator/query/nor/
* https://www.mongodb.com/docs/manual/reference/operator/query/not/
*/
template<typename LHS, typename RHS>
struct And
{
using CType = And<LHS, RHS>;
using LP = ConstructorType<LHS>;
using RP = ConstructorType<RHS>;
And(LP lhs, RP rhs)
: $and(std::move(lhs), std::move(rhs))
{}
std::tuple<LHS, RHS> $and;
};
// Same pattern for Or and Nor
template<typename T>
struct Not
{
using CType = ConstructorType<T>;
Not(CType init)
: $not(std::move(init))
{}
T $not;
};
/*
* query-element
* https://www.mongodb.com/docs/manual/reference/operator/query-element/
* An element exists in the object => Exists
* https://www.mongodb.com/docs/manual/reference/operator/query/exists/
* An element has a specific Type => Type
* https://www.mongodb.com/docs/manual/reference/operator/query/exists/
*/
struct Exists
{
using CType = bool;
Exists(bool init)
: $exists(init)
{}
bool $exists;
};
struct Type
{
using CType = BsonType;
Type(BsonType type)
: $type(static_cast<std::int32_t>(type))
{}
std::int32_t $type;
};
/*
* query-evaluation
* https://www.mongodb.com/docs/manual/reference/operator/query-evaluation/
* Mod field and test remainder => Mod
* https://www.mongodb.com/docs/manual/reference/operator/query/mod/
* Regular Expression => RegEx
* https://www.mongodb.com/docs/manual/reference/operator/query/regex/
* Text search of whole object => Text
* https://www.mongodb.com/docs/manual/reference/operator/query/text/
* Can't seem to get his working.
*
*/
struct Mod
{
using CType = std::pair<std::uint32_t, std::uint32_t>;
Mod(CType init)
: $mod({init.first, init.second})
{}
std::array<std::uint32_t, 2> $mod;
};
struct RegEx
{
using CType = std::pair<std::string, std::string>;
RegEx(CType init)
: $regex(std::move(init.first))
, $options(std::move(init.second))
{}
std::string $regex;
std::string $options;
};
struct TextSearch
{
std::string $search;
std::optional<std::string> $language;
std::optional<bool> $caseSensitive;
std::optional<bool> $diacriticSensitive;
};
struct Text
{
Text(std::string search, std::optional<std::string> language = {}, std::optional<bool> cs = {}, std::optional<bool> ds = {})
: $text{std::move(search), std::move(language), std::move(cs), std::move(ds)}
{}
TextSearch $text;
};
/*
* query-array
* https://www.mongodb.com/docs/manual/reference/operator/query-array/
* Has all the following elements: => All
* An array has an element that matches multiple considitions: => ElemMatch
* An array has a specific size: => Size
*
* https://www.mongodb.com/docs/manual/reference/operator/query/all/
* https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/
* https://www.mongodb.com/docs/manual/reference/operator/query/size/
*/
template<typename T>
struct All
{
using CType = std::vector<T>;
All(CType init)
: $all(std::move(init))
{}
std::vector<T> $all;
};
template<typename T>
struct Elements
{
std::optional<T> $eq;
std::optional<T> $ne;
std::optional<T> $gt;
std::optional<T> $gte;
std::optional<T> $lt;
std::optional<T> $lte;
};
template<typename T>
struct ElemMatch
{
ElemMatch(std::optional<T> eq, std::optional<T> ne, std::optional<T> gt, std::optional<T> gte, std::optional<T> lt, std::optional<T> lte)
: $elemMatch{std::move(eq), std::move(ne), std::move(gt), std::move(gte), std::move(lt), std::move(lte)}
{}
Elements<T> $elemMatch;
};
struct Size
{
using CType = std::uint32_t;
Size(std::uint32_t init)
: $size{init}
{}
std::uint32_t $size;
};
/*
* Bitwise Query operator
* https://www.mongodb.com/docs/manual/reference/operator/query-bitwise/
* AllClear
* AllSet
* AnyClear
* AnySet
*
*
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAllClear/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAllSet/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAnyClear/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAnySet/
*/
struct AllClear
{
using CType = std::uint32_t;
AllClear(CType init)
: $bitsAllClear{std::move(init)}
{}
std::uint32_t $bitsAllClear;
};
struct AllSet
{
using CType = std::uint32_t;
AllSet(CType init)
: $bitsAllSet{std::move(init)}
{}
std::uint32_t $bitsAllSet;
};
struct AnyClear
{
using CType = std::uint32_t;
AnyClear(CType init)
: $bitsAnyClear{std::move(init)}
{}
std::uint32_t $bitsAnyClear;
};
struct AnySet
{
using CType = std::uint32_t;
AnySet(CType init)
: $bitsAnySet{std::move(init)}
{}
std::uint32_t $bitsAnySet;
};
/*
* query-comparison
* https://www.mongodb.com/docs/manual/reference/operator/query-comparison/
* Equal => Eq
* Not Equal => Ne
* Greater => Gt
* Greater or Equal => Gte
* Less => Lt
* Less or Equal => Lte
* Matches a value in array => In
* Matches no values in array => Nin
*
* https://www.mongodb.com/docs/manual/reference/operator/query/eq/
* https://www.mongodb.com/docs/manual/reference/operator/query/ne/
* https://www.mongodb.com/docs/manual/reference/operator/query/gt/
* https://www.mongodb.com/docs/manual/reference/operator/query/gte/
* https://www.mongodb.com/docs/manual/reference/operator/query/lt/
* https://www.mongodb.com/docs/manual/reference/operator/query/lt/
* https://www.mongodb.com/docs/manual/reference/operator/query/nin/
*/ template<typename T>
struct Eq {
using CType = ConstructorType<T>;
Eq(CType init): $eq{std::move(init)} {}
T $eq;
};
// Same pattern for Ne, Gt, Gte, Lt, Lte (are basically the same as Eq)
template<typename T>
struct In
{
using CType = std::vector<T>;
In(CType init): $in{std::move(init)} {}
std::vector<T> $in;
}
// Same pattern for Nin (is basically the same as In)
/*
* query-logical
* https://www.mongodb.com/docs/manual/reference/operator/query-logical/
* Logical AND of two Values => And
* Logical OR of two Values => Or
* Logical NOR of two Values => Nor => NOR(A, B) => !(OR(A,B))
* Logical NOT => Not
*
* https://www.mongodb.com/docs/manual/reference/operator/query/and/
* https://www.mongodb.com/docs/manual/reference/operator/query/or/
* https://www.mongodb.com/docs/manual/reference/operator/query/nor/
* https://www.mongodb.com/docs/manual/reference/operator/query/not/
*/
template<typename LHS, typename RHS>
struct And
{
using CType = And<LHS, RHS>;
using LP = ConstructorType<LHS>;
using RP = ConstructorType<RHS>;
And(LP lhs, RP rhs)
: $and(std::move(lhs), std::move(rhs))
{}
std::tuple<LHS, RHS> $and;
};
// Same pattern for Or and Nor
template<typename T>
struct Not
{
using CType = ConstructorType<T>;
Not(CType init)
: $not(std::move(init))
{}
T $not;
};
/*
* query-element
* https://www.mongodb.com/docs/manual/reference/operator/query-element/
* An element exists in the object => Exists
* https://www.mongodb.com/docs/manual/reference/operator/query/exists/
* An element has a specific Type => Type
* https://www.mongodb.com/docs/manual/reference/operator/query/exists/
*/
struct Exists
{
using CType = bool;
Exists(bool init)
: $exists(init)
{}
bool $exists;
};
enum class BsonType { Double = 1, String = 2, Object = 3, Array = 4,
BinaryData = 5, ObjectId = 7, Boolean = 8, Date = 9,
Null = 10, RegularExpression = 11, JavaScript = 13, Int32 = 16,
Timestamp = 17, Int64 = 18, Decimal128 = 19, MinKey = -1,
MaxKey = 127
};
struct Type
{
using CType = BsonType;
Type(BsonType type)
: $type(static_cast<std::int32_t>(type))
{}
std::int32_t $type;
};
/*
* query-evaluation
* https://www.mongodb.com/docs/manual/reference/operator/query-evaluation/
* Mod field and test remainder => Mod
* https://www.mongodb.com/docs/manual/reference/operator/query/mod/
* Regular Expression => RegEx
* https://www.mongodb.com/docs/manual/reference/operator/query/regex/
* Text search of whole object => Text
* https://www.mongodb.com/docs/manual/reference/operator/query/text/
* Can't seem to get his working.
*
*/
struct Mod
{
using CType = std::pair<std::uint32_t, std::uint32_t>;
Mod(CType init)
: $mod({init.first, init.second})
{}
std::array<std::uint32_t, 2> $mod;
};
struct RegEx
{
using CType = std::pair<std::string, std::string>;
RegEx(CType init)
: $regex(std::move(init.first))
, $options(std::move(init.second))
{}
std::string $regex;
std::string $options;
};
struct TextSearch
{
std::string $search;
std::optional<std::string> $language;
std::optional<bool> $caseSensitive;
std::optional<bool> $diacriticSensitive;
};
struct Text
{
Text(std::string search, std::optional<std::string> language = {}, std::optional<bool> cs = {}, std::optional<bool> ds = {})
: $text{std::move(search), std::move(language), std::move(cs), std::move(ds)}
{}
TextSearch $text;
};
/*
* query-array
* https://www.mongodb.com/docs/manual/reference/operator/query-array/
* Has all the following elements: => All
* An array has an element that matches multiple considitions: => ElemMatch
* An array has a specific size: => Size
*
* https://www.mongodb.com/docs/manual/reference/operator/query/all/
* https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/
* https://www.mongodb.com/docs/manual/reference/operator/query/size/
*/
template<typename T>
struct All
{
using CType = std::vector<T>;
All(CType init)
: $all(std::move(init))
{}
std::vector<T> $all;
};
template<typename T>
struct Elements
{
std::optional<T> $eq;
std::optional<T> $ne;
std::optional<T> $gt;
std::optional<T> $gte;
std::optional<T> $lt;
std::optional<T> $lte;
};
template<typename T>
struct ElemMatch
{
ElemMatch(std::optional<T> eq, std::optional<T> ne, std::optional<T> gt, std::optional<T> gte, std::optional<T> lt, std::optional<T> lte)
: $elemMatch{std::move(eq), std::move(ne), std::move(gt), std::move(gte), std::move(lt), std::move(lte)}
{}
Elements<T> $elemMatch;
};
struct Size
{
using CType = std::uint32_t;
Size(std::uint32_t init)
: $size{init}
{}
std::uint32_t $size;
};
/*
* Bitwise Query operator
* https://www.mongodb.com/docs/manual/reference/operator/query-bitwise/
* AllClear
* AllSet
* AnyClear
* AnySet
*
*
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAllClear/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAllSet/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAnyClear/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAnySet/
*/
struct AllClear
{
using CType = std::uint32_t;
AllClear(CType init)
: $bitsAllClear{std::move(init)}
{}
std::uint32_t $bitsAllClear;
};
struct AllSet
{
using CType = std::uint32_t;
AllSet(CType init)
: $bitsAllSet{std::move(init)}
{}
std::uint32_t $bitsAllSet;
};
struct AnyClear
{
using CType = std::uint32_t;
AnyClear(CType init)
: $bitsAnyClear{std::move(init)}
{}
std::uint32_t $bitsAnyClear;
};
struct AnySet
{
using CType = std::uint32_t;
AnySet(CType init)
: $bitsAnySet{std::move(init)}
{}
std::uint32_t $bitsAnySet;
};
Tests:
TEST(IntegrationConnectionMongoTest, queryEq)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameEQ = Query<FindByName<Eq<std::string>>>;
using VEQ = std::vector<QNameEQ>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VEQ{{"Tom"}});
RemoveResult r2Result = mongo["test"]["People"].remove(VEQ{{"Sam"}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryNe)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameNE = Query<FindByName<Ne<std::string>>>;
using VNE = std::vector<QNameNE>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VNE{{"Sam"}});
RemoveResult r2Result = mongo["test"]["People"].remove(VNE{{"Tom"}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryGt)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameGT = Query<FindByAge<Gt<int>>>;
using VGT = std::vector<QNameGT>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VGT{{56}});
RemoveResult r2Result = mongo["test"]["People"].remove(VGT{{20}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryGte)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameGTE = Query<FindByAge<Gte<int>>>;
using VGTE = std::vector<QNameGTE>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VGTE{{57}});
RemoveResult r2Result = mongo["test"]["People"].remove(VGTE{{22}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryLt)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameLT = Query<FindByAge<Lt<int>>>;
using VLT = std::vector<QNameLT>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VLT{22});
RemoveResult r2Result = mongo["test"]["People"].remove(VLT{58});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryLte)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameLTE = Query<FindByAge<Lte<int>>>;
using VLTE = std::vector<QNameLTE>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VLTE{21});
RemoveResult r2Result = mongo["test"]["People"].remove(VLTE{56});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryIn)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameIN = Query<FindByAge<In<int>>>;
using VIN = std::vector<QNameIN>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VIN{std::vector<int>{25,26,48}});
RemoveResult r2Result = mongo["test"]["People"].remove(VIN{std::vector<int>{23,22,45}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryNin)
{
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameNIN = Query<FindByAge<Nin<int>>>;
using VNIN = std::vector<QNameNIN>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(VNIN{std::vector<int>{22,23,45}});
RemoveResult r2Result = mongo["test"]["People"].remove(VNIN{std::vector<int>{25,26,48}});
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAnd)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameAND = Query<And<FindByName<std::string>, FindByAge<Lt<int>>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameAND{{"Sam", 23}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameAND{{"Sam", 58}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(1, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(2, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryOr)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameOR = Query<Or<FindByName<std::string>, FindByAge<Lt<int>>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameOR{{"Tom", 23}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameOR{{"Sam", 18}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(1, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(2, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryNor)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameNOR = Query<Nor<FindByName<std::string>, FindByAge<Lt<int>>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOR{{"Sam", 22}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOR{{"Tom", 30}}));
RemoveResult r3Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOR{{"Tom", 12}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(1, r2Result.n);
EXPECT_EQ(1, r3Result.ok);
EXPECT_EQ(2, r3Result.n);
}
TEST(IntegrationConnectionMongoTest, queryNot)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameNOT = Query<FindByName<Not<Eq<std::string>>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOT{"Sam"}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameNOT{"Tom"}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryExists)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameEXISTS = Query<FindByName<Exists>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameEXISTS{false}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameEXISTS{true}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryType)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 22, {"Court", "NY", 12}}, {"Sam", 23, {"Jester", "FW", 23}}, {"Sam", 45, {"Limbo", "FG", 56}}};
using QNameEXISTS = Query<FindByName<Type>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameEXISTS{BsonType::Double}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameEXISTS{BsonType::String}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryMod)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 25, {"Court", "NY", 12}}, {"Sam", 37, {"Jester", "FW", 23}}, {"Sam", 49, {"Limbo", "FG", 56}}};
using QNameMod = Query<FindByAge<Mod>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameMod{{12, 0}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameMod{{12, 1}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryRegEx)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Samual", 25, {"Court", "NY", 12}}, {"Samantha", 37, {"Jester", "FW", 23}}, {"Samtra", 49, {"Limbo", "FG", 56}}};
using QNameRegEx = Query<FindByName<RegEx>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameRegEx{{"Samp.*", "i"}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameRegEx{{"Sam.*", "i"}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryText)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 25, {"Cour terror", "NY", 12}}, {"Sam", 37, {"Jes terror", "FW", 23}}, {"Sam", 49, {"Limbo terror", "FG", 56}}};
using QNameText = Query<FindByName<Text>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QNameText{{"Anikin"}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QNameText{{"Sam"}}));
RemoveResult r3Result = mongo["test"]["People"].remove(std::make_tuple(Query<FindByName<std::string>>{"Sam"}));
std::cerr << ThorsAnvil::Serialize::jsonExporter(QNameText{{" Sam "}}) << "\n";
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
std::cerr << "Cleanup: " << r3Result.ok << " Count: " << r3Result.n << "\n";
}
TEST(IntegrationConnectionMongoTest, queryAll)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{
{"Sam", 25, {"Cour terror", "NY", 12}, {{10, 13, 14, 15}}},
{"Sam", 37, {"Jes terror", "FW", 23}, {{13, 14, 15}}},
{"Sam", 49, {"Limbo terror", "FG", 56}, {{10, 14, 15}}}
};
using QDataAll = Query<FindByData<All<int>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QDataAll{{10, 12, 13, 14}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QDataAll{{14, 15}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryElemMatch)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{
{"Sam", 25, {"Cour terror", "NY", 12}, {{10, 13, 14, 15}}},
{"Sam", 37, {"Jes terror", "FW", 23}, {{13, 14, 15}}},
{"Sam", 49, {"Limbo terror", "FG", 56}, {{10, 14, 15}}}
};
using QDataElemMatch = Query<FindByData<ElemMatch<int>>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QDataElemMatch{{25, 14, {}, {}, {}, {}}}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QDataElemMatch{{14, 15, {}, {}, {}, {}}}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryElemSize)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{
{"Sam", 25, {"Cour terror", "NY", 12}, {{10, 13, 14}}},
{"Sam", 37, {"Jes terror", "FW", 23}, {{13, 14, 15}}},
{"Sam", 49, {"Limbo terror", "FG", 56}, {{10, 14, 15}}}
};
using QDataSize = Query<FindByData<Size>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QDataSize{2}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QDataSize{3}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAllClear)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 17, {"Cour terror", "NY", 12}}, {"Sam", 25, {"Jes terror", "FW", 23}}, {"Sam", 33, {"Limbo terror", "FG", 56}}};
using QAgeAllClear = Query<FindByAge<AllClear>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAllClear{0b11000111}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAllClear{0b11000110}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAllSet)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 17, {"Cour terror", "NY", 12}}, {"Sam", 25, {"Jes terror", "FW", 23}}, {"Sam", 33, {"Limbo terror", "FG", 56}}};
using QAgeAllSet = Query<FindByAge<AllSet>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAllSet{0b00111001}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAllSet{0b00000001}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAnyClear)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 17, {"Cour terror", "NY", 12}}, {"Sam", 25, {"Jes terror", "FW", 23}}, {"Sam", 33, {"Limbo terror", "FG", 56}}};
using QAgeAnyClear = Query<FindByAge<AnyClear>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAnyClear{0b00000001}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAnyClear{0b11111110}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
TEST(IntegrationConnectionMongoTest, queryAnySet)
{
using namespace std::string_literals;
ThorsMongo mongo({"localhost", 27017}, {"test", "testPassword", "test"});
std::vector<People> people{{"Sam", 17, {"Cour terror", "NY", 12}}, {"Sam", 25, {"Jes terror", "FW", 23}}, {"Sam", 33, {"Limbo terror", "FG", 56}}};
using QAgeAnySet = Query<FindByAge<AnySet>>;
InsertResult iResult = mongo["test"]["People"].insert(people);
RemoveResult r1Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAnySet{0b10000110}));
RemoveResult r2Result = mongo["test"]["People"].remove(std::make_tuple(QAgeAnySet{0b11111111}));
EXPECT_EQ(1, iResult.ok);
EXPECT_EQ(3, iResult.n);
EXPECT_EQ(3, iResult.inserted.size());
EXPECT_EQ(1, r1Result.ok);
EXPECT_EQ(0, r1Result.n);
EXPECT_EQ(1, r2Result.ok);
EXPECT_EQ(3, r2Result.n);
}
Mongo Queries In C++
The mongo API uses documents (encoded in BSON) as the way to perform queryies (for find / remove etc).
For example a query to find all record where the name
field is "John"
would look like this (here I will encode the document in JSON for readability but in real life it would be encoded in BSON (which is basically a binary version of JSON).
{
"name": {
"$eq": "John"
}
}
You will notice: The first part is the name of the field "name"
then you have the operator "$eq"
followed by the value. Note that my serialization library is based on C++ types and will create the appropriate documents automatically if the types are set up correctly. So create the above document I would create following classes:
struct Eq {
std::string $eq; // I know using $ is an extension.
}
struct FindByName {
Eq name;
};
Then creating an object would be:
FindByName{{"John"}};
The above example is very trivial version and already requires a doubel braces{{
and }}
to initialize. So I wanted to add constructor to make sure we can keep it to one open braces (and deeper nesting don't add up). Side: Note initially I did not use constructors and it became hard to keep track of opening and closing braces without being very careful.
So this would become:
struct Eq {
std::string $eq; // I know using $ is an extension.
}
struct FindByName {
FindByName(std::string init)
: name(std::move(init))
{}
Eq name;
};
Since this is a library I don't know the fields names (or the underlying type) as that is part of the application. But the remaining I have created appropriate classes for.
See Member detection within a class for the the class HasCType
.
Meta Interface:
// Check downstream type has a type CType.
template<typename T, bool = HasCType<T>::val>
struct ConstructorType_T;
template<typename T>
struct ConstructorType_T<T, true>
{
using CType = typename T::CType;
};
template<typename T>
struct ConstructorType_T<T, false>
{
using CType = T;
};
template<typename T>
using ConstructorType = typename ConstructorType_T<T>::CType;
Use this to get CType
from child type. If it is not a query type then it will not have a CType
and thus it is a value (as in "John"
) thus we use the T value. Hopefully it will become clear.
template<typename T>
struct Eq {
using CType = ConstructorType<T>;
Eq(CType init): $eq{std::move(init)} {}
T $eq;
};
Then the user of the library would be expected to create their own type following a similar pattern:
template<typename T>
struct FindByName {
using CType = ConstructorType<T>;
FindByName(CType init): $eq{std::move(init)} {}
T name;
};
using FindByNameEqual = FindByName<Eq<std::string>>;
using FindByNameLess = FindByName<Lt<std::string>>;
// etc.
// Construct a query:
auto john = FindByNameEqual{"John"};
auto Middle = FindByNameLess{"Middle"};
template<typename T>
struct FindByAge {
using CType = ConstructorType<T>;
FindByName(CType init): $eq{std::move(init)} {}
T age;
};
using FindByAgeEqual = FindByAge<Eq<std::uint32_t>>;
using FindByAgeLessEqual = FindByAge<Lt<std::uint32_t>>;
So the code review
/*
* query-comparison
* https://www.mongodb.com/docs/manual/reference/operator/query-comparison/
* Equal => Eq
* Not Equal => Ne
* Greater => Gt
* Greater or Equal => Gte
* Less => Lt
* Less or Equal => Lte
* Matches a value in array => In
* Matches no values in array => Nin
*
* https://www.mongodb.com/docs/manual/reference/operator/query/eq/
* https://www.mongodb.com/docs/manual/reference/operator/query/ne/
* https://www.mongodb.com/docs/manual/reference/operator/query/gt/
* https://www.mongodb.com/docs/manual/reference/operator/query/gte/
* https://www.mongodb.com/docs/manual/reference/operator/query/lt/
* https://www.mongodb.com/docs/manual/reference/operator/query/lt/
* https://www.mongodb.com/docs/manual/reference/operator/query/nin/
*/ template<typename T>
struct Eq {
using CType = ConstructorType<T>;
Eq(CType init): $eq{std::move(init)} {}
T $eq;
};
// Same pattern for Ne, Gt, Gte, Lt, Lte (are basically the same as Eq)
template<typename T>
struct In
{
using CType = std::vector<T>;
In(CType init): $in{std::move(init)} {}
std::vector<T> $in;
}
// Same pattern for Nin (is basically the same as In)
/*
* query-logical
* https://www.mongodb.com/docs/manual/reference/operator/query-logical/
* Logical AND of two Values => And
* Logical OR of two Values => Or
* Logical NOR of two Values => Nor => NOR(A, B) => !(OR(A,B))
* Logical NOT => Not
*
* https://www.mongodb.com/docs/manual/reference/operator/query/and/
* https://www.mongodb.com/docs/manual/reference/operator/query/or/
* https://www.mongodb.com/docs/manual/reference/operator/query/nor/
* https://www.mongodb.com/docs/manual/reference/operator/query/not/
*/
template<typename LHS, typename RHS>
struct And
{
using CType = And<LHS, RHS>;
using LP = ConstructorType<LHS>;
using RP = ConstructorType<RHS>;
And(LP lhs, RP rhs)
: $and(std::move(lhs), std::move(rhs))
{}
std::tuple<LHS, RHS> $and;
};
// Same pattern for Or and Nor
template<typename T>
struct Not
{
using CType = ConstructorType<T>;
Not(CType init)
: $not(std::move(init))
{}
T $not;
};
/*
* query-element
* https://www.mongodb.com/docs/manual/reference/operator/query-element/
* An element exists in the object => Exists
* https://www.mongodb.com/docs/manual/reference/operator/query/exists/
* An element has a specific Type => Type
* https://www.mongodb.com/docs/manual/reference/operator/query/exists/
*/
struct Exists
{
using CType = bool;
Exists(bool init)
: $exists(init)
{}
bool $exists;
};
struct Type
{
using CType = BsonType;
Type(BsonType type)
: $type(static_cast<std::int32_t>(type))
{}
std::int32_t $type;
};
/*
* query-evaluation
* https://www.mongodb.com/docs/manual/reference/operator/query-evaluation/
* Mod field and test remainder => Mod
* https://www.mongodb.com/docs/manual/reference/operator/query/mod/
* Regular Expression => RegEx
* https://www.mongodb.com/docs/manual/reference/operator/query/regex/
* Text search of whole object => Text
* https://www.mongodb.com/docs/manual/reference/operator/query/text/
* Can't seem to get his working.
*
*/
struct Mod
{
using CType = std::pair<std::uint32_t, std::uint32_t>;
Mod(CType init)
: $mod({init.first, init.second})
{}
std::array<std::uint32_t, 2> $mod;
};
struct RegEx
{
using CType = std::pair<std::string, std::string>;
RegEx(CType init)
: $regex(std::move(init.first))
, $options(std::move(init.second))
{}
std::string $regex;
std::string $options;
};
struct TextSearch
{
std::string $search;
std::optional<std::string> $language;
std::optional<bool> $caseSensitive;
std::optional<bool> $diacriticSensitive;
};
struct Text
{
Text(std::string search, std::optional<std::string> language = {}, std::optional<bool> cs = {}, std::optional<bool> ds = {})
: $text{std::move(search), std::move(language), std::move(cs), std::move(ds)}
{}
TextSearch $text;
};
/*
* query-array
* https://www.mongodb.com/docs/manual/reference/operator/query-array/
* Has all the following elements: => All
* An array has an element that matches multiple considitions: => ElemMatch
* An array has a specific size: => Size
*
* https://www.mongodb.com/docs/manual/reference/operator/query/all/
* https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/
* https://www.mongodb.com/docs/manual/reference/operator/query/size/
*/
template<typename T>
struct All
{
using CType = std::vector<T>;
All(CType init)
: $all(std::move(init))
{}
std::vector<T> $all;
};
template<typename T>
struct Elements
{
std::optional<T> $eq;
std::optional<T> $ne;
std::optional<T> $gt;
std::optional<T> $gte;
std::optional<T> $lt;
std::optional<T> $lte;
};
template<typename T>
struct ElemMatch
{
ElemMatch(std::optional<T> eq, std::optional<T> ne, std::optional<T> gt, std::optional<T> gte, std::optional<T> lt, std::optional<T> lte)
: $elemMatch{std::move(eq), std::move(ne), std::move(gt), std::move(gte), std::move(lt), std::move(lte)}
{}
Elements<T> $elemMatch;
};
struct Size
{
using CType = std::uint32_t;
Size(std::uint32_t init)
: $size{init}
{}
std::uint32_t $size;
};
/*
* Bitwise Query operator
* https://www.mongodb.com/docs/manual/reference/operator/query-bitwise/
* AllClear
* AllSet
* AnyClear
* AnySet
*
*
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAllClear/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAllSet/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAnyClear/
* https://www.mongodb.com/docs/manual/reference/operator/query/bitsAnySet/
*/
struct AllClear
{
using CType = std::uint32_t;
AllClear(CType init)
: $bitsAllClear{std::move(init)}
{}
std::uint32_t $bitsAllClear;
};
struct AllSet
{
using CType = std::uint32_t;
AllSet(CType init)
: $bitsAllSet{std::move(init)}
{}
std::uint32_t $bitsAllSet;
};
struct AnyClear
{
using CType = std::uint32_t;
AnyClear(CType init)
: $bitsAnyClear{std::move(init)}
{}
std::uint32_t $bitsAnyClear;
};
struct AnySet
{
using CType = std::uint32_t;
AnySet(CType init)
: $bitsAnySet{std::move(init)}
{}
std::uint32_t $bitsAnySet;
};