Skip to content

Commit

Permalink
MongoDB 5.1+ support
Browse files Browse the repository at this point in the history
  • Loading branch information
WebFreak001 committed Feb 5, 2024
1 parent 57c7a5d commit b90891c
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 97 deletions.
4 changes: 2 additions & 2 deletions dub.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "mongoschemad",
"description": "MongoDB Schema support",
"copyright": "Copyright © 2017, webfreak",
"copyright": "Copyright © 2017-2024, webfreak",
"authors": ["webfreak"],
"license": "MIT",
"dependencies":
{
"vibe-d:mongodb": "*",
"vibe-d:mongodb": ">=0.9.6",
"vibe-d:data": "*"
}
}
170 changes: 78 additions & 92 deletions source/mongoschema/db.d
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,8 @@ private:
/// Mixin for functions for interacting with Mongo collections.
mixin template MongoSchema()
{
import vibe.db.mongo.collection;

import std.typecons : Nullable;
import std.range : isInputRange, ElementType;

Expand Down Expand Up @@ -428,14 +430,16 @@ mixin template MongoSchema()
{
if (_schema_object_id_.valid)
{
collection.update(Bson(["_id": Bson(_schema_object_id_)]),
this.toSchemaBson(), UpdateFlags.upsert);
UpdateOptions options;
options.upsert = true;
collection.replaceOne(Bson(["_id": Bson(_schema_object_id_)]),
this.toSchemaBson(), options);
}
else
{
_schema_object_id_ = BsonObjectID.generate;
auto bson = this.toSchemaBson();
collection.insert(bson);
collection.insertOne(bson);
}
}

Expand All @@ -444,14 +448,16 @@ mixin template MongoSchema()
{
if (_schema_object_id_.valid)
{
collection.update(Bson(["_id": Bson(_schema_object_id_)]),
Bson(["$set": this.toSchemaBson()]), UpdateFlags.upsert);
UpdateOptions options;
options.upsert = true;
collection.updateOne(Bson(["_id": Bson(_schema_object_id_)]),
Bson(["$set": this.toSchemaBson()]), options);
}
else
{
_schema_object_id_ = BsonObjectID.generate;
auto bson = this.toSchemaBson();
collection.insert(bson);
collection.insertOne(bson);
}
}

Expand All @@ -460,7 +466,7 @@ mixin template MongoSchema()
{
if (!_schema_object_id_.valid)
return false;
collection.remove(Bson(["_id": Bson(_schema_object_id_)]), DeleteFlags.SingleRemove);
collection.deleteOne(Bson(["_id": Bson(_schema_object_id_)]));
return true;
}

Expand Down Expand Up @@ -568,37 +574,32 @@ mixin template MongoSchema()
}

/// Finds one or more elements using a query.
static typeof(this)[] find(Query!(typeof(this)) query,
QueryFlags flags = QueryFlags.None, int num_skip = 0, int num_docs_per_chunk = 0)
static typeof(this)[] find(Query!(typeof(this)) query, FindOptions options = FindOptions.init)
{
return find(query._query, flags, num_skip, num_docs_per_chunk);
return find(query._query, options);
}

/// ditto
static typeof(this)[] find(T)(T query, QueryFlags flags = QueryFlags.None,
int num_skip = 0, int num_docs_per_chunk = 0)
static typeof(this)[] find(T)(T query, FindOptions options = FindOptions.init)
{
typeof(this)[] values;
foreach (entry; collection.find(query, null, flags, num_skip, num_docs_per_chunk))
foreach (entry; collection.find(query, options))
{
values ~= fromSchemaBson!(typeof(this))(entry);
}
return values;
}

/// Finds one or more elements using a query as range.
static DocumentRange!(typeof(this)) findRange(Query!(typeof(this)) query,
QueryFlags flags = QueryFlags.None, int num_skip = 0, int num_docs_per_chunk = 0)
static DocumentRange!(typeof(this)) findRange(Query!(typeof(this)) query, FindOptions options = FindOptions.init)
{
return findRange(query._query, flags, num_skip, num_docs_per_chunk);
return findRange(query._query, options);
}

/// ditto
static DocumentRange!(typeof(this)) findRange(T)(T query,
QueryFlags flags = QueryFlags.None, int num_skip = 0, int num_docs_per_chunk = 0)
static DocumentRange!(typeof(this)) findRange(T)(T query, FindOptions options = FindOptions.init)
{
return DocumentRange!(typeof(this))(collection.find(serializeToBson(query),
null, flags, num_skip, num_docs_per_chunk));
return DocumentRange!(typeof(this))(collection.find(serializeToBson(query), options));
}

/// Queries all elements from the collection as range.
Expand All @@ -616,54 +617,66 @@ mixin template MongoSchema()

if (documents.empty)
return;
collection.insert(documents.map!((a) {
collection.insertMany(documents.map!((a) {
a.bsonID = BsonObjectID.init;
return a.toSchemaBson;
}).array, options); // .array needed because of vibe-d issue #2185
}

/// Updates a document.
static void update(U)(Query!(typeof(this)) query, U update, UpdateFlags options = UpdateFlags
.none)
/// Updates a document with `$dollarOperations`.
static void updateOne(U)(Query!(typeof(this)) query, U update, UpdateOptions options = UpdateOptions.init)
{
update(query._query, update, options);
updateOne(query._query, update, options);
}

/// ditto
static void update(T, U)(T query, U update, UpdateFlags options = UpdateFlags.none)
static void updateOne(T, U)(T query, U update, UpdateOptions options = UpdateOptions.init)
{
collection.update(query, update, options);
collection.updateOne(query, update, options);
}

/// Updates a document or inserts it when not existent. Shorthand for `update(..., UpdateFlags.upsert)`
static void upsert(U)(Query!(typeof(this)) query, U upsert,
UpdateFlags options = UpdateFlags.upsert)
/// Updates any amount of documents.
static void updateMany(U)(Query!(typeof(this)) query, U update, UpdateOptions options = UpdateOptions.init)
{
updateMany(query._query, update, options);
}

/// ditto
static void updateMany(T, U)(T query, U update, UpdateOptions options = UpdateOptions.init)
{
collection.updateMany(query, update, options);
}

/// Updates a document or inserts it when not existent. Calls `replaceOne` with `options.upsert` set to true.
static void upsert(U)(Query!(typeof(this)) query, U upsert, UpdateOptions options = UpdateOptions.init)
{
options.upsert = true;
upsert(query._query, upsert, options);
}

/// ditto
static void upsert(T, U)(T query, U update, UpdateFlags options = UpdateFlags.upsert)
static void upsert(T, U)(T query, U update, UpdateOptions options = UpdateOptions.init)
{
collection.update(query, update, options);
options.upsert = true;
collection.replaceOne(query, update, options);
}

/// Deletes one or any amount of documents matching the selector based on the flags.
static void remove(Query!(typeof(this)) query, DeleteFlags flags = DeleteFlags.none)
/// Deletes one or any amount of documents matching the selector based on the options.
static void remove(Query!(typeof(this)) query, DeleteOptions options = DeleteOptions.init)
{
remove(query._query, flags);
remove(query._query, options);
}

/// ditto
static void remove(T)(T selector, DeleteFlags flags = DeleteFlags.none)
static void remove(T)(T selector, DeleteOptions options = DeleteOptions.init)
{
collection.remove(selector, flags);
collection.deleteMany(selector, options);
}

/// Removes all documents from this collection.
static void removeAll()
static void removeAll(DeleteOptions options = DeleteOptions.init)
{
collection.remove();
collection.deleteAll(options);
}

/// Drops the entire collection and all indices in the database.
Expand All @@ -681,15 +694,15 @@ mixin template MongoSchema()
/// ditto
static auto count(T)(T query)
{
return collection.count(query);
return collection.countDocuments(query);
}

/// Returns the count of documents in this collection.
static auto countAll()
{
import vibe.data.bson : Bson;

return collection.count(Bson.emptyObject);
return collection.countDocuments(Bson.emptyObject);
}

/// Start of an aggregation call. Returns a pipeline with typesafe functions for modifying the pipeline and running it at the end.
Expand Down Expand Up @@ -754,57 +767,30 @@ void register(T)(MongoCollection collection) @safe
}


static if (is(IndexOptions))
IndexOptions indexOptions;
static if (hasUDA!(member, mongoBackground))
{
indexOptions.background = true;
}
static if (hasUDA!(member, mongoDropDuplicates))
{
indexOptions.dropDups = true;
}
static if (hasUDA!(member, mongoSparse))
{
IndexOptions indexOptions;
static if (hasUDA!(member, mongoBackground))
{
indexOptions.background = true;
}
static if (hasUDA!(member, mongoDropDuplicates))
{
indexOptions.dropDups = true;
}
static if (hasUDA!(member, mongoSparse))
{
indexOptions.sparse = true;
}
static if (hasUDA!(member, mongoUnique))
{
indexOptions.unique = true;
}
static if (hasUDA!(member, mongoExpire))
{
indexOptions.expireAfterSeconds = cast(int)expires;
}
indexOptions.sparse = true;
}
else
static if (hasUDA!(member, mongoUnique))
{
IndexFlags flags = IndexFlags.None;
static if (hasUDA!(member, mongoBackground))
{
flags |= IndexFlags.Background;
}
static if (hasUDA!(member, mongoDropDuplicates))
{
flags |= IndexFlags.DropDuplicates;
}
static if (hasUDA!(member, mongoSparse))
{
flags |= IndexFlags.Sparse;
}
static if (hasUDA!(member, mongoUnique))
{
flags |= IndexFlags.Unique;
}
static if (hasUDA!(member, mongoExpire))
{
flags |= IndexFlags.ExpireAfterSeconds;
}

if (flags != IndexFlags.None || force)
collection.ensureIndex([tuple(name, 1)], flags, dur!"seconds"(expires));
indexOptions.unique = true;
}
static if (hasUDA!(member, mongoExpire))
{
indexOptions.expireAfterSeconds = cast(int)expires;
}

if (indexOptions != indexOptions.init)
collection.createIndex([name: 1], indexOptions);
}
}
}
Expand Down Expand Up @@ -1021,7 +1007,7 @@ unittest
auto client = connectMongoDB("127.0.0.1");
auto database = client.getDatabase("test");
MongoCollection users = database["users"];
users.remove(); // Clears collection
users.deleteAll(); // Clears collection

