Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(types): add most of type supports for the driver #48

Merged
merged 14 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ scylla = { version = "0.13.1", features = [
uuid = { version = "1.10", features = ["serde", "v4", "fast-rng"] }
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
openssl = { version = "0.10.66", features = ["vendored"] }
openssl = { version = "0.10", features = ["vendored"] }

[build-dependencies]
napi-build = "2"
Expand Down
22 changes: 22 additions & 0 deletions examples/custom-types/bigint.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Cluster } from "../../index.js";

const nodes = process.env.CLUSTER_NODES?.split(",") ?? ["127.0.0.1:9042"];

console.log(`Connecting to ${nodes}`);

const cluster = new Cluster({ nodes });
const session = await cluster.connect();

await session.execute(
"CREATE KEYSPACE IF NOT EXISTS bigints WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
);
await session.useKeyspace("bigints");

await session.execute(
"CREATE TABLE IF NOT EXISTS bigints (a bigint, primary key (a))",
);

await session.execute("INSERT INTO bigints (a) VALUES (?)", [1238773128n]);

const results = await session.execute("SELECT a FROM bigints");
console.log(results);
22 changes: 22 additions & 0 deletions examples/custom-types/floats.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Cluster, Float } from "../../index.js";

const nodes = process.env.CLUSTER_NODES?.split(",") ?? ["127.0.0.1:9042"];

console.log(`Connecting to ${nodes}`);

const cluster = new Cluster({ nodes });
const session = await cluster.connect();

await session.execute(
"CREATE KEYSPACE IF NOT EXISTS floats WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
);
await session.useKeyspace("floats");

await session.execute(
"CREATE TABLE IF NOT EXISTS floats (a float, primary key (a))",
);

await session.execute("INSERT INTO floats (a) VALUES (?)", [new Float(1.1)]);

const results = await session.execute("SELECT a FROM floats");
console.log(results);
26 changes: 26 additions & 0 deletions examples/custom-types/list.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Cluster, List, Uuid } from "../../index.js";

const nodes = process.env.CLUSTER_NODES?.split(",") ?? ["127.0.0.1:9042"];

console.log(`Connecting to ${nodes}`);

const cluster = new Cluster({ nodes });
const session = await cluster.connect();

await session.execute(
"CREATE KEYSPACE IF NOT EXISTS lists WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
);
await session.useKeyspace("lists");

await session.execute(
"CREATE TABLE IF NOT EXISTS lists (a uuid, b list<int>, primary key (a))",
);

// NOTE: driver is not throwing errors if the return of the function is not used.
await session.execute("INSERT INTO lists (a, b) VALUES (?, ?)", [
Uuid.randomV4(),
new List<number>([1, 2, 3]),
]);

const results = await session.execute("SELECT * FROM lists");
console.log(results);
29 changes: 29 additions & 0 deletions examples/custom-types/map.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Cluster, Map, Uuid } from "../../index.js";

const nodes = process.env.CLUSTER_NODES?.split(",") ?? ["127.0.0.1:9042"];

console.log(`Connecting to ${nodes}`);

const cluster = new Cluster({ nodes });
const session = await cluster.connect();

await session.execute(
"CREATE KEYSPACE IF NOT EXISTS maps WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
);
await session.useKeyspace("maps");

await session.execute(
"CREATE TABLE IF NOT EXISTS maps (a uuid, b map<text, int>, primary key (a))",
);

await session.execute("INSERT INTO maps (a, b) VALUES (?, ?)", [
Uuid.randomV4(),
new Map<string, number>([
["a", 1],
["b", 2],
["c", 3],
]),
]);

const results = await session.execute("SELECT * FROM maps");
console.log(results);
25 changes: 25 additions & 0 deletions examples/custom-types/set.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Cluster, Set, Uuid } from "../../index.js";

const nodes = process.env.CLUSTER_NODES?.split(",") ?? ["127.0.0.1:9042"];

console.log(`Connecting to ${nodes}`);

const cluster = new Cluster({ nodes });
const session = await cluster.connect();

await session.execute(
"CREATE KEYSPACE IF NOT EXISTS sets WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
);
await session.useKeyspace("sets");

await session.execute(
"CREATE TABLE IF NOT EXISTS sets (a uuid, b set<int>, primary key (a))",
);

await session.execute("INSERT INTO sets (a, b) VALUES (?, ?)", [
Uuid.randomV4(),
new Set<number>([1, 2, 3, 1]),
]);

const results = await session.execute("SELECT * FROM sets");
console.log(results);
Empty file added examples/custom-types/tuple.mts
Empty file.
2 changes: 1 addition & 1 deletion examples/udt.mts → examples/custom-types/udt.mts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Cluster } from "../index.js";
import { Cluster } from "../../index.js";

