meteor-astronomy icon indicating copy to clipboard operation
meteor-astronomy copied to clipboard

ENUM import/export bug

Open talha-asad opened this issue 7 years ago • 11 comments

Say we have a file that has a campaign class and a Enum that is used within that class. This file exports the ENUM too. Now we have another file that imports the ENUM from that file and then reuses it in one of its own class, this doesn't work and I keep getting this error on the server console:

TypeError: ["ExpressCampaign" class]["fields" property]["state" field] Type does not exist

Below is a basic level copy of files:

campaigns.js

import { Mongo } from 'meteor/mongo';
import { Class, Enum } from 'meteor/jagi:astronomy';
Campaigns = new Mongo.Collection('campaigns');

export const CampaignStatusEnum = Enum.create({
  name: 'CampaignStatusEnum',
  identifiers: {
    INCOMPLETE: 1,
    PENDING: 2,
    ISSUE: 3,
    RUNNING: 4,
    PAUSED: 5,
    FUTURE: 6,
    FINISHED: 7,
    REMOVED: 8
  }
});

Campaign = Class.create({
  name: 'Campaign',
  secured: false,
  collection: Campaigns,
  typeField: 'network',
  fields: {
    _id: {type: String, index: 1},
    user_id: {type: String},
    geomesh_id: {type: String, optional: true, index: 1},
    name: {type: String},
    state: {type: CampaignStatusEnum, default: CampaignStatusEnum.PENDING, index: 1},
    created_at: {type: Date, default() { return new Date(); }, index: -1},
    updated_at: {type: Date, default() { return new Date(); }, index: -1}
  }
});

express_campaigns.js

import { Mongo } from 'meteor/mongo';
import { Class, Enum } from 'meteor/jagi:astronomy';
import { CampaignStatusEnum } from './campaigns';

ExpressCampaigns = new Mongo.Collection('express_campaigns');

ExpressCampaign = Class.create({
  name: 'ExpressCampaign',
  collection: ExpressCampaigns,
  fields: {
    _id: {type: String, index: 1},
    user_id: {type: String, index: 1},
    geomesh_id: {type: String, optional: true, index: 1},
    name: {type: String},
    type: {type: String, optional: true, index: 1},
    state: {type: CampaignStatusEnum, default: CampaignStatusEnum.PENDING, index: 1},
    created_at: {type: Date, default() { return new Date(); }, index: -1},
    updated_at: {type: Date, default() { return new Date(); }, index: -1}
  }
});

talha-asad avatar Apr 05 '17 06:04 talha-asad

The problem is probably in not importing all the classes on the server. Remember that you have to import classes not only on the client but also on the server, even when you're not using them directly. Problem is similar to the one I've talked about in this tutorial https://www.youtube.com/watch?v=fM11TSiELNE&feature=youtu.be&t=550 with the exception that you're dealing with ENUM and not class stored in collection directly.

lukejagodzinski avatar Apr 05 '17 08:04 lukejagodzinski

The classes are available globally, do I still need to export them? In that case the error is still very misleading. Doing a simple console.log on the ENUM shows that it is infact defined and fully functional.

talha-asad avatar Apr 05 '17 09:04 talha-asad

But CampaignStatusEnum is not global, so you have to import it in both client and server. Let's imagine this situation. All classes are global on both client and server and you're trying to create instance of the Campaign class. This class has the state property which is of the CampaignStatusEnum type and has default value. When you perform the save operation then it will try to create instance of this class also on the server and if CampaignStatusEnum is not available through import or it's not global then Astronomy will not know where to look for this type.

lukejagodzinski avatar Apr 05 '17 10:04 lukejagodzinski

Makes sense and I made all ENUMs global and the error remains. The error isn't because it's not defined, I specifically imported it and it was available and the error was on the server side, where I did check it to be available. So something else is definitely amiss.

talha-asad avatar Apr 05 '17 11:04 talha-asad

OK so please create minimal reproduction repository so I will be able to tell if you're missing something or it's a problem with Astronomy. But first let's check what is in the Astro.Type.types object.

import { Type } from 'meteor/jagi:astronomy';
console.log(Type.types);

Log it on the server just before the place where it's used and it's missing.

lukejagodzinski avatar Apr 05 '17 12:04 lukejagodzinski

The ENUM in question, shows up in the log:

CampaignStatusEnum: 
  Type {
    name: 'CampaignStatusEnum',
    class: 
      { [Function: Enum]
        getIdentifiers: [Function],
        getIdentifier: [Function],
        PENDING: 1,
        ISSUE: 2,
        RUNNING: 3,
        PAUSED: 4,
        FUTURE: 5,
        FINISHED: 6,
        DELETED: 7 },
    validate: [Function] }

For a reproduction, the two above files I gave in the first post should suffice. You should name one as campaigns.js and the other one as express_campaign.js and put them in the same dir.

talha-asad avatar Apr 05 '17 13:04 talha-asad

Code works properly, so the problem is on your side. One thing you're doing wrong is mixing imports and globals. You should decide which way of programming you choose. I would encourage you to use imports as you can control import order. And your problem may be related with the order, that you're using ENUM before it's defined. You should also put ENUM in the separate file and import it into these two that you've posted here. Once you make sure that load order is correct, then everything should work properly.

And for future, please always create reproduction. I don't have time to create reproductions as in 90% situations it's developer's fault that something is not working. I want to help but you also have to do some work to let me help you.

lukejagodzinski avatar Apr 05 '17 16:04 lukejagodzinski

Deeply sorry jagi, when I created a reproduction the error indeed stopped coming up. I'll dig into why this is happening in my main project. Will submit reproductions next time. I was pretty sure this is a standalone issue, aah well.

talha-asad avatar Apr 05 '17 17:04 talha-asad

No problem :) As I said I think the problem may be in load order, so use imports instead of globals. That's much more reliable.

lukejagodzinski avatar Apr 05 '17 17:04 lukejagodzinski

The problem was that the same ENUM was being defined twice, on which btw Astronomy gave no error, and I think the other one was being declared later and when the previous (imported) one was being used, it wasn't strictly matching with the new one and Astro was throwing that error. Perhaps the error message can be improved in this case?

Don't allow same ENUM name to be declared twice, period. Or Throw more informative error when the type being used is not the same as the one last declared with that same name.

I'd still pick first, makes things much easier. Something useful did finally came out of this 👍

talha-asad avatar Apr 05 '17 17:04 talha-asad

Hmm right, now it's possible to redeclare ENUM which should not be possible. I will make a fix for that. Thanks for noticing it!

lukejagodzinski avatar Apr 05 '17 20:04 lukejagodzinski