Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@planetscale/database

Package Overview
Dependencies
Maintainers
4
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@planetscale/database - npm Package Compare versions

Comparing version 0.5.0 to 0.6.0

18

dist/index.d.ts

@@ -28,2 +28,3 @@ export { format } from './sanitization.js';

}
export declare type Cast = typeof cast;
export interface Config {

@@ -36,3 +37,16 @@ url?: string;

format?: (query: string, args: any) => string;
cast?: Cast;
}
export interface Field {
name: string;
type: string;
table?: string;
orgTable?: string | null;
database?: string | null;
orgName?: string | null;
columnLength?: number | null;
charset?: number | null;
flags?: number | null;
columnType?: string | null;
}
export declare class Client {

@@ -49,6 +63,6 @@ private config;

refresh(): Promise<void>;
execute(query: string, args?: any): Promise<ExecutedQuery>;
private createSession;
private postJSON;
execute(query: string, args?: any): Promise<ExecutedQuery>;
}
export declare function connect(config: Config): Connection;
export declare function cast(field: Field, value: string | null): number | string | null;

94

dist/index.js

@@ -5,2 +5,3 @@ import { format } from './sanitization.js';

import { decode } from './text.js';
const PACKAGE_VERSION = '0.5.0';
export class DatabaseError extends Error {

@@ -43,37 +44,2 @@ constructor(message, status, body) {

}
async createSession() {
const url = new URL('/psdb.v1alpha1.Database/CreateSession', `https://${this.config.host}`);
const { session } = await this.postJSON(url);
this.session = session;
return session;
}
async postJSON(url, body = {}) {
const auth = btoa(`${this.config.username}:${this.config.password}`);
const { fetch } = this.config;
const response = await fetch(url.toString(), {
method: 'POST',
body: JSON.stringify(body),
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${auth}`
}
});
if (response.ok) {
return await response.json();
}
else {
let error = null;
try {
const e = (await response.json()).error;
error = new DatabaseError(e.message, response.status, e);
}
catch {
error = new DatabaseError(response.statusText, response.status, {
code: 'internal',
message: response.statusText
});
}
throw error;
}
}
async execute(query, args) {

@@ -84,3 +50,3 @@ const url = new URL('/psdb.v1alpha1.Database/Execute', `https://${this.config.host}`);

const start = Date.now();
const saved = await this.postJSON(url, { query: sql, session: this.session });
const saved = await postJSON(this.config, url, { query: sql, session: this.session });
const time = Date.now() - start;

@@ -91,3 +57,3 @@ const { result, session, error } = saved;

this.session = session;
const rows = result ? parse(result) : [];
const rows = result ? parse(result, this.config.cast || cast) : [];
const headers = result ? result.fields?.map((f) => f.name) ?? [] : [];

@@ -108,17 +74,53 @@ const typeByName = (acc, { name, type }) => ({ ...acc, [name]: type });

}
async createSession() {
const url = new URL('/psdb.v1alpha1.Database/CreateSession', `https://${this.config.host}`);
const { session } = await postJSON(this.config, url);
this.session = session;
return session;
}
}
async function postJSON(config, url, body = {}) {
const auth = btoa(`${config.username}:${config.password}`);
const { fetch } = config;
const response = await fetch(url.toString(), {
method: 'POST',
body: JSON.stringify(body),
headers: {
'Content-Type': 'application/json',
'User-Agent': `database-js/${PACKAGE_VERSION}`,
Authorization: `Basic ${auth}`
}
});
if (response.ok) {
return await response.json();
}
else {
let error = null;
try {
const e = (await response.json()).error;
error = new DatabaseError(e.message, response.status, e);
}
catch {
error = new DatabaseError(response.statusText, response.status, {
code: 'internal',
message: response.statusText
});
}
throw error;
}
}
export function connect(config) {
return new Connection(config);
}
function parseRow(fields, rawRow) {
function parseRow(fields, rawRow, cast) {
const row = decodeRow(rawRow);
return fields.reduce((acc, field, ix) => {
acc[field.name] = parseColumn(field.type, row[ix]);
acc[field.name] = cast(field, row[ix]);
return acc;
}, {});
}
function parse(result) {
function parse(result, cast) {
const fields = result.fields;
const rows = result.rows ?? [];
return rows.map((row) => parseRow(fields, row));
return rows.map((row) => parseRow(fields, row, cast));
}

@@ -137,7 +139,7 @@ function decodeRow(row) {

}
function parseColumn(type, value) {
export function cast(field, value) {
if (value === '' || value == null) {
return value;
}
switch (type) {
switch (field.type) {
case 'INT8':

@@ -147,3 +149,2 @@ case 'INT16':

case 'INT32':
case 'INT64':
case 'UINT8':

@@ -153,3 +154,2 @@ case 'UINT16':

case 'UINT32':
case 'UINT64':
case 'YEAR':

@@ -159,4 +159,6 @@ return parseInt(value, 10);

case 'FLOAT64':
return parseFloat(value);
case 'DECIMAL':
return parseFloat(value);
case 'INT64':
case 'UINT64':
case 'DATE':

@@ -163,0 +165,0 @@ case 'TIME':

{
"name": "@planetscale/database",
"version": "0.5.0",
"version": "0.6.0",
"description": "A JavaScript client for PlanetScale databases.",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -1,4 +0,4 @@

# PlanetScale database client
# PlanetScale Serverless Driver for JavaScript
A JavaScript client for PlanetScale databases.
A Fetch API-compatible PlanetScale database driver for serverless and edge compute platforms that require HTTP external connections, such as Cloudflare Workers or Vercel Edge Functions

@@ -8,3 +8,3 @@ ## Installation

```
$ npm install @planetscale/database
npm install @planetscale/database
```

@@ -36,3 +36,3 @@

const config = {
url: process.env['DATABASE_URL'] || 'mysql://user:pass@aws.connect.psdb.cloud'
url: process.env['DATABASE_URL'] || 'mysql://user:pass@host'
}

@@ -51,3 +51,3 @@

const client = new Client({
host: 'aws.connect.psdb.cloud',
host: '<host>',
username: '<user>',

@@ -74,3 +74,3 @@ password: '<password>'

fetch,
host: 'aws.connect.psdb.cloud',
host: '<host>',
username: '<user>',

@@ -87,5 +87,12 @@ password: '<password>'

Query replacement parameters identified with `?` are replaced with escaped values. Providing a custom format function overrides the built-in escaping with an external library, like [`sqlstring`](https://github.com/mysqljs/sqlstring).
Query replacement parameters identified with `?` are replaced with escaped values. Named replacement parameters are supported with a colon prefix.
```ts
const results1 = await conn.execute('select 1 from dual where 1=?', [42])
const results2 = await conn.execute('select 1 from dual where 1=:id', { id: 42 })
```
Providing a custom format function overrides the built-in escaping with an external library, like [`sqlstring`](https://github.com/mysqljs/sqlstring).
```ts
import { connect } from '@planetscale/database'

@@ -96,3 +103,3 @@ import SqlString from 'sqlstring'

format: SqlString.format,
host: 'aws.connect.psdb.cloud',
host: '<host>',
username: '<user>',

@@ -107,6 +114,24 @@ password: '<password>'

Named replacement parameters are supported with a colon prefix.
### Custom type casting function
Column values are converted to their corresponding JavaScript data types. This can be customized by providing a `cast` function.
```ts
const results = await conn.execute('select 1 from dual where 1=:id', { id: 42 })
import { connect, cast } from '@planetscale/database'
function inflate(field, value) {
if (field.type === 'INT64' || field.type === 'UINT64') {
return BigInt(value)
}
return cast(field, value)
}
const config = {
cast: inflate,
host: '<host>',
username: '<user>',
password: '<password>'
}
const conn = connect(config)
```

@@ -113,0 +138,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc