December 11, 2019
How can I cast Bson (vibe.d) to various struct types? The best would be to get rid of the switch statement as well.

It works fine deserializing when casting directly collection.findOne!UserCreate(), but when I try from a Bson object I get below error directly.

What to do?

The error I get when using event.get!UserCreate() is the following:

    store ~master: building configuration "application"...
    /home/tirithen/.dub/packages/vibe-d-0.8.6/vibe-d/data/vibe/data/bson.d(603,4): Error: static assert:  "Cannot cast const(Bson) to 'UserCreate'."
    source/app.d(100,23):        instantiated from here: get!(UserCreate)
    /usr/bin/dmd failed with exit code 1.

The relevant part of the code looks like this:

    module store.app;

    import std.stdio : writeln;
    import std.uuid : UUID, randomUUID;
    import std.datetime.systime : SysTime;
    import std.datetime.timezone : UTC;
    import std.typecons : Nullable;
    import std.exception : enforce;
    import vibe.d : runApplication;
    import vibe.db.mongo.mongo : MongoCollection, connectMongoDB;
    import vibe.data.bson : Bson, fromBsonData;

    import store.hash : hashString;
    import store.events;
    import store.mongo.mongo;
    import store.mongo.lock;

    struct UserCreate
    {
    	EventMeta meta;
    	string username;
    	string email;

    	void applyTo(ref User user)
    	{
    		user.username = this.username;
    		user.email = this.email;
    	}
    }

    struct UserChangePassword
    {
    	EventMeta meta;
    	string password;

    	void applyTo(ref User user)
    	{
    		user.password = this.password;
    	}
    }

    struct UserChangeUsername
    {
    	EventMeta meta;
    	string username;

    	void applyTo(ref User user)
    	{
    		user.username = this.username;
    	}
    }

    struct UserChangeEmail
    {
    	EventMeta meta;
    	string email;

    	void applyTo(ref User user)
    	{
    		user.unverifiedEmail = this.email;
    	}
    }

    struct UserVerifiedEmail
    {
    	EventMeta meta;
    	string email;

    	void applyTo(ref User user)
    	{
    		user.email = this.email;
    		user.unverifiedEmail = "";
    	}
    }

    struct User
    {
    	Meta meta;
    	string username;
    	string email;
    	string unverifiedEmail;
    	string password;
    }

    User loadUser(MongoCollection collection, UUID streamId)
    {
    	auto user = User();
    	auto userEvents = collection.find(Bson(["meta.streamId": Bson(streamId)]));

    	foreach (Bson event; userEvents)
    	{
    		string type = event["meta"]["type"].get!string;
    		writeln("type: ", type);
    		switch (type)
    		{
    		default:
    			writeln("No handler found for type " ~ type ~ ", skipping event.");
    			break;
    		case "UserCreate":
    			applyTo(user, event.get!UserCreate());
    			break;
    		case "UserChangePassword":
    			applyTo(user, event.get!UserChangePassword());
    			break;
    		case "UserChangeUsername":
    			applyTo(user, event.get!UserChangeUsername());
    			break;
    		case "UserChangeEmail":
    			applyTo(user, event.get!UserChangeEmail());
    			break;
    		case "UserVerifiedEmail":
    			applyTo(user, event.get!UserVerifiedEmail());
    			break;
    		}
    	}

    	return user;
    }

    void main()
    {
    	auto connection = Mongo("127.0.0.1", "testing");

    	MongoCollection userEvents = connection.getCollection("userEvents");
    	createEventIndexes(userEvents);

    	auto user = loadUser(userEvents, UUID("95395448-e1b5-458c-a309-6e6842d06505"));
    	writeln(user);

    	runApplication();
    }