jagi / meteor-astronomy

Model layer for Meteor

Home Page:https://atmospherejs.com/jagi/astronomy

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Integrating Astro class with meteor/ostrio:files

kurvenschubser opened this issue · comments

Hi there,

trying to make Astronomy class work with Meteor-Files. This is what I tried:

import { FilesCollection } from "meteor/ostrio:files";
import { Class } from "meteor/jagi:astronomy";
import dayjs from "dayjs";

const Avatars = new FilesCollection({
  storagePath: "/home/gitpod/uploads/Avatars",
  downloadRoute: "/files/avatars",
  collectionName: "Avatars",
});

const Avatar = Class.create({
  name: "Avatar",
  collection: Avatars,
  fields: {
    createdAt: {
      type: Date,
      immutable: true,
      default() {
        return dayjs().toDate();
      },
    },
  },
});

But on startup I get:
TypeError: ["Avatar" class]["collection" property] Property value has to be an instance of "Mongo.Collection"

Hi,

I haven't tried it but from what I see the FilesCollection constructor is a wrapper around Mongo.Collection and you should be able to access the actual collection by writing Avatars.collection, so try this:

import { FilesCollection } from "meteor/ostrio:files";
import { Class } from "meteor/jagi:astronomy";
import dayjs from "dayjs";

const Avatars = new FilesCollection({
  storagePath: "/home/gitpod/uploads/Avatars",
  downloadRoute: "/files/avatars",
  collectionName: "Avatars",
});

const Avatar = Class.create({
  name: "Avatar",
  collection: Avatars.collection,
  fields: {
    createdAt: {
      type: Date,
      immutable: true,
      default() {
        return dayjs().toDate();
      },
    },
  },
});

Ok, that does get rid of the error. I was thinking I could do something like this, using "File" as a type.
const Avatar = Class.create({ name: "Avatar", collection: Avatars.collection, fields: { file: { type: File } });

But I get an error:
Uncaught TypeError: ["Avatar" class]["fields" property]["file" field] Type does not exist.

@kurvenschubser each type has to be registered. Here is documentation: https://jagi.github.io/meteor-astronomy/#custom-types

Alright, thanks for the hint... expanding the example

import Avatars from "../collections/Avatars";

const Avatar = Class.create({
  name: "Avatar",
  collection: Avatars.collection,
  fields: {
    createdAt: {
      type: Date,
      immutable: true,
      default() {
        return dayjs().toDate();
      },
    },
    fileName: {
      type: String,
      required: false,
    },
    fileSize: {
      type: Number,
      required: false,
    },
    filePath: {
      type: String,
      required: false,
    },
    fileExt: {
      type: String,
      required: false,
    },
  },
});

if (Meteor.isClient) {
  console.log("AvatarDef.Meteor.isClient");
  import { Type, Validator } from "meteor/jagi:astronomy";
  const validateIsFile = Validator.create({
    name: "isFile",
    parseParam(param) {
      if (!(param instanceof File)) {
        console.log(param);
        throw new TypeError(
          `Parameter for the "isFile" validator has to be a file`
        );
      }
    },
    isValid({ value, param }) {
      return value instanceof File;
    },
    resolveError({ name, param }) {
      return `Type of "${name}" has to a file`;
    },
  });

  Type.create({
    name: "File",
    class: File,
    validate(args) {
      validateIsFile(args);
    },
  });

  Avatar.extend({
    fields: {
      file: {
        type: File,
      },
    },
    events: {
      beforeSave(e) {
        const doc = e.currentTarget;
        console.log("avatar.events.beforesave, doc=", doc);
      },
    },
  });
}

Before I set the avatar.file to a File (from ) I can log it to console, it's a "File" just as expected. However in the log in the beforeSave event, the doc.file field only has an empty Object, not a "File". What am I missing?

I think what actually happens there is that it tries serialize it to send over the wire, from the client to server or the other way around. The File type is a custom type and doesn't come with the toJSONValue and fromJSONValue that are being used for serialization.

I don't remember precisely but I was dealing with something like that without actually storing file as the property of the class. You don't really need an entire file in both client and server. You could have the Avatar class that only has some properties from the File class that you care about and you can copy them. Even exposing an entire File class doesn't seem like a good idea. To much data will be sent over the network.

Hmm, maybe I could write a custom Field Type or setter? On setting the file field to a File object I would like to validate it has max size and so on, then an saving the doc, I would do the file upload with ostrio:files and await the result. Then save the URL or file object id in the Avatar doc. Could you pont me in the right direction?

Sorry, but I don't provide business support, I have my own job and a lot of daily responsibilities. I've also mentioned it several times in GitHub issues and in docs that most application logic should end up in Meteor methods (that's also what MDG recommends). There is the meteorMethods property on the Astro class that you can use to define methods. You can do all the validation there and set some fields in the document. But a lot depends on your business logic

No business, just my hobby ;) I'll take a different approach. Thanks anyways.

I know :) but still I can't help everyone even though I would like to