Skip to content

Instantly share code, notes, and snippets.

@mtth
Last active November 17, 2015 06:22
Show Gist options
  • Save mtth/5cd7e3f62e258a545291 to your computer and use it in GitHub Desktop.
Save mtth/5cd7e3f62e258a545291 to your computer and use it in GitHub Desktop.
Instrument Avro types
/* jshint node: true */
'use strict';
var avsc = require('avsc');
/**
* Function returning an instrumented type.
*
* @param schema {Object} Schema to parse.
*
* When passed a buffer to decode, the instrumented type will return a
* wrapped decoded value, with start and end markers for each value.
*
* Sample usage:
*
* var instrumentedType = instrument(schema);
* var obj = instrumentedType.fromBuffer(buf);
*
*/
function instrument(schema) {
if (schema instanceof avsc.types.Type) {
schema = schema.getSchema();
}
var refs = []; // Array of previously seen schemas, to avoid cycles.
return avsc.parse(schema, {typeHook: hook});
function hook(schema, opts) {
if (~refs.indexOf(schema)) {
return;
}
refs.push(schema);
if (schema.type === 'record') {
// Defaults (if any) won't correspond to the wrapped schema, we remove
// them (they wouldn't be used anyway).
schema.fields.forEach(function (f) { f['default'] = undefined; });
}
var name = schema.name;
if (name) {
// Rewire the name (attaching it to the wrapper and replacing the
// original schema's) for name references to work correctly.
schema.name = 'r' + Math.random().toString(36).substr(2, 6);
}
var wrappedSchema = {
name: name || 'r' + Math.random().toString(36).substr(2, 6),
namespace: schema.namespace,
type: 'record',
fields: [{name: 'value', type: schema}]
};
refs.push(wrappedSchema);
// Create type and override read method to place start and end markers.
var type = avsc.parse(wrappedSchema, opts);
var read = type._read;
type._read = function (tap) {
var pos = tap.pos;
var obj = read.call(type, tap);
obj.start = pos;
obj.end = tap.pos;
return obj;
};
return type;
}
}
/**
* Convenience method to instrument a single object.
*
* @param type {Type} The type to be instrumented.
* @param obj {Object} A valid instance of `type`.
*
* Returns an representation of `obj` with start and end markers.
*
*/
function instrumentObject(type, obj) {
return instrument(type).fromBuffer(type.toBuffer(obj));
}
@mtth
Copy link
Author

mtth commented Oct 22, 2015

For example:

var type = avsc.parse({
  name: 'Cat',
  type: 'record',
  fields: [
    {name: 'name', type: 'string'},
    {name: 'age', type: 'int'},
    {name: 'napTimes', type: {type: 'array', items: 'long'}}
  ]
});

var obj = {
  name: 'Theodore',
  age: 17,
  napTimes: [1239012, 1239315]
};

var instrumentedObj = instrumentObject(type, obj);
//  == {
//   "value": {
//     "name": {
//       "value": "Theodore",
//       "start": 0,
//       "end": 9
//     },
//     "age": {
//       "value": 17,
//       "start": 9,
//       "end": 10
//     },
//     "napTimes": {
//       "value": [
//         {
//           "value": 1239012,
//           "start": 11,
//           "end": 15
//         },
//         {
//           "value": 1239315,
//           "start": 15,
//           "end": 19
//         }
//       ],
//       "start": 10,
//       "end": 20
//     }
//   },
//   "start": 0,
//   "end": 20
// }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment