Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
264 views
in Technique[技术] by (71.8m points)

javascript - How to extend EJSON to serialize RegEx for Meteor Client-Server interactions?

I have an arbitrary (E)JSON that gets created and sent over the wire from client to server in my Meteor app. It uses RegExp objects to zero-in on results:

# on the client
selector = 
  "roles.user": { "$ne": null } 
  "profile.email": /^admin@/gi 

All is dandy fine on the client side, but if I pass this to the server via Meteor.call or Meteor.subscribe, the resulting (E)JSON takes this form:

# on the server
selector =
  "roles.user": { "$ne": null }
  "profile.email": {}

...and somewhere an engineer dies a little on the inside.

There are plenty of resources on the Web explaining why RegEx is unserializable via JSON.stringify/JSON.parse or the equivalent EJSON methods.

I'm not convinced RegEx serialization is impossible. So how can it be done?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

After reviewing this HowTo and the Meteor EJSON Docs, we may serialize RegEx using the EJSON.addType method.

Extend RegExp - Provide RegExp with the methods EJSON.addType requires for implementation.

RegExp::options = ->
  opts = []
  opts.push 'g' if @global
  opts.push 'i' if @ignoreCase
  opts.push 'm' if @multiline
  return opts.join('')

RegExp::clone = ->
  self = @
  return new RegExp(self.source, self.options())

RegExp::equals = (other) ->
  self = @
  if other isnt instanceOf RegExp
    return false
  return EJSON.stringify(self) is EJSON.stringify(other)

RegExp::typeName = ->
  return "RegExp"

RegExp::toJSONValue = ->
  self = @
  return {
    'regex': self.source
    'options': self.options()
  }

Call EJSON.addType - Do this anywhere. It's best to make it available to client AND server though. This is going to deserialize the object defined in toJSONValue above.

EJSON.addType "RegExp", (value) ->
  return new RegExp(value['regex'], value['options'])

Test In Your Console - Don't take my word for it. See for yourself.

> o = EJSON.stringify(/^Mooo/ig)
"{"$type":"RegExp","$value":{"regex":"^Mooo","options":"ig"}}"
> EJSON.parse(o)
/^Mooo/gi

And there you have a RegExp being serialized and parsed on client and server, able to be passed in over the wire, saved in a Session, and even possibly stored in a Collection of queries!

EDIT to addess IE10+ Error: Assignment to read-only properties is not allowed in strict mode Courtesy of @Tim Fletcher in the comments

import { EJSON } from 'meteor/ejson';

function getOptions(self) {
  const opts = [];
  if (self.global) opts.push('g');
  if (self.ignoreCase) opts.push('i');
  if (self.multiline) opts.push('m');
  return opts.join('');
}

RegExp.prototype.clone = function clone() {
  return new RegExp(this.source, getOptions(this));
};

RegExp.prototype.equals = function equals(other) {
  if (!(other instanceof RegExp)) return false;
  return EJSON.stringify(this) === EJSON.stringify(other);
};

RegExp.prototype.typeName = function typeName() {
  return 'RegExp';
};

RegExp.prototype.toJSONValue = function toJSONValue() {
  return { regex: this.source, options: getOptions(this) };
};

EJSON.addType('RegExp', value => new RegExp(value.regex, value.options));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...