@confluentinc/schemaregistry
Version:
Node.js client for Confluent Schema Registry
816 lines (815 loc) • 30.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RuleConditionError = exports.RuleError = exports.NoneAction = exports.ErrorAction = exports.FieldType = exports.FieldContext = exports.FieldRuleExecutor = exports.RuleContext = exports.PrefixSchemaIdDeserializer = exports.DualSchemaIdDeserializer = exports.PrefixSchemaIdSerializer = exports.HeaderSchemaIdSerializer = exports.TopicNameStrategy = exports.Deserializer = exports.Serializer = exports.Serde = exports.SerializationError = exports.SchemaId = exports.VALUE_SCHEMA_ID_HEADER = exports.KEY_SCHEMA_ID_HEADER = exports.MAGIC_BYTE_V1 = exports.MAGIC_BYTE_V0 = exports.MAGIC_BYTE = exports.SerdeType = void 0;
const wildcard_matcher_1 = require("./wildcard-matcher");
const schemaregistry_client_1 = require("../schemaregistry-client");
const rule_registry_1 = require("./rule-registry");
const buffer_wrapper_1 = require("./buffer-wrapper");
var SerdeType;
(function (SerdeType) {
SerdeType["KEY"] = "KEY";
SerdeType["VALUE"] = "VALUE";
})(SerdeType || (exports.SerdeType = SerdeType = {}));
exports.MAGIC_BYTE = Buffer.alloc(1);
exports.MAGIC_BYTE_V0 = exports.MAGIC_BYTE;
exports.MAGIC_BYTE_V1 = Buffer.alloc(1, 1);
exports.KEY_SCHEMA_ID_HEADER = '__key_schema_id';
exports.VALUE_SCHEMA_ID_HEADER = '__value_schema_id';
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
byteToHex.push((i + 0x100).toString(16).slice(1));
}
class SchemaId {
constructor(schemaType, id, guid, messageIndexes) {
this.schemaType = schemaType;
this.id = id;
this.guid = guid;
this.messageIndexes = messageIndexes;
}
fromBytes(payload) {
let totalBytesRead = 0;
const magicByte = payload.subarray(0, 1);
if (magicByte.equals(exports.MAGIC_BYTE_V0)) {
this.id = payload.subarray(1, 5).readInt32BE(0);
totalBytesRead = 5;
}
else if (magicByte.equals(exports.MAGIC_BYTE_V1)) {
this.guid = this.stringifyUuid(payload.subarray(1, 17));
totalBytesRead = 17;
}
else {
throw new SerializationError(`Unknown magic byte ${JSON.stringify(magicByte)}`);
}
if (this.schemaType == "PROTOBUF") {
const [bytesRead, msgIndexes] = this.readMessageIndexes(payload.subarray(totalBytesRead));
this.messageIndexes = msgIndexes;
totalBytesRead += bytesRead;
}
return totalBytesRead;
}
stringifyUuid(arr, offset = 0) {
return (byteToHex[arr[offset + 0]] +
byteToHex[arr[offset + 1]] +
byteToHex[arr[offset + 2]] +
byteToHex[arr[offset + 3]] +
'-' +
byteToHex[arr[offset + 4]] +
byteToHex[arr[offset + 5]] +
'-' +
byteToHex[arr[offset + 6]] +
byteToHex[arr[offset + 7]] +
'-' +
byteToHex[arr[offset + 8]] +
byteToHex[arr[offset + 9]] +
'-' +
byteToHex[arr[offset + 10]] +
byteToHex[arr[offset + 11]] +
byteToHex[arr[offset + 12]] +
byteToHex[arr[offset + 13]] +
byteToHex[arr[offset + 14]] +
byteToHex[arr[offset + 15]]).toLowerCase();
}
idToBytes() {
if (this.id == null) {
throw new SerializationError('Schema id is not set');
}
const idBuffer = Buffer.alloc(4);
idBuffer.writeInt32BE(this.id, 0);
if (this.messageIndexes != null) {
return Buffer.concat([exports.MAGIC_BYTE_V0, idBuffer, this.writeMessageIndexes(this.messageIndexes)]);
}
return Buffer.concat([exports.MAGIC_BYTE_V0, idBuffer]);
}
guidToBytes() {
if (this.guid == null) {
throw new SerializationError('Schema guid is not set');
}
const guidBuffer = Buffer.from(this.parseUuid(this.guid));
if (this.messageIndexes != null) {
return Buffer.concat([exports.MAGIC_BYTE_V1, guidBuffer, this.writeMessageIndexes(this.messageIndexes)]);
}
return Buffer.concat([exports.MAGIC_BYTE_V1, guidBuffer]);
}
parseUuid(uuid) {
let v;
return Uint8Array.of((v = parseInt(uuid.slice(0, 8), 16)) >>> 24, (v >>> 16) & 0xff, (v >>> 8) & 0xff, v & 0xff, (v = parseInt(uuid.slice(9, 13), 16)) >>> 8, v & 0xff, (v = parseInt(uuid.slice(14, 18), 16)) >>> 8, v & 0xff, (v = parseInt(uuid.slice(19, 23), 16)) >>> 8, v & 0xff, ((v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000) & 0xff, (v / 0x100000000) & 0xff, (v >>> 24) & 0xff, (v >>> 16) & 0xff, (v >>> 8) & 0xff, v & 0xff);
}
readMessageIndexes(payload) {
const bw = new buffer_wrapper_1.BufferWrapper(payload);
const count = bw.readVarInt();
if (count == 0) {
return [1, [0]];
}
const msgIndexes = [];
for (let i = 0; i < count; i++) {
msgIndexes.push(bw.readVarInt());
}
return [bw.pos, msgIndexes];
}
writeMessageIndexes(msgIndexes) {
if (msgIndexes.length === 1 && msgIndexes[0] === 0) {
const buffer = Buffer.alloc(1);
buffer.writeUInt8(0, 0);
return buffer;
}
const buffer = Buffer.alloc((1 + msgIndexes.length) * buffer_wrapper_1.MAX_VARINT_LEN_64);
const bw = new buffer_wrapper_1.BufferWrapper(buffer);
bw.writeVarInt(msgIndexes.length);
for (let i = 0; i < msgIndexes.length; i++) {
bw.writeVarInt(msgIndexes[i]);
}
return buffer.subarray(0, bw.pos);
}
}
exports.SchemaId = SchemaId;
/**
* SerializationError represents a serialization error
*/
class SerializationError extends Error {
constructor(message) {
super(message);
}
}
exports.SerializationError = SerializationError;
/**
* Serde represents a serializer/deserializer
*/
class Serde {
constructor(client, serdeType, conf, ruleRegistry) {
this.fieldTransformer = null;
this.client = client;
this.serdeType = serdeType;
this.conf = conf;
this.ruleRegistry = ruleRegistry ?? rule_registry_1.RuleRegistry.getGlobalInstance();
}
close() {
return;
}
subjectName(topic, info) {
const strategy = this.conf.subjectNameStrategy ?? exports.TopicNameStrategy;
return strategy(topic, this.serdeType, info);
}
async resolveReferences(client, schema, deps, format) {
let references = schema.references;
if (references == null) {
return;
}
for (let ref of references) {
let metadata = await client.getSchemaMetadata(ref.subject, ref.version, true, format);
deps.set(ref.name, metadata.schema);
await this.resolveReferences(client, metadata, deps);
}
}
async executeRules(subject, topic, ruleMode, source, target, msg, inlineTags) {
return await this.executeRulesWithPhase(subject, topic, schemaregistry_client_1.RulePhase.DOMAIN, ruleMode, source, target, msg, inlineTags);
}
async executeRulesWithPhase(subject, topic, rulePhase, ruleMode, source, target, msg, inlineTags) {
if (msg == null || target == null) {
return msg;
}
let rules;
switch (ruleMode) {
case schemaregistry_client_1.RuleMode.UPGRADE:
rules = target.ruleSet?.migrationRules;
break;
case schemaregistry_client_1.RuleMode.DOWNGRADE:
rules = source?.ruleSet?.migrationRules?.map(x => x).reverse();
break;
default:
if (rulePhase === schemaregistry_client_1.RulePhase.ENCODING) {
rules = target.ruleSet?.encodingRules;
}
else {
rules = target.ruleSet?.domainRules;
}
if (ruleMode === schemaregistry_client_1.RuleMode.READ) {
// Execute read rules in reverse order for symmetry
rules = rules?.map(x => x).reverse();
}
break;
}
if (rules == null) {
return msg;
}
for (let i = 0; i < rules.length; i++) {
let rule = rules[i];
if (this.isDisabled(rule)) {
continue;
}
let mode = rule.mode;
switch (mode) {
case schemaregistry_client_1.RuleMode.WRITEREAD:
if (ruleMode !== schemaregistry_client_1.RuleMode.WRITE && ruleMode !== schemaregistry_client_1.RuleMode.READ) {
continue;
}
break;
case schemaregistry_client_1.RuleMode.UPDOWN:
if (ruleMode !== schemaregistry_client_1.RuleMode.UPGRADE && ruleMode !== schemaregistry_client_1.RuleMode.DOWNGRADE) {
continue;
}
break;
default:
if (mode !== ruleMode) {
continue;
}
break;
}
let ctx = new RuleContext(source, target, subject, topic, this.serdeType === SerdeType.KEY, ruleMode, rule, i, rules, inlineTags, this.fieldTransformer);
let ruleExecutor = this.ruleRegistry.getExecutor(rule.type);
if (ruleExecutor == null) {
await this.runAction(ctx, ruleMode, rule, this.getOnFailure(rule), msg, new Error(`could not find rule executor of type ${rule.type}`), 'ERROR');
return msg;
}
try {
let result = await ruleExecutor.transform(ctx, msg);
switch (rule.kind) {
case 'CONDITION':
if (result === false) {
throw new RuleConditionError(rule);
}
break;
case 'TRANSFORM':
msg = result;
break;
}
await this.runAction(ctx, ruleMode, rule, msg != null
? this.getOnSuccess(rule) : this.getOnFailure(rule), msg, null, msg != null ? 'NONE' : 'ERROR');
}
catch (error) {
if (error instanceof SerializationError) {
throw error;
}
await this.runAction(ctx, ruleMode, rule, this.getOnFailure(rule), msg, error, 'ERROR');
}
}
return msg;
}
getOnSuccess(rule) {
let override = this.ruleRegistry.getOverride(rule.type);
if (override != null && override.onSuccess != null) {
return override.onSuccess;
}
return rule.onSuccess;
}
getOnFailure(rule) {
let override = this.ruleRegistry.getOverride(rule.type);
if (override != null && override.onFailure != null) {
return override.onFailure;
}
return rule.onFailure;
}
isDisabled(rule) {
let override = this.ruleRegistry.getOverride(rule.type);
if (override != null && override.disabled != null) {
return override.disabled;
}
return rule.disabled;
}
async runAction(ctx, ruleMode, rule, action, msg, err, defaultAction) {
let actionName = this.getRuleActionName(rule, ruleMode, action);
if (actionName == null) {
actionName = defaultAction;
}
let ruleAction = this.getRuleAction(ctx, actionName);
if (ruleAction == null) {
throw new RuleError(`Could not find rule action of type ${actionName}`);
}
try {
await ruleAction.run(ctx, msg, err);
}
catch (error) {
if (error instanceof SerializationError) {
throw error;
}
console.warn("could not run post-rule action %s: %s", actionName, error);
}
}
getRuleActionName(rule, ruleMode, actionName) {
if (actionName == null || actionName === '') {
return null;
}
if ((rule.mode === schemaregistry_client_1.RuleMode.WRITEREAD || rule.mode === schemaregistry_client_1.RuleMode.UPDOWN) && actionName.includes(',')) {
let parts = actionName.split(',');
switch (ruleMode) {
case schemaregistry_client_1.RuleMode.WRITE:
case schemaregistry_client_1.RuleMode.UPGRADE:
return parts[0];
case schemaregistry_client_1.RuleMode.READ:
case schemaregistry_client_1.RuleMode.DOWNGRADE:
return parts[1];
}
}
return actionName;
}
getRuleAction(ctx, actionName) {
if (actionName === 'ERROR') {
return new ErrorAction();
}
else if (actionName === 'NONE') {
return new NoneAction();
}
return this.ruleRegistry.getAction(actionName);
}
}
exports.Serde = Serde;
/**
* Serializer represents a serializer
*/
class Serializer extends Serde {
constructor(client, serdeType, conf, ruleRegistry) {
super(client, serdeType, conf, ruleRegistry);
}
config() {
return this.conf;
}
// GetSchemaID returns a schema ID for the given schema
async getSchemaId(schemaType, topic, msg, info, format) {
let autoRegister = this.config().autoRegisterSchemas;
let useSchemaId = this.config().useSchemaId;
let useLatestWithMetadata = this.config().useLatestWithMetadata;
let useLatest = this.config().useLatestVersion;
let normalizeSchema = this.config().normalizeSchemas;
let metadata;
let subject = this.subjectName(topic, info);
if (autoRegister) {
metadata = await this.client.registerFullResponse(subject, info, Boolean(normalizeSchema));
}
else if (useSchemaId != null && useSchemaId >= 0) {
info = await this.client.getBySubjectAndId(subject, useSchemaId, format);
metadata = await this.client.getIdFullResponse(subject, info, Boolean(normalizeSchema));
}
else if (useLatestWithMetadata != null && Object.keys(useLatestWithMetadata).length !== 0) {
metadata = await this.client.getLatestWithMetadata(subject, useLatestWithMetadata, true, format);
info = metadata;
}
else if (useLatest) {
metadata = await this.client.getLatestSchemaMetadata(subject, format);
info = metadata;
}
else {
metadata = await this.client.getIdFullResponse(subject, info, Boolean(normalizeSchema));
}
let schemaId = new SchemaId(schemaType, metadata.id, metadata.guid);
return [schemaId, info];
}
serializeSchemaId(topic, payload, schemaId, headers) {
const serializer = this.config().schemaIdSerializer ?? exports.PrefixSchemaIdSerializer;
return serializer(topic, this.serdeType, payload, schemaId, headers);
}
}
exports.Serializer = Serializer;
/**
* Deserializer represents a deserializer
*/
class Deserializer extends Serde {
constructor(client, serdeType, conf, ruleRegistry) {
super(client, serdeType, conf, ruleRegistry);
}
config() {
return this.conf;
}
deserializeSchemaId(topic, payload, schemaId, headers) {
const deserializer = this.config().schemaIdDeserializer ?? exports.DualSchemaIdDeserializer;
return deserializer(topic, this.serdeType, payload, schemaId, headers);
}
async getWriterSchema(topic, payload, schemaId, headers, format) {
const bytesRead = this.deserializeSchemaId(topic, payload, schemaId, headers);
let info;
if (schemaId.id != null) {
let subject = this.subjectName(topic);
info = await this.client.getBySubjectAndId(subject, schemaId.id, format);
}
else if (schemaId.guid != null) {
info = await this.client.getByGuid(schemaId.guid, format);
}
else {
throw new SerializationError("Invalid schema ID");
}
return [info, bytesRead];
}
async getReaderSchema(subject, format) {
let useLatestWithMetadata = this.config().useLatestWithMetadata;
let useLatest = this.config().useLatestVersion;
if (useLatestWithMetadata != null && Object.keys(useLatestWithMetadata).length !== 0) {
return await this.client.getLatestWithMetadata(subject, useLatestWithMetadata, true, format);
}
if (useLatest) {
return await this.client.getLatestSchemaMetadata(subject, format);
}
return null;
}
hasRules(ruleSet, phase, mode) {
if (ruleSet == null) {
return false;
}
let rules;
switch (phase) {
case schemaregistry_client_1.RulePhase.MIGRATION:
rules = ruleSet.migrationRules;
break;
case schemaregistry_client_1.RulePhase.DOMAIN:
rules = ruleSet.domainRules;
break;
case schemaregistry_client_1.RulePhase.ENCODING:
rules = ruleSet.encodingRules;
}
switch (mode) {
case schemaregistry_client_1.RuleMode.UPGRADE:
case schemaregistry_client_1.RuleMode.DOWNGRADE:
return this.checkRules(rules, (ruleMode) => ruleMode === mode || ruleMode === schemaregistry_client_1.RuleMode.UPDOWN);
case schemaregistry_client_1.RuleMode.UPDOWN:
return this.checkRules(rules, (ruleMode) => ruleMode === mode);
case schemaregistry_client_1.RuleMode.WRITE:
case schemaregistry_client_1.RuleMode.READ:
return this.checkRules(rules, (ruleMode) => ruleMode === mode || ruleMode === schemaregistry_client_1.RuleMode.WRITEREAD);
case schemaregistry_client_1.RuleMode.WRITEREAD:
return this.checkRules(rules, (ruleMode) => ruleMode === mode);
}
}
checkRules(rules, filter) {
if (rules == null) {
return false;
}
for (let rule of rules) {
let ruleMode = rule.mode;
if (ruleMode && filter(ruleMode)) {
return true;
}
}
return false;
}
async getMigrations(subject, sourceInfo, target, format) {
let version = await this.client.getVersion(subject, sourceInfo, false, true);
let source = {
id: 0,
guid: "",
version: version,
schema: sourceInfo.schema,
references: sourceInfo.references,
metadata: sourceInfo.metadata,
ruleSet: sourceInfo.ruleSet,
};
let migrationMode;
let migrations = [];
let first;
let last;
if (source.version < target.version) {
migrationMode = schemaregistry_client_1.RuleMode.UPGRADE;
first = source;
last = target;
}
else if (source.version > target.version) {
migrationMode = schemaregistry_client_1.RuleMode.DOWNGRADE;
first = target;
last = source;
}
else {
return migrations;
}
let previous = null;
let versions = await this.getSchemasBetween(subject, first, last, format);
for (let i = 0; i < versions.length; i++) {
let version = versions[i];
if (i === 0) {
previous = version;
continue;
}
if (version.ruleSet != null && this.hasRules(version.ruleSet, schemaregistry_client_1.RulePhase.MIGRATION, migrationMode)) {
let m;
if (migrationMode === schemaregistry_client_1.RuleMode.UPGRADE) {
m = {
ruleMode: migrationMode,
source: previous,
target: version,
};
}
else {
m = {
ruleMode: migrationMode,
source: version,
target: previous,
};
}
migrations.push(m);
}
previous = version;
}
if (migrationMode === schemaregistry_client_1.RuleMode.DOWNGRADE) {
migrations = migrations.reverse();
}
return migrations;
}
async getSchemasBetween(subject, first, last, format) {
if (last.version - first.version <= 1) {
return [first, last];
}
let version1 = first.version;
let version2 = last.version;
let result = [first];
for (let i = version1 + 1; i < version2; i++) {
let meta = await this.client.getSchemaMetadata(subject, i, true, format);
result.push(meta);
}
result.push(last);
return result;
}
async executeMigrations(migrations, subject, topic, msg) {
for (let migration of migrations) {
// TODO fix source, target?
msg = await this.executeRulesWithPhase(subject, topic, schemaregistry_client_1.RulePhase.MIGRATION, migration.ruleMode, migration.source, migration.target, msg, null);
}
return msg;
}
}
exports.Deserializer = Deserializer;
/**
* TopicNameStrategy creates a subject name by appending -[key|value] to the topic name.
* @param topic - the topic name
* @param serdeType - the serde type
*/
const TopicNameStrategy = (topic, serdeType) => {
let suffix = '-value';
if (serdeType === SerdeType.KEY) {
suffix = '-key';
}
return topic + suffix;
};
exports.TopicNameStrategy = TopicNameStrategy;
const HeaderSchemaIdSerializer = (topic, serdeType, payload, schemaId, headers) => {
if (headers == null) {
throw new SerializationError('Missing Headers');
}
let headerKey = serdeType === SerdeType.KEY ? exports.KEY_SCHEMA_ID_HEADER : exports.VALUE_SCHEMA_ID_HEADER;
headers[headerKey] = schemaId.guidToBytes();
return payload;
};
exports.HeaderSchemaIdSerializer = HeaderSchemaIdSerializer;
const PrefixSchemaIdSerializer = (topic, serdeType, payload, schemaId, headers) => {
return Buffer.concat([schemaId.idToBytes(), payload]);
};
exports.PrefixSchemaIdSerializer = PrefixSchemaIdSerializer;
const DualSchemaIdDeserializer = (topic, serdeType, payload, schemaId, headers) => {
let headerKey = serdeType === SerdeType.KEY ? exports.KEY_SCHEMA_ID_HEADER : exports.VALUE_SCHEMA_ID_HEADER;
// get header with headerKey from headers
if (headers != null) {
let headerValues = headers[headerKey];
let buf;
if (headerValues != null) {
if (Array.isArray(headerValues)) {
let headerValue = headerValues.length > 0 ? headerValues[headerValues.length - 1] : null;
if (typeof headerValue === 'string') {
buf = Buffer.from(headerValue, 'utf8');
}
else {
buf = headerValue;
}
}
else if (typeof headerValues === 'string') {
buf = Buffer.from(headerValues, 'utf8');
}
else {
buf = headerValues;
}
if (buf != null) {
schemaId.fromBytes(buf);
return 0;
}
}
}
return schemaId.fromBytes(payload);
};
exports.DualSchemaIdDeserializer = DualSchemaIdDeserializer;
const PrefixSchemaIdDeserializer = (topic, serdeType, payload, schemaId, headers) => {
return schemaId.fromBytes(payload);
};
exports.PrefixSchemaIdDeserializer = PrefixSchemaIdDeserializer;
/**
* RuleContext represents a rule context
*/
class RuleContext {
constructor(source, target, subject, topic, isKey, ruleMode, rule, index, rules, inlineTags, fieldTransformer) {
this.source = source;
this.target = target;
this.subject = subject;
this.topic = topic;
this.isKey = isKey;
this.ruleMode = ruleMode;
this.rule = rule;
this.index = index;
this.rules = rules;
this.inlineTags = inlineTags;
this.fieldTransformer = fieldTransformer;
this.fieldContexts = [];
}
getParameter(name) {
const params = this.rule.params;
if (params != null) {
let value = params[name];
if (value != null) {
return value;
}
}
let metadata = this.target.metadata;
if (metadata != null && metadata.properties != null) {
let value = metadata.properties[name];
if (value != null) {
return value;
}
}
return null;
}
getInlineTags(name) {
let tags = this.inlineTags?.get(name);
if (tags != null) {
return tags;
}
return new Set();
}
currentField() {
let size = this.fieldContexts.length;
if (size === 0) {
return null;
}
return this.fieldContexts[size - 1];
}
enterField(containingMessage, fullName, name, fieldType, tags) {
let allTags = new Set(tags ?? this.getInlineTags(fullName));
for (let v of this.getTags(fullName)) {
allTags.add(v);
}
let fieldContext = new FieldContext(containingMessage, fullName, name, fieldType, allTags);
this.fieldContexts.push(fieldContext);
return fieldContext;
}
getTags(fullName) {
let tags = new Set();
let metadata = this.target.metadata;
if (metadata?.tags != null) {
for (let [k, v] of Object.entries(metadata.tags)) {
if ((0, wildcard_matcher_1.match)(fullName, k)) {
for (let tag of v) {
tags.add(tag);
}
}
}
}
return tags;
}
leaveField() {
let size = this.fieldContexts.length - 1;
this.fieldContexts = this.fieldContexts.slice(0, size);
}
}
exports.RuleContext = RuleContext;
/**
* FieldRuleExecutor represents a field rule executor
*/
class FieldRuleExecutor {
constructor() {
this.config = null;
}
async transform(ctx, msg) {
// TODO preserve source
switch (ctx.ruleMode) {
case schemaregistry_client_1.RuleMode.WRITE:
case schemaregistry_client_1.RuleMode.UPGRADE:
for (let i = 0; i < ctx.index; i++) {
let otherRule = ctx.rules[i];
if (areTransformsWithSameTag(ctx.rule, otherRule)) {
// ignore this transform if an earlier one has the same tag
return msg;
}
}
break;
case schemaregistry_client_1.RuleMode.READ:
case schemaregistry_client_1.RuleMode.DOWNGRADE:
for (let i = ctx.index + 1; i < ctx.rules.length; i++) {
let otherRule = ctx.rules[i];
if (areTransformsWithSameTag(ctx.rule, otherRule)) {
// ignore this transform if a later one has the same tag
return msg;
}
}
break;
}
let fieldTransform = this.newTransform(ctx);
return ctx.fieldTransformer(ctx, fieldTransform, msg);
}
}
exports.FieldRuleExecutor = FieldRuleExecutor;
function areTransformsWithSameTag(rule1, rule2) {
return rule1.tags != null && rule1.tags.length > 0
&& rule1.kind === 'TRANSFORM'
&& rule1.kind === rule2.kind
&& rule1.mode === rule2.mode
&& rule1.type === rule2.type
&& rule1.tags === rule2.tags;
}
/**
* FieldContext represents a field context
*/
class FieldContext {
constructor(containingMessage, fullName, name, fieldType, tags) {
this.containingMessage = containingMessage;
this.fullName = fullName;
this.name = name;
this.type = fieldType;
this.tags = new Set(tags);
}
isPrimitive() {
let t = this.type;
return t === FieldType.STRING || t === FieldType.BYTES || t === FieldType.INT
|| t === FieldType.LONG || t === FieldType.FLOAT || t === FieldType.DOUBLE
|| t === FieldType.BOOLEAN || t === FieldType.NULL;
}
typeName() {
return this.type.toString();
}
}
exports.FieldContext = FieldContext;
var FieldType;
(function (FieldType) {
FieldType["RECORD"] = "RECORD";
FieldType["ENUM"] = "ENUM";
FieldType["ARRAY"] = "ARRAY";
FieldType["MAP"] = "MAP";
FieldType["COMBINED"] = "COMBINED";
FieldType["FIXED"] = "FIXED";
FieldType["STRING"] = "STRING";
FieldType["BYTES"] = "BYTES";
FieldType["INT"] = "INT";
FieldType["LONG"] = "LONG";
FieldType["FLOAT"] = "FLOAT";
FieldType["DOUBLE"] = "DOUBLE";
FieldType["BOOLEAN"] = "BOOLEAN";
FieldType["NULL"] = "NULL";
})(FieldType || (exports.FieldType = FieldType = {}));
/**
* ErrorAction represents an error action
*/
class ErrorAction {
configure(clientConfig, config) {
}
type() {
return 'ERROR';
}
async run(ctx, msg, err) {
throw new SerializationError(err.message);
}
close() {
}
}
exports.ErrorAction = ErrorAction;
/**
* NoneAction represents a no-op action
*/
class NoneAction {
configure(clientConfig, config) {
}
type() {
return 'NONE';
}
async run(ctx, msg, err) {
return;
}
close() {
}
}
exports.NoneAction = NoneAction;
/**
* RuleError represents a rule error
*/
class RuleError extends Error {
/**
* Creates a new rule error.
* @param message - The error message.
*/
constructor(message) {
super(message);
}
}
exports.RuleError = RuleError;
/**
* RuleConditionError represents a rule condition error
*/
class RuleConditionError extends RuleError {
/**
* Creates a new rule condition error.
* @param rule - The rule.
*/
constructor(rule) {
super(RuleConditionError.error(rule));
this.rule = rule;
}
static error(rule) {
let errMsg = rule.doc;
if (!errMsg) {
if (rule.expr !== '') {
return `Expr failed: '${rule.expr}'`;
}
return `Condition failed: '${rule.name}'`;
}
return errMsg;
}
}
exports.RuleConditionError = RuleConditionError;