const nodes = process.env.CLUSTER_NODES?.split(",") ?? ["127.0.0.1:9042"];

Expand Down
22 changes: 22 additions & 0 deletions examples/custom-types/uuid.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Cluster, Uuid } from "../../index.js";

const nodes = process.env.CLUSTER_NODES?.split(",") ?? ["127.0.0.1:9042"];

console.log(`Connecting to ${nodes}`);

const cluster = new Cluster({ nodes });
const session = await cluster.connect();

await session.execute(
"CREATE KEYSPACE IF NOT EXISTS uuids WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
);
await session.useKeyspace("uuids");

await session.execute(
"CREATE TABLE IF NOT EXISTS uuids (a uuid, primary key (a))",
);

await session.execute("INSERT INTO uuids (a) VALUES (?)", [Uuid.randomV4()]);

const results = await session.execute("SELECT a FROM uuids");
console.log(results);
24 changes: 24 additions & 0 deletions examples/custom-types/varint.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Cluster, Varint } from "../../index.js";

const nodes = process.env.CLUSTER_NODES?.split(",") ?? ["127.0.0.1:9042"];

console.log(`Connecting to ${nodes}`);

const cluster = new Cluster({ nodes });
const session = await cluster.connect();

await session.execute(
"CREATE KEYSPACE IF NOT EXISTS varints WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
);
await session.useKeyspace("varints");

await session.execute(
"CREATE TABLE IF NOT EXISTS varints (a varint, primary key (a))",
);

await session.execute("INSERT INTO varints (a) VALUES (?)", [
new Varint([0x00, 0x01, 0x02]),
]);

const results = await session.execute("SELECT a FROM varints");
console.log(results);
4 changes: 2 additions & 2 deletions examples/tracing.mts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ console.log(`Connecting to ${nodes}`);
const cluster = new Cluster({ nodes });
const session = await cluster.connect();

const { tracing } = await session.executeWithTracing(
const { tracing, result } = await session.executeWithTracing(
"SELECT * FROM system_schema.scylla_tables",
[],
// {
// prepare: true,
// },
);

console.log(tracing);
console.log(result, tracing);
100 changes: 96 additions & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,41 @@ export declare class Cluster {
}
export type ScyllaCluster = Cluster

export declare class Decimal {
constructor(intVal: Array<number>, scale: number)
/** Returns the string representation of the Decimal. */
toString(): string
}

export declare class Duration {
months: number
days: number
nanoseconds: number
constructor(months: number, days: number, nanoseconds: number)
/** Returns the string representation of the Duration. */
toString(): string
}

/**
* A float number.
*
* Due to the nature of numbers in JavaScript, it's hard to distinguish between integers and floats, so this type is used to represent
* float numbers while any other JS number will be treated as an integer. (This is not the case for BigInts, which are always treated as BigInts).
*/
export declare class Float {
constructor(inner: number)
}

/** A list of any CqlType */
export declare class List<T = NativeTypes> {
constructor(values: T[])
}

/** A map of any CqlType to any CqlType */
export declare class Map<T = NativeTypes, U = NativeTypes> {
constructor(values: Array<Array<T | U>>)
}

export declare class Metrics {
/** Returns counter for nonpaged queries */
getQueriesNum(): bigint
Expand Down Expand Up @@ -76,7 +111,7 @@ export declare class ScyllaClusterData {
export declare class ScyllaSession {
metrics(): Metrics
getClusterData(): Promise<ScyllaClusterData>
executeWithTracing(query: string | Query | PreparedStatement, parameters?: Array<number | string | Uuid | Record<string, number | string | Uuid>> | undefined | null, options?: QueryOptions | undefined | null): Promise<any>
executeWithTracing(query: string | Query | PreparedStatement, parameters?: Array<ParameterWithMapType> | undefined | null, options?: QueryOptions | undefined | null): Promise<TracingReturn>
/**
* Sends a query to the database and receives a response.\
* Returns only a single page of results, to receive multiple pages use (TODO: Not implemented yet)
Expand All @@ -93,8 +128,8 @@ export declare class ScyllaSession {
* driver does not check it by itself, so incorrect data will be written if the order is
* wrong.
*/
execute(query: string | Query | PreparedStatement, parameters?: Array<number | string | Uuid | Record<string, number | string | Uuid>> | undefined | null, options?: QueryOptions | undefined | null): Promise<any>
query(scyllaQuery: Query, parameters?: Array<number | string | Uuid | Record<string, number | string | Uuid>> | undefined | null): Promise<any>
execute(query: string | Query | PreparedStatement, parameters?: Array<ParameterWithMapType> | undefined | null, options?: QueryOptions | undefined | null): Promise<JSQueryResult>
query(scyllaQuery: Query, parameters?: Array<ParameterWithMapType> | undefined | null): Promise<JSQueryResult>
prepare(query: string): Promise<PreparedStatement>
/**
* Perform a batch query\
Expand Down Expand Up @@ -133,7 +168,7 @@ export declare class ScyllaSession {
* console.log(await session.execute("SELECT * FROM users"));
* ```
*/
batch(batch: BatchStatement, parameters: Array<Array<number | string | Uuid | Record<string, number | string | Uuid>> | undefined | null>): Promise<any>
batch(batch: BatchStatement, parameters: Array<Array<ParameterWithMapType> | undefined | null>): Promise<JSQueryResult>
/**
* Sends `USE <keyspace_name>` request on all connections\
* This allows to write `SELECT * FROM table` instead of `SELECT * FROM keyspace.table`\
Expand Down Expand Up @@ -204,6 +239,11 @@ export declare class ScyllaSession {
checkSchemaAgreement(): Promise<boolean>
}

/** A list of any CqlType */
export declare class Set<T = NativeTypes> {
constructor(values: T[])
}

export declare class Uuid {
/** Generates a random UUID v4. */
static randomV4(): Uuid
Expand All @@ -213,6 +253,27 @@ export declare class Uuid {
toString(): string
}

/**
* Native CQL `varint` representation.
*
* Represented as two's-complement binary in big-endian order.
*
* This type is a raw representation in bytes. It's the default
* implementation of `varint` type - independent of any
* external crates and crate features.
*
* # DB data format
* Notice that constructors don't perform any normalization
* on the provided data. This means that underlying bytes may
* contain leading zeros.
*
* Currently, Scylla and Cassandra support non-normalized `varint` values.
* Bytes provided by the user via constructor are passed to DB as is.
*/
export declare class Varint {
constructor(inner: Array<number>)
}

export interface Auth {
username: string
password: string
Expand Down Expand Up @@ -320,3 +381,34 @@ export declare const enum VerifyMode {
None = 0,
Peer = 1
}

type NativeTypes = number | string | Uuid | bigint | Duration | Decimal | Float | List;
type WithMapType = NativeTypes | Record<string, NativeTypes> | NativeTypes[];
type ParameterWithMapType = WithMapType;
type JSQueryResult = Record<string, WithMapType>[];
type TracingReturn = { result: JSQueryResult; tracing: TracingInfo };

export interface TracingInfo {
client?: string; // IP address as a string
command?: string;
coordinator?: string; // IP address as a string
duration?: number;
parameters?: Record<string, string>;
request?: string;
/**
* started_at is a timestamp - time since unix epoch
*/
started_at?: string;
events: TracingEvent[];
}

/**
* A single event happening during a traced query
*/
export interface TracingEvent {
event_id: string;
activity?: string;
source?: string; // IP address as a string
source_elapsed?: number;
thread?: string;
}
13 changes: 10 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,19 +365,26 @@ module.exports.BatchStatement = nativeBinding.BatchStatement
module.exports.ScyllaBatchStatement = nativeBinding.ScyllaBatchStatement
module.exports.Cluster = nativeBinding.Cluster
module.exports.ScyllaCluster = nativeBinding.ScyllaCluster
module.exports.Decimal = nativeBinding.Decimal
module.exports.Duration = nativeBinding.Duration
module.exports.Float = nativeBinding.Float
module.exports.List = nativeBinding.List
module.exports.Map = nativeBinding.Map
module.exports.Metrics = nativeBinding.Metrics
module.exports.PreparedStatement = nativeBinding.PreparedStatement
module.exports.Query = nativeBinding.Query
module.exports.ScyllaClusterData = nativeBinding.ScyllaClusterData
module.exports.ScyllaSession = nativeBinding.ScyllaSession
module.exports.Set = nativeBinding.Set
module.exports.Uuid = nativeBinding.Uuid
module.exports.Varint = nativeBinding.Varint
module.exports.Compression = nativeBinding.Compression
module.exports.Consistency = nativeBinding.Consistency
module.exports.SerialConsistency = nativeBinding.SerialConsistency
module.exports.VerifyMode = nativeBinding.VerifyMode

const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom')

nativeBinding.Uuid.prototype[customInspectSymbol] = function () {
return this.toString();
}
nativeBinding.Uuid.prototype[customInspectSymbol] = function () { return this.toString(); }
nativeBinding.Duration.prototype[customInspectSymbol] = function () { return this.toString(); }
nativeBinding.Decimal.prototype[customInspectSymbol] = function () { return this.toString(); }
Loading
Loading