struct User
{
Expand Down Expand Up @@ -1056,10 +1042,10 @@ unittest
User faker;
faker.username = "Example";
faker.hash = sha512Of("PASSWORD").dup;
faker.profilePicture = "example-avatar.png";
faker.profilePicture = "faker-avatar.png";

assertThrown(faker.save());
// Unique username
assertThrown(faker.save());

faker.username = "Example_";
assertNotThrown(faker.save());
Expand Down Expand Up @@ -1129,7 +1115,7 @@ unittest
}

auto coll = client.getCollection("test.users2");
coll.remove();
coll.deleteAll();
coll.register!User;

User register(string name, string password)
Expand Down
35 changes: 32 additions & 3 deletions source/mongoschema/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ T bsonToMember(T)(auto ref T member, Bson value)
{ // Arrays of anything except strings
alias Type = typeof(member[0]);
if (value.type != Bson.Type.array)
throw new Exception("Cannot convert from BSON type " ~ value.type.to!string ~ " to array");
throw new Exception("Cannot convert from BSON type " ~ value.type.toString ~ " to array");
auto arr = value.get!(Bson[]);
auto ret = appender!T();
ret.reserve(arr.length);
Expand All @@ -206,7 +206,7 @@ T bsonToMember(T)(auto ref T member, Bson value)
alias Type = typeof(member[0]);
T values;
if (value.type != Bson.Type.array)
throw new Exception("Cannot convert from BSON type " ~ value.type.to!string ~ " to array");
throw new Exception("Cannot convert from BSON type " ~ value.type.toString ~ " to array");
auto arr = value.get!(Bson[]);
if (arr.length != values.length)
throw new Exception("Cannot convert from BSON array of length "
Expand Down Expand Up @@ -238,7 +238,7 @@ T bsonToMember(T)(auto ref T member, Bson value)
return cast(T) value.get!double;
else
throw new Exception(
"Cannot convert BSON from type " ~ value.type.to!string ~ " to " ~ T.stringof);
"Cannot convert BSON from type " ~ value.type.toString ~ " to " ~ T.stringof);
}
else static if (__traits(compiles, { value.get!T(); }))
{
Expand All @@ -256,6 +256,35 @@ T bsonToMember(T)(auto ref T member, Bson value)
}
}

// our own function instead of std.conv because it prints way too many deprecations
private string toString(Bson.Type type)
{
final switch (type)
{
case Bson.Type.end: return "end";
case Bson.Type.double_: return "double";
case Bson.Type.string: return "string";
case Bson.Type.object: return "object";
case Bson.Type.array: return "array";
case Bson.Type.binData: return "binData";
case Bson.Type.undefined: return "undefined";
case Bson.Type.objectID: return "objectID";
case Bson.Type.bool_: return "bool";
case Bson.Type.date: return "date";
case Bson.Type.null_: return "null";
case Bson.Type.regex: return "regex";
case Bson.Type.dbRef: return "dbRef";
case Bson.Type.code: return "code";
case Bson.Type.symbol: return "symbol";
case Bson.Type.codeWScope: return "codeWScope";
case Bson.Type.int_: return "int";
case Bson.Type.timestamp: return "timestamp";
case Bson.Type.long_: return "long";
case Bson.Type.minKey: return "minKey";
case Bson.Type.maxKey: return "maxKey";
}
}

string[] getSerializableMembers(alias obj)()
{
alias T = typeof(obj);
Expand Down

0 comments on commit b90891c

Please sign in to comment.