haxe-js-kit icon indicating copy to clipboard operation
haxe-js-kit copied to clipboard

Mongoose discriminators

Open zabojad opened this issue 9 years ago • 5 comments

Hi !

I need to implement Mongoose discriminators : http://mongoosejs.com/docs/discriminators.html

I believe it's not supported yet by the haxe js kit...

If it's indeed so, what would be the best way to support it so that it supports both ways of declaring schemas (macro and non-macro ways) ?

Thanks

zabojad avatar Jan 25 '16 16:01 zabojad

I guess you can start by adding the needed signatures (for example, add discriminatorKey in SchemaOptions : https://github.com/clemos/haxe-js-kit/blob/develop/js/npm/mongoose/Schema.hx#L36-L52) Then I don't really know how it could fit with macros, as I don't really know this feature. I'll try to look into it this week. Meanwhile, feel free to let me know how you would see the integration.

clemos avatar Jan 25 '16 16:01 clemos

Ok, I have a working but ugly start (see #107 ).

It gives this kind of use:

typedef FilterTypeData = {
    var title : String;
}

typedef FilterTypeChoiceData = {
    > FilterTypeData,
    var choices : Array<{ id : String, title : String }>;
}

typedef FilterTypeInputData = {
    > FilterTypeData,
    var inputType : String; // possible values: "date", "time", "number", "text"...
}

@:schemaOptions({
    versionKey: false,
    discriminatorKey: "type"
})
class FilterType extends Model<FilterTypeData>{}

class FilterTypeChoice extends Model<FilterTypeChoiceData>{}

class FilterTypeInput extends Model<FilterTypeInputData>{}

class FilterTypeManager extends Manager<FilterTypeData, FilterType>{}

class FilterTypeDao {

    public function new(db : Mongoose) {

        md = FilterTypeManager.build(db, "FilterType");

        // choiceMd = md.discriminator("FilterTypeChoice", FilterTypeChoiceData);
        choiceMd = md.discriminator("FilterTypeChoice", new js.npm.mongoose.Schema({ choices : [{ id : "String", title : "String" }] }, { versionKey: false, discriminatorKey: "type" })); // temporary as we can't use the macro way yet

        // inputMd = md.discriminator("FilterTypeInput", FilterTypeInputData);
        inputMd = md.discriminator("FilterTypeInput", new js.npm.mongoose.Schema({ inputType : "String" }, { versionKey: false, discriminatorKey: "type" })); // temporary as we can't use the macro way yet
    }

    public var md (default, null) : TModels<FilterTypeData, FilterType>;

    public var choiceMd (default, null) : TModels<FilterTypeChoiceData, FilterTypeChoice>;

    public var inputMd (default, null) : TModels<FilterTypeInputData, FilterTypeInput>;
}

zabojad avatar Jan 25 '16 19:01 zabojad

You should be able to do: choiceMd = md.discriminator("FilterTypeChoice", FilterTypeChoice.Schema);

clemos avatar Jan 25 '16 19:01 clemos

Yes, indeed ! It looks much nicer this way...

So, to recap, we have:

package wink.server.db.dao;

import js.npm.mongoose.macro.Manager;
import js.npm.mongoose.macro.Model;
import js.npm.mongoose.Model.TModels;
import js.npm.mongoose.Mongoose;
import js.npm.mongoose.Query;

import js.support.Callback;

typedef FilterTypeData = {
    var title : String;
}

typedef FilterTypeChoiceData = {
    > FilterTypeData,
    var choices : Array<{ id : String, title : String }>;
}

typedef FilterTypeInputData = {
    > FilterTypeData,
    var inputType : String; // possible values: "date", "time", "number", "text"...
}

@:schemaOptions({
    versionKey: false,
    discriminatorKey: "type"
})
class FilterType extends Model<FilterTypeData>{}

@:schemaOptions({
    versionKey: false,
    discriminatorKey: "type"
})
class FilterTypeChoice extends Model<FilterTypeChoiceData>{}

@:schemaOptions({
    versionKey: false,
    discriminatorKey: "type"
})
class FilterTypeInput extends Model<FilterTypeInputData>{}

class FilterTypeManager extends Manager<FilterTypeData, FilterType>{}

class FilterTypeDao {

    public function new(db : Mongoose) {

        md = FilterTypeManager.build(db, "FilterType");

        choiceMd = md.discriminator("FilterTypeChoice", FilterTypeChoice.Schema);

        inputMd = md.discriminator("FilterTypeInput", FilterTypeInput.Schema);
    }

    public var md (default, null) : TModels<FilterTypeData, FilterType>;

    public var choiceMd (default, null) : TModels<FilterTypeChoiceData, FilterTypeChoice>;

    public var inputMd (default, null) : TModels<FilterTypeInputData, FilterTypeInput>;
}

I think it's really acceptable and there is no need for extra macro stuff... What do you think? All this has been tested and works...

zabojad avatar Jan 25 '16 21:01 zabojad

If you tested it, then I guess it's fine. I just wonder if your FilterTypeChoice.Schema contains the title field, which would be wrong (?). But ITOH when not using disciminator, you do want to have all the fields, so not generating the full schema when using an extension would be a bug...

Also, does the type system ensures that the discriminator model is an extension of the source model ? If not, it's still ok, but it would be nice to figure out a way to leverage the type system to ensure that.

clemos avatar Jan 26 '16 09:01 clemos