Socket
Socket
Sign inDemoInstall

kysely

Package Overview
Dependencies
Maintainers
1
Versions
158
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

kysely - npm Package Compare versions

Comparing version 0.1.1 to 0.1.2

lib/dialect/dialect.d.ts

48

lib/kysely.d.ts
import { RawBuilder } from './raw-builder/raw-builder';
import { TableArg, FromQueryBuilder } from './query-builder/methods/from-method';
import { DriverConfig } from './driver/driver-config';
import { Dialect } from './dialect/dialect';
/**

@@ -38,2 +40,4 @@ * The main Kysely class.

export declare class Kysely<DB> {
#private;
constructor(config: KyselyConfig);
/**

@@ -265,3 +269,3 @@ * Creates a query builder against the given table/tables.

* ```sql
* select * from "person" where now() - birth_date > interval $0 year
* select * from "person" where now() - birth_date > interval $1 year
* ```

@@ -286,2 +290,44 @@ *

raw<T = unknown>(sql: string, params?: any[]): RawBuilder<T>;
/**
* Returns true if called inside a Kysely.transaction() callback.
*/
isTransactionRunning(): boolean;
/**
* Begins a transaction for the async chain started inside the callback.
*
* Any `kysely` query started inside the callback or any method called
* by the callback will automatically use the save transaction. No need to
* pass around a transaction object. This is possible through node's async
* hooks and specifically `AsyncLocalStorage`.
*
* @example
* ```ts
* async function main() {
* await db.transaction(async () => {
* await doStuff()
* });
* }
*
* async function doStuff() {
* // This automatically uses the correct transasction because `doStuff` was
* // called inside the transaction method that registers the transaction
* // for a shared `AsyncLocalStorage` inside `Kysely`.
* await db.query('person').insert({ first_name: 'Jennifer' }).execute()
*
* return doMoreStuff();
* }
*
* function doMoreStuff(): Promise<void> {
* // Even this is automatically uses the correct transaction even though
* // we didn't `await` on the method. Node's async hooks work with all
* // possible kinds of async events.
* return db.query('pet').insert({ name: 'Fluffy' }).execute()
* }
* ```
*/
transaction<T>(callback: () => Promise<T>): Promise<T>;
destroy(): Promise<void>;
}
export interface KyselyConfig extends DriverConfig {
dialect: 'postgres' | Dialect;
}

@@ -8,2 +8,5 @@ "use strict";

const from_method_1 = require("./query-builder/methods/from-method");
const postgres_dialect_1 = require("./dialect/postgres/postgres-dialect");
const transactional_connection_provider_1 = require("./driver/transactional-connection-provider");
const async_hooks_1 = require("async_hooks");
/**

@@ -44,5 +47,19 @@ * The main Kysely class.

class Kysely {
constructor(config) {
this.#transactions = new async_hooks_1.AsyncLocalStorage();
const dialect = createDialect(config);
this.#driver = dialect.createDriver(config);
this.#compiler = dialect.createQueryCompiler();
}
#driver;
#compiler;
#transactions;
query(from) {
const query = new query_builder_1.QueryBuilder();
return new query_builder_1.QueryBuilder(query_node_1.cloneQueryNodeWithFroms(query.toOperationNode(), from_method_1.parseFromArgs(query, from)));
const query = new query_builder_1.QueryBuilder({ queryNode: query_node_1.createQueryNode() });
const connectionProvider = new transactional_connection_provider_1.TransactionalConnectionProvider(this.#driver, this.#transactions);
return new query_builder_1.QueryBuilder({
compiler: this.#compiler,
connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithFroms(query.toOperationNode(), from_method_1.parseFromArgs(query, from)),
});
}

@@ -148,3 +165,3 @@ /**

* ```sql
* select * from "person" where now() - birth_date > interval $0 year
* select * from "person" where now() - birth_date > interval $1 year
* ```

@@ -171,3 +188,82 @@ *

}
/**
* Returns true if called inside a Kysely.transaction() callback.
*/
isTransactionRunning() {
return !!this.#transactions.getStore();
}
/**
* Begins a transaction for the async chain started inside the callback.
*
* Any `kysely` query started inside the callback or any method called
* by the callback will automatically use the save transaction. No need to
* pass around a transaction object. This is possible through node's async
* hooks and specifically `AsyncLocalStorage`.
*
* @example
* ```ts
* async function main() {
* await db.transaction(async () => {
* await doStuff()
* });
* }
*
* async function doStuff() {
* // This automatically uses the correct transasction because `doStuff` was
* // called inside the transaction method that registers the transaction
* // for a shared `AsyncLocalStorage` inside `Kysely`.
* await db.query('person').insert({ first_name: 'Jennifer' }).execute()
*
* return doMoreStuff();
* }
*
* function doMoreStuff(): Promise<void> {
* // Even this is automatically uses the correct transaction even though
* // we didn't `await` on the method. Node's async hooks work with all
* // possible kinds of async events.
* return db.query('pet').insert({ name: 'Fluffy' }).execute()
* }
* ```
*/
async transaction(callback) {
let connection = null;
if (this.isTransactionRunning()) {
throw new Error('You attempted to call Kysely.transaction() inside an existing transaction. Nested transactions are not yet supported. See the Kysely.isTransactionRunning() method.');
}
try {
await this.#driver.ensureInit();
connection = await this.#driver.acquireConnection();
await connection.execute({ sql: 'BEGIN', bindings: [] });
return await this.#transactions.run(connection, () => {
return callback();
});
}
catch (error) {
if (connection) {
await connection.execute({ sql: 'ROLLBACK', bindings: [] });
}
throw error;
}
finally {
if (connection) {
await this.#driver.releaseConnection(connection);
}
}
}
async destroy() {
await this.#driver.ensureDestroy();
this.#transactions.disable();
}
}
exports.Kysely = Kysely;
function createDialect(config) {
if (typeof config.dialect !== 'string') {
return config.dialect;
}
else if (config.dialect === 'postgres') {
return new postgres_dialect_1.PostgresDialect();
}
else {
throw new Error(`unknown dialect ${config.dialect}`);
}
}

12

lib/query-builder/join-builder.js

@@ -22,4 +22,8 @@ "use strict";

subQuery(table) {
const query = new query_builder_1.QueryBuilder();
return new query_builder_1.QueryBuilder(query_node_1.cloneQueryNodeWithFroms(query.toOperationNode(), from_method_1.parseFromArgs(query, table)));
const query = new query_builder_1.QueryBuilder({
queryNode: query_node_1.createQueryNode(),
});
return new query_builder_1.QueryBuilder({
queryNode: query_node_1.cloneQueryNodeWithFroms(query.toOperationNode(), from_method_1.parseFromArgs(query, table)),
});
}

@@ -30,3 +34,5 @@ /**

on(lhs, op, rhs) {
const query = new query_builder_1.QueryBuilder();
const query = new query_builder_1.QueryBuilder({
queryNode: query_node_1.createQueryNode(),
});
return new JoinBuilder(join_node_1.cloneJoinNodeWithOn(this.#joinNode, 'and', filter_method_1.parseFilterReferenceArgs(query, lhs, op, rhs)));

@@ -33,0 +39,0 @@ }

@@ -15,2 +15,3 @@ "use strict";

const parens_node_1 = require("../../operation-node/parens-node");
const query_node_1 = require("../../operation-node/query-node");
const OPERATOR_WHITELIST = [

@@ -133,3 +134,6 @@ '=',

}
const query = grouper(new query_builder_1.QueryBuilder());
const inputQuery = new query_builder_1.QueryBuilder({
queryNode: query_node_1.createQueryNode(),
});
const query = grouper(inputQuery);
const where = query.toOperationNode().where;

@@ -136,0 +140,0 @@ if (!where) {

import { JoinNode, JoinType } from '../../operation-node/join-node';
import { AnyColumn, AnyColumnWithTable, AnyQueryBuilder } from '../type-utils';
import { FromArgDatabaseType, ExtractAliasesFromFromArg } from './from-method';
import { JoinBuilder } from '../join-builder';
export declare type JoinReferenceArg<DB, TB extends keyof DB, F> = AnyColumn<FromArgDatabaseType<DB, F>, TB | ExtractAliasesFromFromArg<DB, F>> | AnyColumnWithTable<FromArgDatabaseType<DB, F>, TB | ExtractAliasesFromFromArg<DB, F>>;
export declare type JoinCallbackArg<DB, TB extends keyof DB, F> = (join: JoinBuilder<FromArgDatabaseType<DB, F>, TB | ExtractAliasesFromFromArg<DB, F>>) => JoinBuilder<any, any>;
export declare function parseJoinArgs(query: AnyQueryBuilder, joinType: JoinType, args: any[]): JoinNode;

@@ -7,4 +7,8 @@ "use strict";

const filter_method_1 = require("./filter-method");
const join_builder_1 = require("../join-builder");
function parseJoinArgs(query, joinType, args) {
if (args.length === 3) {
if (args.length === 2) {
return parseCallbackJoin(query, joinType, args[0], args[1]);
}
else if (args.length === 3) {
return parseSingleOnJoin(query, joinType, args[0], args[1], args[2]);

@@ -17,2 +21,7 @@ }

exports.parseJoinArgs = parseJoinArgs;
function parseCallbackJoin(query, joinType, from, callback) {
const tableNode = from_method_1.parseFromArg(query, from);
const joinBuilder = callback(new join_builder_1.JoinBuilder(join_node_1.createJoinNode(joinType, tableNode)));
return joinBuilder.toOperationNode();
}
function parseSingleOnJoin(query, joinType, from, lhsColumn, rhsColumn) {

@@ -19,0 +28,0 @@ const tableNode = from_method_1.parseFromArg(query, from);

@@ -5,3 +5,3 @@ import { AliasNode } from '../operation-node/alias-node';

import { QueryCompiler } from '../query-compiler/query-compiler';
import { JoinReferenceArg } from './methods/join-method';
import { JoinCallbackArg, JoinReferenceArg } from './methods/join-method';
import { QueryNode } from '../operation-node/query-node';

@@ -11,2 +11,3 @@ import { TableArg, FromQueryBuilder } from './methods/from-method';

import { FilterReferenceArg, FilterValueArg, ExistsFilterArg, FilterOperatorArg } from './methods/filter-method';
import { ConnectionProvider } from '../driver/connection-provider';
/**

@@ -29,3 +30,3 @@ * The main query builder class.

#private;
constructor(queryNode?: QueryNode);
constructor({ queryNode, compiler, connectionProvider }: QueryBuilderArgs);
/**

@@ -76,2 +77,120 @@ * Creates a subquery.

* Adds a `where` clause to the query.
*
* Also see {@link QueryBuilder.whereExists | whereExists} and {@link QueryBuilder.whereRef | whereRef}
*
* @example
* Find a row by column value:
*
* ```ts
* db.query('person')
* .where('id', '=', 100)
* .selectAll()
* ```
*
* The generated SQL (postgresql):
*
* ```sql
* select * from "person" where "id" = $1
* ```
*
* @example
* Operator can be any supported operator or if the typings don't support it
* you can always use `db.raw('your operator')`.
*
* ```ts
* db.query('person')
* .where('id', '>', 100)
* .selectAll()
* ```
*
* The generated SQL (postgresql):
*
* ```sql
* select * from "person" where "id" > $1
* ```
*
* @example
* A `where in` query. The first argument can contain
* the table name, but it's not mandatory.
*
* ```ts
* db.query('person')
* .where('person.id', 'in', [100, 200, 300])
* .selectAll()
* ```
*
* The generated SQL (postgresql):
*
* ```sql
* select * from "person" where "id" in ($1, $2, $3)
* ```
*
* @example
* Both the first and third argument can also be a subquery.
* A subquery is defined by passing a function:
*
* ```ts
* db.query('person')
* .where(
* (qb) => qb.subQuery('pet')
* .select('pet.id')
* .whereRef('pet.owner_id', '=', 'person.id'),
* 'in',
* [100, 200, 300]
* )
* .selectAll()
* ```
*
* The generated SQL (postgresql):
*
* ```sql
* select *
* from "person"
* where (
* select "pet"."id"
* from "pet"
* where "pet"."owner_id" = "person"."id"
* ) in ($1, $2, $3)
* ```
*
* @example
* If everything else fails, you can always pass {@link Kysely.raw | raw}
* as any of the arguments, including the operator:
*
* ```ts
* db.query('person')
* .where(
* db.raw('coalesce(first_name, last_name)'),
* 'like',
* '%' + name + '%',
* )
* .selectAll()
* ```
*
* The generated SQL (postgresql):
*
* ```sql
* select *
* from "person"
* where coalesce(first_name, last_name) like $1
* ```
*
* @example
* If you only pass one function argument to this method, it can be
* used to create parentheses around other where clauses:
*
* ```ts
* db.query('person')
* .selectAll()
* .where((qb) => qb
* .where('id', '=', 1)
* .orWhere('id', '=', 2)
* )
* ```
*
* The generated SQL (postgresql):
*
* ```sql
* select * from "person" (where "id" = 1 or "id" = 2)
* ```
*/

@@ -89,3 +208,3 @@ where(lhs: FilterReferenceArg<DB, TB, O>, op: FilterOperatorArg, rhs: FilterValueArg<DB, TB, O>): QueryBuilder<DB, TB, O>;

* It's often necessary to wrap `or where` clauses in parentheses to control
* the precendence. You can use the one argument version of the `where` method
* precendence. You can use the one argument version of the `where` method
* for that. See the examples.

@@ -226,2 +345,3 @@ *

innerJoin<F extends TableArg<DB, TB, O>, K1 extends JoinReferenceArg<DB, TB, F>, K2 extends JoinReferenceArg<DB, TB, F>>(table: F, k1: K1, k2: K2): FromQueryBuilder<DB, TB, O, F>;
innerJoin<F extends TableArg<DB, TB, O>, FN extends JoinCallbackArg<DB, TB, F>>(table: F, callback: FN): FromQueryBuilder<DB, TB, O, F>;
/**

@@ -232,6 +352,11 @@ *

toOperationNode(): QueryNode;
compile(compiler: QueryCompiler): CompiledQuery;
castTo<T>(): QueryBuilder<DB, TB, T>;
compile(): CompiledQuery;
execute(): Promise<O[]>;
}
export interface QueryBuilderArgs {
queryNode: QueryNode;
compiler?: QueryCompiler;
connectionProvider?: ConnectionProvider;
}
/**

@@ -238,0 +363,0 @@ * {@link QueryBuilder} with an alias. The result of calling {@link QueryBuilder.as}.

@@ -26,11 +26,21 @@ "use strict";

class QueryBuilder {
constructor(queryNode = query_node_1.createQueryNode()) {
constructor({ queryNode, compiler, connectionProvider }) {
this.#queryNode = queryNode;
this.#compiler = compiler;
this.#connectionProvider = connectionProvider;
}
#queryNode;
#compiler;
#connectionProvider;
subQuery(table) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithFroms(query_node_1.createQueryNode(), from_method_1.parseFromArgs(this, table)));
return new QueryBuilder({
queryNode: query_node_1.cloneQueryNodeWithFroms(query_node_1.createQueryNode(), from_method_1.parseFromArgs(this, table)),
});
}
where(...args) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseFilterArgs(this, args)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseFilterArgs(this, args)),
});
}

@@ -41,6 +51,14 @@ /**

whereRef(lhs, op, rhs) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseFilterReferenceArgs(this, lhs, op, rhs)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseFilterReferenceArgs(this, lhs, op, rhs)),
});
}
orWhere(...args) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseFilterArgs(this, args)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseFilterArgs(this, args)),
});
}

@@ -51,3 +69,7 @@ /**

orWhereRef(lhs, op, rhs) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseFilterReferenceArgs(this, lhs, op, rhs)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseFilterReferenceArgs(this, lhs, op, rhs)),
});
}

@@ -58,3 +80,7 @@ /**

whereExists(arg) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseExistsFilterArgs(this, 'exists', arg)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseExistsFilterArgs(this, 'exists', arg)),
});
}

@@ -65,3 +91,7 @@ /**

whereNotExists(arg) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseExistsFilterArgs(this, 'not exists', arg)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseExistsFilterArgs(this, 'not exists', arg)),
});
}

@@ -72,3 +102,7 @@ /**

orWhereExists(arg) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseExistsFilterArgs(this, 'exists', arg)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseExistsFilterArgs(this, 'exists', arg)),
});
}

@@ -79,9 +113,21 @@ /**

orWhereNotExists(arg) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseExistsFilterArgs(this, 'not exists', arg)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseExistsFilterArgs(this, 'not exists', arg)),
});
}
select(selection) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithSelections(this.#queryNode, select_method_1.parseSelectArgs(this, selection)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithSelections(this.#queryNode, select_method_1.parseSelectArgs(this, selection)),
});
}
distinctOn(selection) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithDistinctOnSelections(this.#queryNode, select_method_1.parseSelectArgs(this, selection)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithDistinctOnSelections(this.#queryNode, select_method_1.parseSelectArgs(this, selection)),
});
}

@@ -92,3 +138,7 @@ /**

distinct() {
return new QueryBuilder(query_node_1.cloneQueryNodeWithSelectModifier(this.#queryNode, 'Distinct'));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithSelectModifier(this.#queryNode, 'Distinct'),
});
}

@@ -99,3 +149,7 @@ /**

forUpdate() {
return new QueryBuilder(query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForUpdate'));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForUpdate'),
});
}

@@ -106,3 +160,7 @@ /**

forShare() {
return new QueryBuilder(query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForShare'));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForShare'),
});
}

@@ -113,3 +171,7 @@ /**

forKeyShare() {
return new QueryBuilder(query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForKeyShare'));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForKeyShare'),
});
}

@@ -120,3 +182,7 @@ /**

forNoKeyUpdate() {
return new QueryBuilder(query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForNoKeyUpdate'));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForNoKeyUpdate'),
});
}

@@ -127,3 +193,7 @@ /**

skipLocked() {
return new QueryBuilder(query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'SkipLocked'));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'SkipLocked'),
});
}

@@ -134,9 +204,21 @@ /**

noWait() {
return new QueryBuilder(query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'NoWait'));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'NoWait'),
});
}
selectAll(table) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithSelections(this.#queryNode, select_method_1.parseSelectAllArgs(table)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithSelections(this.#queryNode, select_method_1.parseSelectAllArgs(table)),
});
}
innerJoin(...args) {
return new QueryBuilder(query_node_1.cloneQueryNodeWithJoin(this.#queryNode, join_method_1.parseJoinArgs(this, 'InnerJoin', args)));
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: query_node_1.cloneQueryNodeWithJoin(this.#queryNode, join_method_1.parseJoinArgs(this, 'InnerJoin', args)),
});
}

@@ -152,10 +234,29 @@ /**

}
compile(compiler) {
return compiler.compile(this.#queryNode);
}
castTo() {
return new QueryBuilder(this.#queryNode);
return new QueryBuilder({
compiler: this.#compiler,
connectionProvider: this.#connectionProvider,
queryNode: this.#queryNode,
});
}
compile() {
if (!this.#compiler) {
throw new Error(`this query cannot be compiled to SQL`);
}
return this.#compiler.compile(this.#queryNode);
}
async execute() {
return [{}];
if (!this.#connectionProvider) {
throw new Error(`this query cannot be executed`);
}
let connection;
try {
connection = await this.#connectionProvider.acquireConnection();
return await connection.execute(this.compile());
}
finally {
if (connection) {
await this.#connectionProvider.releaseConnection(connection);
}
}
}

@@ -162,0 +263,0 @@ }

@@ -40,3 +40,3 @@ import { AliasNode } from '../operation-node/alias-node';

protected visitIdentifier(node: IdentifierNode): void;
protected visitUnwrappedIdentifier(node: IdentifierNode): void;
protected compileUnwrappedIdentifier(node: IdentifierNode): void;
protected visitFilter(node: FilterNode): void;

@@ -53,5 +53,6 @@ protected visitAnd(node: AndNode): void;

protected visitTable(node: TableNode): void;
protected appendIdentifierWrapper(): void;
protected appendLeftIdentifierWrapper(): void;
protected appendRightIdentifierWrapper(): void;
protected append(str: string): void;
protected appendValue(value: any): void;
}

@@ -113,7 +113,7 @@ "use strict";

visitIdentifier(node) {
this.appendIdentifierWrapper();
this.visitUnwrappedIdentifier(node);
this.appendIdentifierWrapper();
this.appendLeftIdentifierWrapper();
this.compileUnwrappedIdentifier(node);
this.appendRightIdentifierWrapper();
}
visitUnwrappedIdentifier(node) {
compileUnwrappedIdentifier(node) {
this.append(node.identifier);

@@ -191,5 +191,8 @@ }

}
appendIdentifierWrapper() {
appendLeftIdentifierWrapper() {
this.append('"');
}
appendRightIdentifierWrapper() {
this.append('"');
}
append(str) {

@@ -196,0 +199,0 @@ this.#sqlFragments.push(str);

{
"name": "kysely",
"version": "0.1.1",
"version": "0.1.2",
"description": "Type safe SQL query builder",

@@ -19,4 +19,6 @@ "main": "lib/index.js",

"@types/node": "^14.14.31",
"@types/pg": "^7.14.11",
"chai": "^4.3.0",
"mocha": "^8.3.0",
"pg": "^8.5.1",
"prettier": "^2.2.1",

@@ -23,0 +25,0 @@ "ts-node": "^9.1.1",

# Kysely
A type safe typescript SQL query builder for node.js.
A type-safe and autocompletion-friendly typescript SQL query builder for node.js. Heavily inspired by
[knex](http://knexjs.org/) but not intended to be a clone.
![](https://github.com/koskimas/kysely/blob/master/assets/demo.gif)
Kysely's typescript typings only allow you to join tables that are available in the database and refer to
columns of the tables that are joined to the query. The result type also always only contains the selected
columns with correct types and aliases. This allows tools like vscode autocomplete to make your life so
much easier.
Kysely's typings only allow you to use tables that are available in the database and refer to
columns of the tables that are joined to the query. The result type always only contains the selected
columns with correct types and aliases. This allows tools like vscode autocompletion to make your life
so much easier.
As you can see in the gif above, through the pure magic of modern typescript, Kysely is even able to parse
the alias given to `pet.name` and add a column `pet_name` to the result row type. Kysely is also able to
retain and parse columns and types from selected subqueries, joined subqueries, with statements and
pretty much anything you can think of. Typescript is always there for you to immediately tell what
kind of query you can build and offer completions.
infer colum names and types from selected subqueries, joined subqueries, `with` statements and pretty much
anything you can think of. Typescript is always there for you to tell what kind of query you can build and
offer completions.

@@ -33,3 +34,2 @@ Of course there are cases where things cannot be typed at compile time, and Kysely offers escape

last_name: string
age: number
gender: 'male' | 'female' | 'other'

@@ -58,3 +58,7 @@ }

// You'd create one of these when you start your app.
const db = new Kysely<Database>()
const db = new Kysely<Database>({
dialect: 'postgres',
host: 'localhost',
database: 'kysely_test',
})

@@ -65,3 +69,4 @@ async function demo() {

.innerJoin('pet', 'pet.owner_id', 'person.id')
.select(['person.first_name', 'pet.name as pet_name'])
.select(['first_name', 'pet.name as pet_name'])
.where('person.id', '=', 1)
.execute()

@@ -71,3 +76,2 @@

}
```

@@ -77,3 +81,15 @@

This whole library is still just a proof of concept, and you can't yet start using it for anything
serious, but the concept is pretty much proven! Typescript is amazing!
This whole library is still just a proof of concept and you can't yet start using it for anything
serious. Only a small subset of postgres dialect is implemented.
However, I'd say the concept is pretty much proven! Typescript is amazing! Let me know if this is something
you'd use and I'll continue working on this.
# Why not just contribute to knex
Kysely is very similar to knex, but it also attempts to fix things that I personally find not-so-good
in knex. Bringing the type system and the changes to knex would mean very significantly breaking the
backwards compatibility. That's not possible at this point of the project. Knex was also originally
written for javascript and the typescript typings were added afterwards. That always leads to
compromises in the types. Designing a library for typescript from the ground up produces much
better and simpler types.
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