mariadb
Version:
fast mariadb or mysql connector.
312 lines (261 loc) • 8.85 kB
JavaScript
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2015-2024 MariaDB Corporation Ab
;
const QUOTE = 0x27;
// Cache common GeoJSON types
const GEO_TYPES = new Set([
'Point',
'LineString',
'Polygon',
'MultiPoint',
'MultiLineString',
'MultiPolygon',
'GeometryCollection'
]);
// Optimized function to pad numbers with leading zeros
const formatDigit = function (val, significantDigit) {
const str = `${val}`;
return str.length < significantDigit ? '0'.repeat(significantDigit - str.length) + str : str;
};
class TextEncoder {
/**
* Write (and escape) current parameter value to output writer
*
* @param out output writer
* @param value current parameter. Expected to be non-null
* @param opts connection options
* @param info connection information
*/
static writeParam(out, value, opts, info) {
switch (typeof value) {
case 'boolean':
out.writeStringAscii(value ? 'true' : 'false');
break;
case 'bigint':
case 'number':
out.writeStringAscii(`${value}`);
break;
case 'string':
out.writeStringEscapeQuote(value);
break;
case 'object':
if (Object.prototype.toString.call(value) === '[object Date]') {
out.writeStringAscii(TextEncoder.getLocalDate(value));
} else if (Buffer.isBuffer(value)) {
out.writeStringAscii("_BINARY '");
out.writeBufferEscape(value);
out.writeInt8(QUOTE);
} else if (typeof value.toSqlString === 'function') {
out.writeStringEscapeQuote(String(value.toSqlString()));
} else if (Array.isArray(value)) {
if (opts.arrayParenthesis) {
out.writeStringAscii('(');
}
for (let i = 0; i < value.length; i++) {
if (i !== 0) out.writeStringAscii(',');
if (value[i] == null) {
out.writeStringAscii('NULL');
} else TextEncoder.writeParam(out, value[i], opts, info);
}
if (opts.arrayParenthesis) {
out.writeStringAscii(')');
}
} else {
if (value.type != null && GEO_TYPES.has(value.type)) {
//GeoJSON format.
const isMariaDb = info.isMariaDB();
const prefix =
(isMariaDb && info.hasMinVersion(10, 1, 4)) || (!isMariaDb && info.hasMinVersion(5, 7, 6)) ? 'ST_' : '';
switch (value.type) {
case 'Point':
out.writeStringAscii(
prefix + "PointFromText('POINT(" + TextEncoder.geoPointToString(value.coordinates) + ")')"
);
break;
case 'LineString':
out.writeStringAscii(
prefix + "LineFromText('LINESTRING(" + TextEncoder.geoArrayPointToString(value.coordinates) + ")')"
);
break;
case 'Polygon':
out.writeStringAscii(
prefix +
"PolygonFromText('POLYGON(" +
TextEncoder.geoMultiArrayPointToString(value.coordinates) +
")')"
);
break;
case 'MultiPoint':
out.writeStringAscii(
prefix +
"MULTIPOINTFROMTEXT('MULTIPOINT(" +
TextEncoder.geoArrayPointToString(value.coordinates) +
")')"
);
break;
case 'MultiLineString':
out.writeStringAscii(
prefix +
"MLineFromText('MULTILINESTRING(" +
TextEncoder.geoMultiArrayPointToString(value.coordinates) +
")')"
);
break;
case 'MultiPolygon':
out.writeStringAscii(
prefix +
"MPolyFromText('MULTIPOLYGON(" +
TextEncoder.geoMultiPolygonToString(value.coordinates) +
")')"
);
break;
case 'GeometryCollection':
out.writeStringAscii(
prefix +
"GeomCollFromText('GEOMETRYCOLLECTION(" +
TextEncoder.geometricCollectionToString(value.geometries) +
")')"
);
break;
}
} else if (String === value.constructor) {
out.writeStringEscapeQuote(value);
break;
} else {
if (opts.permitSetMultiParamEntries) {
let first = true;
for (const key in value) {
const val = value[key];
if (typeof val === 'function') continue;
if (first) {
first = false;
} else {
out.writeStringAscii(',');
}
out.writeString('`' + key + '`');
if (val == null) {
out.writeStringAscii('=NULL');
} else {
out.writeStringAscii('=');
TextEncoder.writeParam(out, val, opts, info);
}
}
if (first) out.writeStringEscapeQuote(JSON.stringify(value));
} else {
out.writeStringEscapeQuote(JSON.stringify(value));
}
}
}
break;
}
}
static geometricCollectionToString(geo) {
if (!geo) return '';
const len = geo.length;
let st = '';
for (let i = 0; i < len; i++) {
const item = geo[i];
//GeoJSON format.
if (i !== 0) st += ',';
switch (item.type) {
case 'Point':
st += `POINT(${TextEncoder.geoPointToString(item.coordinates)})`;
break;
case 'LineString':
st += `LINESTRING(${TextEncoder.geoArrayPointToString(item.coordinates)})`;
break;
case 'Polygon':
st += `POLYGON(${TextEncoder.geoMultiArrayPointToString(item.coordinates)})`;
break;
case 'MultiPoint':
st += `MULTIPOINT(${TextEncoder.geoArrayPointToString(item.coordinates)})`;
break;
case 'MultiLineString':
st += `MULTILINESTRING(${TextEncoder.geoMultiArrayPointToString(item.coordinates)})`;
break;
case 'MultiPolygon':
st += `MULTIPOLYGON(${TextEncoder.geoMultiPolygonToString(item.coordinates)})`;
break;
}
}
return st;
}
static geoMultiPolygonToString(coords) {
if (!coords) return '';
const len = coords.length;
if (len === 0) return '';
let st = '(';
for (let i = 0; i < len; i++) {
if (i !== 0) st += ',(';
st += TextEncoder.geoMultiArrayPointToString(coords[i]) + ')';
}
return st;
}
static geoMultiArrayPointToString(coords) {
if (!coords) return '';
const len = coords.length;
if (len === 0) return '';
let st = '(';
for (let i = 0; i < len; i++) {
if (i !== 0) st += ',(';
st += TextEncoder.geoArrayPointToString(coords[i]) + ')';
}
return st;
}
static geoArrayPointToString(coords) {
if (!coords) return '';
const len = coords.length;
if (len === 0) return '';
let st = '';
for (let i = 0; i < len; i++) {
if (i !== 0) st += ',';
st += TextEncoder.geoPointToString(coords[i]);
}
return st;
}
static geoPointToString(coords) {
if (!coords) return '';
const x = isNaN(coords[0]) ? '' : coords[0];
const y = isNaN(coords[1]) ? '' : coords[1];
return x + ' ' + y;
}
static getLocalDate(date) {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hours = date.getHours();
const minutes = date.getMinutes();
const seconds = date.getSeconds();
const ms = date.getMilliseconds();
const d = "'" + year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
if (ms === 0) return d + "'";
return d + '.' + (ms < 10 ? '00' : ms < 100 ? '0' : '') + ms + "'";
}
static getFixedFormatDate(date) {
const year = date.getFullYear();
const mon = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const min = date.getMinutes();
const sec = date.getSeconds();
const ms = date.getMilliseconds();
let result =
"'" +
formatDigit(year, 4) +
'-' +
formatDigit(mon, 2) +
'-' +
formatDigit(day, 2) +
' ' +
formatDigit(hour, 2) +
':' +
formatDigit(min, 2) +
':' +
formatDigit(sec, 2);
if (ms > 0) {
result += '.' + formatDigit(ms, 3);
}
return result + "'";
}
}
module.exports = TextEncoder;