Meteor-Community-Packages / meteor-collection2

A Meteor package that extends Mongo.Collection to provide support for specifying a schema and then validating against that schema when inserting and updating.
https://packosphere.com/aldeed/collection2
MIT License
1.02k stars 108 forks source link

proof-of-concept(wip): allow custom validator #447

Open jankapunkt opened 5 months ago

jankapunkt commented 5 months ago

We all know that this library is on the one hand crucial for modern Meteor Apps, at the same time it's still tightly coupled with SimpleSchema.

This PR is a current proof of concept (not it's work-in-progress status) to make it independent from Simple Schema.

The idea is to be non-breaking for SimpleSchema users but provide all necessary functionality for other validation libs, like zod, ajv etc.

This change requires users to register a "validator" object that implements certain methods. Consider the example for Simple Schema (also located in tests/prepare.js:

import SimpleSchema from "meteor/aldeed:simple-schema";

Collection2.defineValidation({
  name: 'SimpleSchema',

  // check if the schema is a schema instance
  is: schema => SimpleSchema.isSimpleSchema(schema),

  // create a new schema instance by definition object
  create: schema => new SimpleSchema(schema),

  // extend the schema, I don't know if other libs support this...
  extend: (s1, s2) => {
    if (s2.version >= 2) {
      const ss = new SimpleSchema(s1);
      ss.extend(s2);
      return ss;
    } else {
      return new SimpleSchema([s1, s2]);
    }
  },

  // mutated cleaning of a doc or modifier, I don't know mofidier support in other libs
  clean: ({ doc, modifier, schema, userId, isLocalCollection, type }) => {
    const isModifier = !Collection2.isInsertType(type);
    const target = isModifier ? modifier : doc;
    schema.clean(target, {
      mutate: true,
      isModifier,
      // We don't do these here because they are done on the client if desired
      filter: false,
      autoConvert: false,
      removeEmptyStrings: false,
      trimStrings: false,
      extendAutoValueContext: {
        isInsert: Collection2.isInsertType(type),
        isUpdate: Collection2.isUpdateType(type),
        isUpsert: Collection2.isUpdateType(type),
        userId,
        isFromTrustedCode: false,
        docId: doc?._id,
        isLocalCollection
      }
    })
  },
  // incomplete yet, will be added once it's implemented
  validate: () => {},

  // the idea is to freeze the validator to avoid any tampering or redefining
  freeze: false
});

The hard part is to extract all Simple-Schema-specific code into this validator without breaking things and at the same time get the abstraction done in a way it will smoothly work with other libs.

Current status: