| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| /* eslint-disable brace-style */ |
| |
| import { Schema, Field } from '../../schema'; |
| import { |
| DataType, Dictionary, TimeBitWidth, |
| Utf8, Binary, Decimal, FixedSizeBinary, |
| List, FixedSizeList, Map_, Struct, Union, |
| Bool, Null, Int, Float, Date_, Time, Interval, Timestamp, IntBitWidth, Int32, TKeys, |
| } from '../../type'; |
| |
| import { DictionaryBatch, RecordBatch, FieldNode, BufferRegion } from './message'; |
| import { TimeUnit, Precision, IntervalUnit, UnionMode, DateUnit } from '../../enum'; |
| |
| /** @ignore */ |
| export function schemaFromJSON(_schema: any, dictionaries: Map<number, DataType> = new Map()) { |
| return new Schema( |
| schemaFieldsFromJSON(_schema, dictionaries), |
| customMetadataFromJSON(_schema['customMetadata']), |
| dictionaries |
| ); |
| } |
| |
| /** @ignore */ |
| export function recordBatchFromJSON(b: any) { |
| return new RecordBatch( |
| b['count'], |
| fieldNodesFromJSON(b['columns']), |
| buffersFromJSON(b['columns']) |
| ); |
| } |
| |
| /** @ignore */ |
| export function dictionaryBatchFromJSON(b: any) { |
| return new DictionaryBatch( |
| recordBatchFromJSON(b['data']), |
| b['id'], b['isDelta'] |
| ); |
| } |
| |
| /** @ignore */ |
| function schemaFieldsFromJSON(_schema: any, dictionaries?: Map<number, DataType>) { |
| return (_schema['fields'] || []).filter(Boolean).map((f: any) => Field.fromJSON(f, dictionaries)); |
| } |
| |
| /** @ignore */ |
| function fieldChildrenFromJSON(_field: any, dictionaries?: Map<number, DataType>): Field[] { |
| return (_field['children'] || []).filter(Boolean).map((f: any) => Field.fromJSON(f, dictionaries)); |
| } |
| |
| /** @ignore */ |
| function fieldNodesFromJSON(xs: any[]): FieldNode[] { |
| return (xs || []).reduce<FieldNode[]>((fieldNodes, column: any) => [ |
| ...fieldNodes, |
| new FieldNode( |
| column['count'], |
| nullCountFromJSON(column['VALIDITY']) |
| ), |
| ...fieldNodesFromJSON(column['children']) |
| ], [] as FieldNode[]); |
| } |
| |
| /** @ignore */ |
| function buffersFromJSON(xs: any[], buffers: BufferRegion[] = []): BufferRegion[] { |
| for (let i = -1, n = (xs || []).length; ++i < n;) { |
| const column = xs[i]; |
| column['VALIDITY'] && buffers.push(new BufferRegion(buffers.length, column['VALIDITY'].length)); |
| column['TYPE'] && buffers.push(new BufferRegion(buffers.length, column['TYPE'].length)); |
| column['OFFSET'] && buffers.push(new BufferRegion(buffers.length, column['OFFSET'].length)); |
| column['DATA'] && buffers.push(new BufferRegion(buffers.length, column['DATA'].length)); |
| buffers = buffersFromJSON(column['children'], buffers); |
| } |
| return buffers; |
| } |
| |
| /** @ignore */ |
| function nullCountFromJSON(validity: number[]) { |
| return (validity || []).reduce((sum, val) => sum + +(val === 0), 0); |
| } |
| |
| /** @ignore */ |
| export function fieldFromJSON(_field: any, dictionaries?: Map<number, DataType>) { |
| |
| let id: number; |
| let keys: TKeys | null; |
| let field: Field | void; |
| let dictMeta: any; |
| let type: DataType<any>; |
| let dictType: Dictionary; |
| |
| // If no dictionary encoding |
| if (!dictionaries || !(dictMeta = _field['dictionary'])) { |
| type = typeFromJSON(_field, fieldChildrenFromJSON(_field, dictionaries)); |
| field = new Field(_field['name'], type, _field['nullable'], customMetadataFromJSON(_field['customMetadata'])); |
| } |
| // If dictionary encoded and the first time we've seen this dictionary id, decode |
| // the data type and child fields, then wrap in a Dictionary type and insert the |
| // data type into the dictionary types map. |
| else if (!dictionaries.has(id = dictMeta['id'])) { |
| // a dictionary index defaults to signed 32 bit int if unspecified |
| keys = (keys = dictMeta['indexType']) ? indexTypeFromJSON(keys) as TKeys : new Int32(); |
| dictionaries.set(id, type = typeFromJSON(_field, fieldChildrenFromJSON(_field, dictionaries))); |
| dictType = new Dictionary(type, keys, id, dictMeta['isOrdered']); |
| field = new Field(_field['name'], dictType, _field['nullable'], customMetadataFromJSON(_field['customMetadata'])); |
| } |
| // If dictionary encoded, and have already seen this dictionary Id in the schema, then reuse the |
| // data type and wrap in a new Dictionary type and field. |
| else { |
| // a dictionary index defaults to signed 32 bit int if unspecified |
| keys = (keys = dictMeta['indexType']) ? indexTypeFromJSON(keys) as TKeys : new Int32(); |
| dictType = new Dictionary(dictionaries.get(id)!, keys, id, dictMeta['isOrdered']); |
| field = new Field(_field['name'], dictType, _field['nullable'], customMetadataFromJSON(_field['customMetadata'])); |
| } |
| return field || null; |
| } |
| |
| /** @ignore */ |
| function customMetadataFromJSON(_metadata?: Record<string, string>) { |
| return new Map<string, string>(Object.entries(_metadata || {})); |
| } |
| |
| /** @ignore */ |
| function indexTypeFromJSON(_type: any) { |
| return new Int(_type['isSigned'], _type['bitWidth']); |
| } |
| |
| /** @ignore */ |
| function typeFromJSON(f: any, children?: Field[]): DataType<any> { |
| |
| const typeId = f['type']['name']; |
| |
| switch (typeId) { |
| case 'NONE': return new Null(); |
| case 'null': return new Null(); |
| case 'binary': return new Binary(); |
| case 'utf8': return new Utf8(); |
| case 'bool': return new Bool(); |
| case 'list': return new List((children || [])[0]); |
| case 'struct': return new Struct(children || []); |
| case 'struct_': return new Struct(children || []); |
| } |
| |
| switch (typeId) { |
| case 'int': { |
| const t = f['type']; |
| return new Int(t['isSigned'], t['bitWidth'] as IntBitWidth); |
| } |
| case 'floatingpoint': { |
| const t = f['type']; |
| return new Float(Precision[t['precision']] as any); |
| } |
| case 'decimal': { |
| const t = f['type']; |
| return new Decimal(t['scale'], t['precision']); |
| } |
| case 'date': { |
| const t = f['type']; |
| return new Date_(DateUnit[t['unit']] as any); |
| } |
| case 'time': { |
| const t = f['type']; |
| return new Time(TimeUnit[t['unit']] as any, t['bitWidth'] as TimeBitWidth); |
| } |
| case 'timestamp': { |
| const t = f['type']; |
| return new Timestamp(TimeUnit[t['unit']] as any, t['timezone']); |
| } |
| case 'interval': { |
| const t = f['type']; |
| return new Interval(IntervalUnit[t['unit']] as any); |
| } |
| case 'union': { |
| const t = f['type']; |
| return new Union(UnionMode[t['mode']] as any, (t['typeIds'] || []), children || []); |
| } |
| case 'fixedsizebinary': { |
| const t = f['type']; |
| return new FixedSizeBinary(t['byteWidth']); |
| } |
| case 'fixedsizelist': { |
| const t = f['type']; |
| return new FixedSizeList(t['listSize'], (children || [])[0]); |
| } |
| case 'map': { |
| const t = f['type']; |
| return new Map_((children || [])[0], t['keysSorted']); |
| } |
| } |
| throw new Error(`Unrecognized type: "${typeId}"`); |
| } |