Sample type hook implementations for avro.parse
.
Last active
July 19, 2018 02:51
-
-
Save mtth/c0088c745de048c4e466 to your computer and use it in GitHub Desktop.
Avro type hooks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* jshint node: true */ | |
'use strict'; | |
var avro = require('avsc'); | |
/** | |
* Type hook to allow "inlining" record fields. | |
* | |
* This can be useful to work around Avro's lack of inheritance support. | |
* | |
* If any record fields contain another record and have an "inline" attribute | |
* set, this hook will add the inner record's fields directly to the outer | |
* record. For example using this hook on the following schema (using IDL | |
* notation): | |
* | |
* record Foo { | |
* record Bar { | |
* int one; | |
* int two; | |
* } @inline(true) bar; | |
* int three; | |
* } | |
* | |
* Will create a type equivalent to: | |
* | |
* record Foo { | |
* int one; | |
* int two; | |
* int three; | |
* } | |
* | |
*/ | |
function typeHook(attrs, opts) { | |
if (attrs.type !== 'record') { | |
// Inlining only applies to records. | |
return; | |
} | |
var fields = []; | |
var namespace = opts.namespace; | |
opts.namespace = attrs.namespace || opts.namespace; | |
attrs.fields.forEach(function (fieldAttrs) { | |
if (!fieldAttrs.inline) { | |
// Default behavior. | |
fields.push(fieldAttrs); | |
return; | |
} | |
var type; | |
if (typeof fieldAttrs.type === 'string') { | |
// This is a reference, we must obtain the underlying type. | |
var name = fieldAttrs.type; | |
if (!~name.indexOf('.') && opts.namespace) { | |
name = opts.namespace + '.' + name; | |
} | |
type = opts.registry[name]; | |
if (!type) { | |
// Just add the undefined reference so that `parse` can throw an | |
// appropriate "undefined type" error. | |
fields.push(fieldAttrs); | |
return; | |
} | |
} else { | |
type = avro.parse(fieldAttrs.type, opts); | |
} | |
if (!avro.Type.isType(type, 'record', 'error')) { | |
throw new Error('only record fields can be inlined'); | |
} | |
type.fields.forEach(function (inlinedField) { | |
// Note that we don't need to check for duplicates here since that will | |
// be done by `parse` when it creates the type after the hook returns. | |
fields.push({ | |
aliases: inlinedField.aliases, | |
'default': inlinedField.defaultValue(), | |
name: inlinedField.name, | |
order: computeOrder(inlinedField.order), | |
type: inlinedField.type | |
}); | |
}); | |
function computeOrder(order) { | |
// If the inlined field has a descending order, we must "invert" all its | |
// fields' orders. Similarly for ignored. | |
if (order === 'ignore' || fieldAttrs.order === 'ignore') { | |
return 'ignore'; | |
} | |
switch (fieldAttrs.order || 'ascending') { | |
case 'descending': | |
return order === 'ascending' ? 'descending' : 'ascending'; | |
case 'ascending': | |
return order; | |
default: | |
throw new Error('invalid order: ' + fieldAttrs.order); | |
} | |
} | |
}); | |
opts.namespace = namespace; | |
attrs.fields = fields; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* jshint node: true */ | |
'use strict'; | |
var avro = require('avsc'); | |
/** | |
* Hook which will decode/encode enums to/from integers. | |
* | |
* The default `EnumType` implementation represents enum values as strings | |
* (consistent with the JSON representation). This hook can be used to provide | |
* an alternate representation (which is for example compatible with TypeScript | |
* enums). | |
* | |
* For simplicity, we don't do any bound checking here but we could by | |
* implementing a "bounded long" logical type and returning that instead. | |
* | |
*/ | |
function typeHook(attrs, opts) { | |
if (attrs.type === 'enum') { | |
return avro.parse('long', opts); | |
} | |
// Falling through will cause the default type to be used. | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* jshint node: true */ | |
'use strict'; | |
/** | |
* Hook to obfuscate a schema. | |
* | |
* This hook will produce a type with the names of records, fixed, enums, | |
* fields, and symbols mangled. | |
* | |
*/ | |
function typeHook(attrs) { | |
if (!attrs.name) { | |
return; // Nothing to mangle. | |
} | |
attrs.name = randomString(); | |
var fields, symbols; | |
if ((fields = attrs.fields)) { | |
fields.forEach(function (o) { o.name = randomString(); }); | |
} else if ((symbols = attrs.symbols)) { | |
symbols.forEach(function (s, i) { symbols[i] = randomString(); }); | |
} | |
} | |
function randomString() { (Math.random() + 1).toString(36).substring(8); } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment