UNPKG

oracle-nosqldb

Version:

Node.js driver for Oracle NoSQL Database

319 lines (274 loc) 9.83 kB
/*- * Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Universal Permissive License v 1.0 as shown at * https://oss.oracle.com/licenses/upl/ */ 'use strict'; const assert = require('assert'); const OpCode = require('../binary_protocol/constants').OpCode; const Protocol = require('./protocol'); const ErrorCode = require('../error_code'); const NoSQLError = require('../error').NoSQLError; const PutOp = require('../ops').PutOp; const Op = require('../ops').Op; const Fields = require('./constants').Fields; class GetSerializer extends Protocol { static serialize(nw, req, serialVersion) { nw.startMap(); this.writeHeader(nw, OpCode.GET, serialVersion, req); nw.startMapField(Fields.PAYLOAD); this.writeConsistency(nw, req.opt.consistency); this.writeKey(nw, req.key, req.opt); nw.endMapField(); nw.endMap(); } static deserialize(nr, req) { return this.deserializeResponse(nr, req, (field, res) => { if (field !== Fields.ROW) { return false; } this.readMap(nr, field => { switch (field) { case Fields.VALUE: res.row = this.readRow(nr, req.opt); return true; case Fields.ROW_VERSION: res.version = this.readRowVersion(nr); return true; case Fields.EXPIRATION: res.expirationTime = this.readDateAsLong(nr); return true; case Fields.MODIFIED: res.modificationTime = this.readDateAsLong(nr); return true; default: return false; } }); return true; }, { row: null }); //value if row doesn't exist } } class PutSerializer extends Protocol { static _opcode(opt) { if (opt.ifAbsent) { return OpCode.PUT_IF_ABSENT; } if (opt.ifPresent) { return OpCode.PUT_IF_PRESENT; } if (opt.matchVersion) { return OpCode.PUT_IF_VERSION; } return OpCode.PUT; } static _serializePutOp(nw, op) { this.checkWriteBooleanField(nw, Fields.EXACT_MATCH, op.opt.exactMatch); this.checkWriteBooleanField(nw, Fields.UPDATE_TTL, PutOp.needUpdateTTL(op)); if (op.opt.ttl != null) { nw.writeStringField(Fields.TTL, this.ttlToString(op.opt.ttl)); } this.checkWriteIntField(nw, Fields.IDENTITY_CACHE_SIZE, op.opt.identityCacheSize); if (op.opt.matchVersion != null) { this.writeRowVersion(nw, op.opt.matchVersion); } this.writeValue(nw, op.row, op.opt); } static serialize(nw, req, serialVersion) { nw.startMap(); this.writeHeader(nw, this._opcode(req.opt), serialVersion, req); nw.startMapField(Fields.PAYLOAD); this.serializeWriteRequest(nw, req); this._serializePutOp(nw, req); nw.endMapField(); nw.endMap(); } static deserialize(nr, req) { return this.deserializeResponse(nr, req, (field, res) => { switch (field) { case Fields.ROW_VERSION: res.version = this.readRowVersion(nr); res.success = true; return true; case Fields.RETURN_INFO: this.deserializeReturnInfo(nr, res, req.opt); return true; case Fields.GENERATED: res.generatedValue = this.readFieldValue(nr, req.opt); return true; default: return false; } }, { success: false }); } } class DeleteSerializer extends Protocol { static _opcode(opt) { return opt.matchVersion ? OpCode.DELETE_IF_VERSION : OpCode.DELETE; } static _serializeDeleteOp(nw, op) { if (op.opt.matchVersion != null) { this.writeRowVersion(nw, op.opt.matchVersion); } this.writeKey(nw, op.key, op.opt); } static serialize(nw, req, serialVersion) { nw.startMap(); this.writeHeader(nw, this._opcode(req.opt), serialVersion, req); nw.startMapField(Fields.PAYLOAD); this.serializeWriteRequest(nw, req); this._serializeDeleteOp(nw, req); nw.endMapField(); nw.endMap(); } static deserialize(nr, req) { return this.deserializeResponse(nr, req, (field, res) => { switch (field) { case Fields.SUCCESS: res.success = nr.readBoolean(); return true; case Fields.RETURN_INFO: this.deserializeReturnInfo(nr, res, req.opt); return true; default: return false; } }, { success: false }); } } class MultiDeleteSerializer extends Protocol { static serialize(nw, req, serialVersion) { nw.startMap(); this.writeHeader(nw, OpCode.MULTI_DELETE, serialVersion, req); nw.startMapField(Fields.PAYLOAD); this.writeDurability(nw, req.opt.durability); this.checkWriteIntField(nw, Fields.MAX_WRITE_KB, req.opt.maxWriteKB); if (req.opt.continuationKey != null) { nw.writeBinaryField(Fields.CONTINUATION_KEY, req.opt.continuationKey); } if (req.opt.fieldRange != null) { this.writeFieldRange(nw, req.opt.fieldRange, req.opt); } this.writeKey(nw, req.key, req.opt); nw.endMapField(); nw.endMap(); } static deserialize(nr, req) { return this.deserializeResponse(nr, req, (field, res) => { switch (field) { case Fields.NUM_DELETIONS: res.deletedCount = nr.readInt(); return true; case Fields.CONTINUATION_KEY: res.continuationKey = nr.readBinary(); return true; default: return false; } }); } } class WriteMultipleSerializer extends Protocol { static serialize(nw, req, serialVersion) { nw.startMap(); //req.tableName is set for single-table requests but not for //multi-table requests. this.writeHeader(nw, OpCode.WRITE_MULTIPLE, serialVersion, req); nw.startMapField(Fields.PAYLOAD); this.writeDurability(nw, req.opt.durability); nw.writeIntField(Fields.NUM_OPERATIONS, req.ops.length); nw.startArrayField(Fields.OPERATIONS); let i = 0; for(const op of req.ops) { const start = nw.length; nw.startMap(); this.checkWriteStringField(nw, Fields.TABLE_NAME, op.tableName); if (op.put) { nw.writeIntField(Fields.OP_CODE, PutSerializer._opcode( op.opt)); PutSerializer._serializePutOp(nw, op); } else { assert(op.delete); nw.writeIntField(Fields.OP_CODE, DeleteSerializer._opcode( op.opt)); DeleteSerializer._serializeDeleteOp(nw, op); } this.checkWriteBooleanField(nw, Fields.RETURN_ROW, op.opt.returnExisting); this.checkWriteBooleanField(nw, Fields.ABORT_ON_FAIL, op.opt.abortOnFail); nw.endMap(); const opLen = nw.length - start; if (opLen > Op.REQUEST_SIZE_LIMIT) { throw new NoSQLError(ErrorCode.REQUEST_SIZE_LIMIT_EXCEEDED, `Operation size ${opLen} exceeds the limit of \ ${this.REQUEST_SIZE_LIMIT} for ${op.put ? 'put' : 'delete'} operation at \ index ${i}`, null, req); } i++; } nw.endArrayField(); nw.endMapField(); nw.endMap(); } static _readOpResult(nr, opt) { const res = {}; Protocol.readMap(nr, field => { switch (field) { case Fields.SUCCESS: res.success = nr.readBoolean(); return true; case Fields.ROW_VERSION: res.version = Protocol.readRowVersion(nr); return true; case Fields.GENERATED: res.generatedValue = Protocol.readFieldValue(nr, opt); return true; case Fields.RETURN_INFO: Protocol.deserializeReturnInfo(nr, res, opt); return true; default: return false; } }); return res; } static deserialize(nr, req) { return this.deserializeResponse(nr, req, (field, res) => { switch (field) { case Fields.WM_SUCCESS: res.results = this.readArray(nr, this._readOpResult, req.opt); return true; case Fields.WM_FAILURE: this.readMap(nr, field => { switch (field) { case Fields.WM_FAIL_INDEX: res.failedOpIndex = nr.readInt(); return true; case Fields.WM_FAIL_RESULT: res.failedOpResult = this._readOpResult(nr, req); return true; default: return false; } }); return true; default: return false; } }); } } module.exports = { GetSerializer, PutSerializer, DeleteSerializer, MultiDeleteSerializer, WriteMultipleSerializer };