123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.AvroSchemaDecoder = void 0;
- const Reader_1 = require("@jsonjoy.com/buffers/lib/Reader");
- const AvroDecoder_1 = require("./AvroDecoder");
- const AvroSchemaValidator_1 = require("./AvroSchemaValidator");
- class AvroSchemaDecoder {
- constructor(reader = new Reader_1.Reader()) {
- this.reader = reader;
- this.namedSchemas = new Map();
- this.decoder = new AvroDecoder_1.AvroDecoder();
- this.decoder.reader = reader;
- this.validator = new AvroSchemaValidator_1.AvroSchemaValidator();
- }
- decode(data, schema) {
- this.reader.reset(data);
- this.namedSchemas.clear();
- if (!this.validator.validateSchema(schema)) {
- throw new Error('Invalid Avro schema');
- }
- this.collectNamedSchemas(schema);
- return this.readValue(schema);
- }
- readValue(schema) {
- const resolvedSchema = this.resolveSchema(schema);
- if (typeof resolvedSchema === 'string') {
- switch (resolvedSchema) {
- case 'null':
- return this.decoder.readNull();
- case 'boolean':
- return this.decoder.readBoolean();
- case 'int':
- return this.decoder.readInt();
- case 'long':
- return this.decoder.readLong();
- case 'float':
- return this.decoder.readFloat();
- case 'double':
- return this.decoder.readDouble();
- case 'bytes':
- return this.decoder.readBytes();
- case 'string':
- return this.decoder.readString();
- default:
- throw new Error(`Unknown primitive type: ${resolvedSchema}`);
- }
- }
- if (Array.isArray(resolvedSchema)) {
- return this.readUnion(resolvedSchema);
- }
- switch (resolvedSchema.type) {
- case 'record':
- return this.readRecord(resolvedSchema);
- case 'enum':
- return this.readEnum(resolvedSchema);
- case 'array':
- return this.readArray(resolvedSchema);
- case 'map':
- return this.readMap(resolvedSchema);
- case 'fixed':
- return this.readFixed(resolvedSchema);
- default:
- throw new Error(`Unknown schema type: ${resolvedSchema.type}`);
- }
- }
- readRecord(schema) {
- const result = {};
- for (let i = 0; i < schema.fields.length; i++) {
- const field = schema.fields[i];
- try {
- result[field.name] = this.readValue(field.type);
- }
- catch (error) {
- throw new Error(`Error reading field '${field.name}': ${error.message}`);
- }
- }
- return result;
- }
- readEnum(schema) {
- const index = this.decoder.readEnum();
- if (index < 0 || index >= schema.symbols.length) {
- throw new Error(`Invalid enum index ${index} for enum with ${schema.symbols.length} symbols`);
- }
- return schema.symbols[index];
- }
- readArray(schema) {
- return this.decoder.readArray(() => this.readValue(schema.items));
- }
- readMap(schema) {
- return this.decoder.readMap(() => this.readValue(schema.values));
- }
- readUnion(schema) {
- const schemaReaders = schema.map((subSchema) => () => this.readValue(subSchema));
- const result = this.decoder.readUnion(schemaReaders);
- return result.value;
- }
- readFixed(schema) {
- return this.decoder.readFixed(schema.size);
- }
- readNull(schema) {
- this.validateSchemaType(schema, 'null');
- return this.decoder.readNull();
- }
- readBoolean(schema) {
- this.validateSchemaType(schema, 'boolean');
- return this.decoder.readBoolean();
- }
- readInt(schema) {
- this.validateSchemaType(schema, 'int');
- const value = this.decoder.readInt();
- if (!Number.isInteger(value) || value < -2147483648 || value > 2147483647) {
- throw new Error('Decoded value is not a valid 32-bit integer');
- }
- return value;
- }
- readLong(schema) {
- this.validateSchemaType(schema, 'long');
- return this.decoder.readLong();
- }
- readFloat(schema) {
- this.validateSchemaType(schema, 'float');
- return this.decoder.readFloat();
- }
- readDouble(schema) {
- this.validateSchemaType(schema, 'double');
- return this.decoder.readDouble();
- }
- readBytes(schema) {
- this.validateSchemaType(schema, 'bytes');
- return this.decoder.readBytes();
- }
- readString(schema) {
- this.validateSchemaType(schema, 'string');
- return this.decoder.readString();
- }
- validateSchemaType(schema, expectedType) {
- const resolvedSchema = this.resolveSchema(schema);
- const actualType = typeof resolvedSchema === 'string'
- ? resolvedSchema
- : Array.isArray(resolvedSchema)
- ? 'union'
- : resolvedSchema.type;
- if (actualType !== expectedType) {
- throw new Error(`Expected schema type ${expectedType}, got ${actualType}`);
- }
- }
- resolveSchema(schema) {
- if (typeof schema === 'string') {
- const namedSchema = this.namedSchemas.get(schema);
- return namedSchema || schema;
- }
- return schema;
- }
- collectNamedSchemas(schema) {
- if (typeof schema === 'string' || Array.isArray(schema)) {
- return;
- }
- if (typeof schema === 'object' && schema !== null) {
- switch (schema.type) {
- case 'record':
- const recordSchema = schema;
- const recordFullName = this.getFullName(recordSchema.name, recordSchema.namespace);
- this.namedSchemas.set(recordFullName, recordSchema);
- recordSchema.fields.forEach((field) => this.collectNamedSchemas(field.type));
- break;
- case 'enum':
- const enumSchema = schema;
- const enumFullName = this.getFullName(enumSchema.name, enumSchema.namespace);
- this.namedSchemas.set(enumFullName, enumSchema);
- break;
- case 'fixed':
- const fixedSchema = schema;
- const fixedFullName = this.getFullName(fixedSchema.name, fixedSchema.namespace);
- this.namedSchemas.set(fixedFullName, fixedSchema);
- break;
- case 'array':
- this.collectNamedSchemas(schema.items);
- break;
- case 'map':
- this.collectNamedSchemas(schema.values);
- break;
- }
- }
- }
- getFullName(name, namespace) {
- return namespace ? `${namespace}.${name}` : name;
- }
- }
- exports.AvroSchemaDecoder = AvroSchemaDecoder;
- //# sourceMappingURL=AvroSchemaDecoder.js.map
|