UNPKG

cassandra-driver

Version:

DataStax Node.js Driver for Apache Cassandra

502 lines (444 loc) 12.2 kB
/* * 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. */ /** * @module datastax/graph/tinkerpop/typeSerializers * @ignore */ /** * @author Jorge Bay Gondra */ 'use strict'; // Replace dependencies to minimize code changes from Apache TinkerPop const t = { P: UnsupportedType, TextP: UnsupportedType, Traversal: UnsupportedType, Traverser: UnsupportedType, EnumValue: UnsupportedType }; const ts = { TraversalStrategy: UnsupportedType }; const Bytecode = UnsupportedType; const g = require('./index'); const utils = { Long: UnsupportedType }; t.t = g.t; t.direction = g.direction; function UnsupportedType() { } const valueKey = '@value'; const typeKey = '@type'; /** * @abstract */ class TypeSerializer { serialize() { throw new Error('serialize() method not implemented for ' + this.constructor.name); } deserialize() { throw new Error('deserialize() method not implemented for ' + this.constructor.name); } canBeUsedFor() { throw new Error('canBeUsedFor() method not implemented for ' + this.constructor.name); } } class NumberSerializer extends TypeSerializer { serialize(item) { if (isNaN(item)) { return { [typeKey]: 'g:Double', [valueKey]: 'NaN' }; } else if (item === Number.POSITIVE_INFINITY) { return { [typeKey]: 'g:Double', [valueKey]: 'Infinity' }; } else if (item === Number.NEGATIVE_INFINITY) { return { [typeKey]: 'g:Double', [valueKey]: '-Infinity' }; } else { return item; } } deserialize(obj) { var val = obj[valueKey]; if (val === 'NaN') { return NaN; } else if (val === 'Infinity') { return Number.POSITIVE_INFINITY; } else if (val === '-Infinity') { return Number.NEGATIVE_INFINITY; } else { return parseFloat(val); } } canBeUsedFor(value) { return (typeof value === 'number'); } } class DateSerializer extends TypeSerializer { serialize(item) { return { [typeKey]: 'g:Date', [valueKey]: item.getTime() }; } deserialize(obj) { return new Date(obj[valueKey]); } canBeUsedFor(value) { return (value instanceof Date); } } class LongSerializer extends TypeSerializer { serialize(item) { return { [typeKey]: 'g:Int64', [valueKey]: item.value }; } canBeUsedFor(value) { return (value instanceof utils.Long); } } class BytecodeSerializer extends TypeSerializer { serialize(item) { let bytecode = item; if (item instanceof t.Traversal) { bytecode = item.getBytecode(); } const result = {}; result[typeKey] = 'g:Bytecode'; const resultValue = result[valueKey] = {}; const sources = this._serializeInstructions(bytecode.sourceInstructions); if (sources) { resultValue['source'] = sources; } const steps = this._serializeInstructions(bytecode.stepInstructions); if (steps) { resultValue['step'] = steps; } return result; } _serializeInstructions(instructions) { if (instructions.length === 0) { return null; } const result = new Array(instructions.length); result[0] = instructions[0]; for (let i = 0; i < instructions.length; i++) { result[i] = instructions[i].map(item => this.writer.adaptObject(item)); } return result; } canBeUsedFor(value) { return (value instanceof Bytecode) || (value instanceof t.Traversal); } } class PSerializer extends TypeSerializer { /** @param {P} item */ serialize(item) { const result = {}; result[typeKey] = 'g:P'; const resultValue = result[valueKey] = { 'predicate': item.operator }; if (item.other === undefined || item.other === null) { resultValue['value'] = this.writer.adaptObject(item.value); } else { resultValue['value'] = [ this.writer.adaptObject(item.value), this.writer.adaptObject(item.other) ]; } return result; } canBeUsedFor(value) { return (value instanceof t.P); } } class TextPSerializer extends TypeSerializer { /** @param {TextP} item */ serialize(item) { const result = {}; result[typeKey] = 'g:TextP'; const resultValue = result[valueKey] = { 'predicate': item.operator }; if (item.other === undefined || item.other === null) { resultValue['value'] = this.writer.adaptObject(item.value); } else { resultValue['value'] = [ this.writer.adaptObject(item.value), this.writer.adaptObject(item.other) ]; } return result; } canBeUsedFor(value) { return (value instanceof t.TextP); } } class LambdaSerializer extends TypeSerializer { /** @param {Function} item */ serialize(item) { return { [typeKey]: 'g:Lambda', [valueKey]: { 'arguments': item.length, 'language': 'gremlin-javascript', 'script': item.toString() } }; } canBeUsedFor(value) { return (typeof value === 'function'); } } class EnumSerializer extends TypeSerializer { /** @param {EnumValue} item */ serialize(item) { return { [typeKey]: 'g:' + item.typeName, [valueKey]: item.elementName }; } canBeUsedFor(value) { return value && value.typeName && value instanceof t.EnumValue; } } class TraverserSerializer extends TypeSerializer { /** @param {Traverser} item */ serialize(item) { return { [typeKey]: 'g:Traverser', [valueKey]: { 'value': this.writer.adaptObject(item.object), 'bulk': this.writer.adaptObject(item.bulk) } }; } deserialize(obj) { const value = obj[valueKey]; return new t.Traverser(this.reader.read(value['value']), this.reader.read(value['bulk'])); } canBeUsedFor(value) { return (value instanceof t.Traverser); } } class TraversalStrategySerializer extends TypeSerializer { /** @param {TraversalStrategy} item */ serialize(item) { return { [typeKey]: 'g:' + item.constructor.name, [valueKey]: item.configuration }; } canBeUsedFor(value) { return (value instanceof ts.TraversalStrategy); } } class VertexSerializer extends TypeSerializer { deserialize(obj) { const value = obj[valueKey]; return new g.Vertex(this.reader.read(value['id']), value['label'], this.reader.read(value['properties'])); } /** @param {Vertex} item */ serialize(item) { return { [typeKey]: 'g:Vertex', [valueKey]: { 'id': this.writer.adaptObject(item.id), 'label': item.label } }; } canBeUsedFor(value) { return (value instanceof g.Vertex); } } class VertexPropertySerializer extends TypeSerializer { deserialize(obj) { const value = obj[valueKey]; return new g.VertexProperty( this.reader.read(value['id']), value['label'], this.reader.read(value['value']), this.reader.read(value['properties']) ); } } class PropertySerializer extends TypeSerializer { deserialize(obj) { const value = obj[valueKey]; return new g.Property( value['key'], this.reader.read(value['value'])); } } class EdgeSerializer extends TypeSerializer { deserialize(obj) { const value = obj[valueKey]; return new g.Edge( this.reader.read(value['id']), new g.Vertex(this.reader.read(value['outV']), this.reader.read(value['outVLabel'])), value['label'], new g.Vertex(this.reader.read(value['inV']), this.reader.read(value['inVLabel'])), this.reader.read(value['properties']) ); } /** @param {Edge} item */ serialize(item) { return { [typeKey]: 'g:Edge', [valueKey]: { 'id': this.writer.adaptObject(item.id), 'label': item.label, 'outV': this.writer.adaptObject(item.outV.id), 'outVLabel': item.outV.label, 'inV': this.writer.adaptObject(item.inV.id), 'inVLabel': item.inV.label } }; } canBeUsedFor(value) { return (value instanceof g.Edge); } } class PathSerializer extends TypeSerializer { deserialize(obj) { const value = obj[valueKey]; const objects = value['objects'].map(o => this.reader.read(o)); return new g.Path(this.reader.read(value['labels']), objects); } } class Path3Serializer extends TypeSerializer { deserialize(obj) { const value = obj[valueKey]; return new g.Path(this.reader.read(value['labels']), this.reader.read(value['objects'])); } } class TSerializer extends TypeSerializer { deserialize(obj) { return t.t[obj[valueKey]]; } } class DirectionSerializer extends TypeSerializer { deserialize(obj) { return t.direction[obj[valueKey].toLowerCase()]; } } class ArraySerializer extends TypeSerializer { constructor(typeKey) { super(); this.typeKey = typeKey; } deserialize(obj) { const value = obj[valueKey]; if (!Array.isArray(value)) { throw new Error('Expected Array, obtained: ' + value); } return value.map(x => this.reader.read(x)); } /** @param {Array} item */ serialize(item) { return { [typeKey]: this.typeKey, [valueKey]: item.map(x => this.writer.adaptObject(x)) }; } canBeUsedFor(value) { return Array.isArray(value); } } class BulkSetSerializer extends TypeSerializer { deserialize(obj) { const value = obj[valueKey]; if (!Array.isArray(value)) { throw new Error('Expected Array, obtained: ' + value); } // coerce the BulkSet to List. if the bulk exceeds the int space then we can't coerce to List anyway, // so this query will be trouble. we'd need a legit BulkSet implementation here in js. this current // implementation is here to replicate the previous functionality that existed on the server side in // previous versions. let result = []; for (let ix = 0, iy = value.length; ix < iy; ix += 2) { const pair = value.slice(ix, ix + 2); result = result.concat(Array(this.reader.read(pair[1])).fill(this.reader.read(pair[0]))); } return result; } } class MapSerializer extends TypeSerializer { deserialize(obj) { const value = obj[valueKey]; if (!Array.isArray(value)) { throw new Error('Expected Array, obtained: ' + value); } const result = new Map(); for (let i = 0; i < value.length; i += 2) { result.set(this.reader.read(value[i]), this.reader.read(value[i + 1])); } return result; } /** @param {Map} map */ serialize(map) { const arr = []; map.forEach((v, k) => { arr.push(this.writer.adaptObject(k)); arr.push(this.writer.adaptObject(v)); }); return { [typeKey]: 'g:Map', [valueKey]: arr }; } canBeUsedFor(value) { return value instanceof Map; } } class ListSerializer extends ArraySerializer { constructor() { super('g:List'); } } class SetSerializer extends ArraySerializer { constructor() { super('g:Set'); } } module.exports = { BulkSetSerializer, BytecodeSerializer, DateSerializer, DirectionSerializer, EdgeSerializer, EnumSerializer, LambdaSerializer, ListSerializer, LongSerializer, MapSerializer, NumberSerializer, Path3Serializer, PathSerializer, PropertySerializer, PSerializer, TextPSerializer, SetSerializer, TSerializer, TraverserSerializer, TraversalStrategySerializer, typeKey, valueKey, VertexPropertySerializer, VertexSerializer };