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

fix: type definitions for columns constraint #355

Merged
merged 4 commits into from
Oct 9, 2022
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ test/types/*.js
test/types/*.map
src/decorators.js*
src/data_types.js*

src/raw.js*
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const { heresql } = require('./src/utils/string');
const Hint = require('./src/hint');
const Realm = require('./src/realm');
const Decorators = require('./src/decorators');
const Raw = require('./src/raw');
const Raw = require('./src/raw').default;
const { MysqlDriver, PostgresDriver, SqliteDriver, AbstractDriver } = require('./src/drivers');
const { isBone } = require('./src/utils');

Expand Down
55 changes: 38 additions & 17 deletions src/adapters/sequelize.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
Attributes, Literal, OperatorCondition,
BoneOptions, ResultSet, Raw,
SetOptions, BeforeHooksType, AfterHooksType,
QueryOptions, OrderOptions, QueryResult, Values as CommonValues,
QueryOptions, OrderOptions, QueryResult, Values as CommonValues, BoneColumns, InstanceColumns,
} from '../types/common';
import { AbstractBone } from '../types/abstract_bone';
import { Spell } from '../spell';
Expand All @@ -21,21 +21,21 @@ interface BaseSequelizeConditions<T extends typeof SequelizeBone> extends QueryO
where?: WhereConditions<T>;
order?: OrderOptions<T>;
limit?: number;
attributes?: string | Raw | Array<[keyof Extract<CommonValues<InstanceType<T>>, Literal>] | string | Raw> | [keyof Extract<CommonValues<InstanceType<T>>, Literal>];
attributes?: BoneColumns<T> | Array<BoneColumns<T> | string | Raw> | string | Raw;
offset?: number;
}

type SequelizeUpdateOptions<T extends typeof SequelizeBone> = BaseSequelizeConditions<T> & {
fields?: Array<[keyof Extract<CommonValues<InstanceType<T>>, Literal>] | string | Raw> | [keyof Extract<CommonValues<InstanceType<T>>, Literal>];
fields?: BoneColumns<T> | Array<BoneColumns<T> | string | Raw> | string;
}

interface SequelizeInstanceUpdateOptions<T extends SequelizeBone> extends QueryOptions {
attributes?: string | Raw | Array<[keyof Extract<CommonValues<T>, Literal>] | string | Raw> | [keyof Extract<CommonValues<T>, Literal>];
attributes?: [keyof Extract<CommonValues<T>, Literal>] | string | Raw | Array<[keyof Extract<CommonValues<T>, Literal>] | string | Raw>;
fields?: Array<[keyof Extract<CommonValues<T>, Literal>] | string | Raw> | [keyof Extract<CommonValues<T>, Literal>];
}

interface SequelizeConditions<T extends typeof SequelizeBone> extends BaseSequelizeConditions<T> {
group?: string | string[] | Raw;
group?: BoneColumns<T> | BoneColumns<T>[] | Raw | string;
having?: WhereConditions<T> | string | { [key:string]: Literal | Literal[] } | Raw;
include?: string | Raw;
}
Expand Down Expand Up @@ -82,7 +82,7 @@ export class SequelizeBone extends AbstractBone {

static getTableName(): boolean;

static removeAttribute(name: string): void;
static removeAttribute<T extends typeof SequelizeBone>(this: T, name?: BoneColumns<T>): void;

/**
*
Expand Down Expand Up @@ -122,7 +122,8 @@ export class SequelizeBone extends AbstractBone {
*/
static setScope<T extends typeof SequelizeBone>(this: T, name: (string | ((...args: any[]) => SequelizeConditions<T>) | SequelizeConditions<T> | Array<SequelizeConditions<T>>), ...args: any[]): void;

static aggregate<T extends typeof SequelizeBone>(this: T, name: string, func: aggregators, options?: SequelizeConditions<T>): Spell<T, number>;
static aggregate<T extends typeof SequelizeBone>(this: T, name: BoneColumns<T>, func: aggregators, options?: SequelizeConditions<T>): Spell<T, number>;
static aggregate<T extends typeof SequelizeBone>(this: T, name: Raw | '*', func: aggregators, options?: SequelizeConditions<T>): Spell<T, number>;

static build<T extends typeof SequelizeBone>(this: T, values: Values<T>, options?: BoneOptions): InstanceType<T>;

Expand All @@ -133,24 +134,30 @@ export class SequelizeBone extends AbstractBone {
*/
static bulkBuild<T extends typeof SequelizeBone>(this:T, valueSets: Array<Values<T>>, options?: BoneOptions): Array<InstanceType<T>>;

static count<T extends typeof SequelizeBone>(this: T, name?: string): Spell<T, ResultSet<T> | number>;
static count<T extends typeof SequelizeBone>(this: T, name?: BoneColumns<T>): Spell<T, ResultSet<T> | number>;
static count<T extends typeof SequelizeBone>(this: T, name?: Raw | '*'): Spell<T, ResultSet<T> | number>;
static count<T extends typeof SequelizeBone>(this: T, conditions?: SequelizeConditions<T>): Spell<T, ResultSet<T> | number>;

static decrement<T extends typeof SequelizeBone>(
this: T,
fields: string | Array<string> | { [Property in keyof Extract<InstanceType<T>, Literal>]?: number },
fields: { [Property in keyof Extract<InstanceType<T>, Literal>]?: number } | string | Array<BoneColumns<T> | string> ,
options?: SequelizeConditions<T>
): Spell<T, QueryResult>;

static increment<T extends typeof SequelizeBone>(
this: T,
fields: string | Array<string> | { [Property in keyof Extract<InstanceType<T>, Literal>]?: number },
fields: { [Property in keyof Extract<InstanceType<T>, Literal>]?: number } | string | Array<BoneColumns<T> | string> ,
options?: SequelizeConditions<T>
): Spell<T, QueryResult>;

static max<T extends typeof SequelizeBone>(this: T, filed: string, options?: SequelizeConditions<T>): Promise<Literal>;
static min<T extends typeof SequelizeBone>(this: T, filed: string, options?: SequelizeConditions<T>): Promise<Literal>;
static sum<T extends typeof SequelizeBone>(this: T, filed: string, options?: SequelizeConditions<T>): Promise<Literal>;
static max<T extends typeof SequelizeBone>(this: T, field: BoneColumns<T>, options?: SequelizeConditions<T>): Promise<Literal>;
static max<T extends typeof SequelizeBone>(this: T, field: Raw, options?: SequelizeConditions<T>): Promise<Literal>;

static min<T extends typeof SequelizeBone>(this: T, field: BoneColumns<T>, options?: SequelizeConditions<T>): Promise<Literal>;
static min<T extends typeof SequelizeBone>(this: T, field: Raw, options?: SequelizeConditions<T>): Promise<Literal>;

static sum<T extends typeof SequelizeBone>(this: T, field: BoneColumns<T>, options?: SequelizeConditions<T>): Promise<Literal>;
static sum<T extends typeof SequelizeBone>(this: T, field: Raw, options?: SequelizeConditions<T>): Promise<Literal>;

static destroy<T extends typeof SequelizeBone>(this: T, options?: DestroyOptions<T>): Promise<Array<number> | number>;
static bulkDestroy<T extends typeof SequelizeBone>(this: T, options?: DestroyOptions<T>): Spell<T, number>;
Expand Down Expand Up @@ -184,18 +191,32 @@ export class SequelizeBone extends AbstractBone {
get dataValues(): { [key: string]: Literal };

where(): { [key: string]: number | bigint | string };
set<T, Key extends keyof CommonValues<T>>(this: T, key: Key, value: T[Key]): void;
set<T, Key extends keyof T>(this: T, key: Key, value: T[Key]): void;

get<T, Key extends keyof CommonValues<T>>(this: T, key?: Key): T[Key];
get<T, Key extends keyof T>(this: T, key?: Key): T[Key];

setDataValue<T, Key extends keyof CommonValues<T>>(this: T, key: Key, value: T[Key]): void;
setDataValue<T, Key extends keyof T>(this: T, key: Key, value: T[Key]): void;

getDataValue<T>(this: T): T;
getDataValue<T, Key extends keyof CommonValues<T>>(this: T, key: Key): T[Key];
getDataValue<T, Key extends keyof T>(this: T, key: Key): T[Key];
previous(key?: string): Literal | Literal[] | { [key: string]: Literal | Literal[] };

previous<T, Key extends keyof CommonValues<T>>(this: T, key?: Key): Literal | Literal[] | { [Property in keyof Extract<this, Literal>]?: Literal | Literal[] };
previous<T, Key extends keyof T>(this: T, key?: Key): Literal | Literal[] | { [Property in keyof Extract<this, Literal>]?: Literal | Literal[] };

isSoftDeleted(): boolean;

increment(field: string | string[] | { [Property in keyof Extract<this, Literal>]?: number }, options?: QueryOptions): Spell<typeof SequelizeBone, QueryResult>;
decrement(field: string | string[] | { [Property in keyof Extract<this, Literal>]?: number }, options?: QueryOptions): Spell<typeof SequelizeBone, QueryResult>;
increment(field: InstanceColumns<this> | Array<InstanceColumns<this>> | { [Property in keyof Extract<this, Literal>]?: number }, options?: QueryOptions): Spell<typeof SequelizeBone, QueryResult>;
increment(field: string | Raw | Array<string | Raw>, options?: QueryOptions): Spell<typeof SequelizeBone, QueryResult>;
decrement(field: InstanceColumns<this> | Array<InstanceColumns<this>> | { [Property in keyof Extract<this, Literal>]?: number }, options?: QueryOptions): Spell<typeof SequelizeBone, QueryResult>;
decrement(field: string | Raw | Array<string | Raw> , options?: QueryOptions): Spell<typeof SequelizeBone, QueryResult>;
destroy(options?: SequelizeDestroyOptions): Promise<this| number>;
update<T = this>(this: T, changes?: { [key: string]: Literal } | { [Property in keyof Extract<this, Literal>]?: Literal }, opts?: SequelizeInstanceUpdateOptions<this>): Promise<number>;
update<T = this>(this: T, changes?: { [Property in keyof Extract<this, Literal>]?: Literal }, opts?: SequelizeInstanceUpdateOptions<this>): Promise<number>;
update<T = this>(this: T, changes?: { [key: string]: Literal }, opts?: SequelizeInstanceUpdateOptions<this>): Promise<number>;

}

export const sequelize: (Bone: AbstractBone) => typeof SequelizeBone;
2 changes: 1 addition & 1 deletion src/adapters/sequelize.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const { setupSingleHook } = require('../setup_hooks');
const { compose, isPlainObject } = require('../utils');
const Raw = require('../raw');
const Raw = require('../raw').default;

function translateOptions(spell, options) {
const { attributes, where, group, order, offset, limit, include, having } = options;
Expand Down
9 changes: 5 additions & 4 deletions src/bone.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Spell } from './spell';
import { AbstractBone } from './types/abstract_bone';
import { Collection, Literal, QueryOptions, ResultSet, WhereConditions } from './types/common';
import { BoneColumns, Collection, Literal, QueryOptions, Raw, ResultSet, Values, WhereConditions } from './types/common';

export default class Bone extends AbstractBone {

Expand All @@ -26,7 +26,8 @@ export default class Bone extends AbstractBone {
static findOne<T extends typeof Bone>(this: T, primaryKey: number | number[] | bigint): Spell<T, InstanceType<T> | null>;
static findOne<T extends typeof Bone>(this: T, ): Spell<T, InstanceType<T> | null>;

static sum<T extends typeof Bone>(this: T, name?: string): Spell<T, ResultSet<T> | number>;
static sum<T extends typeof Bone>(this: T, name?: BoneColumns<T>): Spell<T, ResultSet<T> | number>;
static sum<T extends typeof Bone>(this: T, name?: Raw): Spell<T, ResultSet<T> | number>;

/**
* restore rows
Expand All @@ -36,12 +37,12 @@ export default class Bone extends AbstractBone {
* @param conditions query conditions
* @param opts query options
*/
static restore<T extends typeof Bone>(this: T, conditions: Object, opts?: QueryOptions): Spell<T, number>;
static restore<T extends typeof Bone>(this: T, conditions: WhereConditions<T>, opts?: QueryOptions): Spell<T, number>;

/**
* UPDATE rows.
*/
static update<T extends typeof Bone>(this: T, whereConditions: WhereConditions<T>, values?: Object, opts?: QueryOptions): Spell<T, number>;
static update<T extends typeof Bone>(this: T, whereConditions: WhereConditions<T>, values?: Values<InstanceType<T>> & Partial<Record<BoneColumns<T>, Literal>>, opts?: QueryOptions): Spell<T, number>;

/**
* Discard all the applied scopes.
Expand Down
2 changes: 1 addition & 1 deletion src/bone.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ require('reflect-metadata');
const { default: DataTypes } = require('./data_types');
const Collection = require('./collection');
const Spell = require('./spell');
const Raw = require('./raw');
const Raw = require('./raw').default;
const { capitalize, camelCase, snakeCase } = require('./utils/string');
const { hookNames, setupSingleHook } = require('./setup_hooks');
const {
Expand Down
23 changes: 11 additions & 12 deletions src/data_types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
'use strict';

const util = require('util');
import Raw from './raw';
import util from 'util';
const invokableFunc = require('./utils/invokable');
const Raw = require('./raw');

export enum LENGTH_VARIANTS {
tiny = 'tiny',
Expand Down Expand Up @@ -67,7 +65,7 @@ class STRING extends DataType {
return chunks.join(' ');
}

uncast(value: string | typeof Raw | null): string {
uncast(value: string | Raw | null): string | Raw {
if (value == null || value instanceof Raw) return value;
return '' + value;
}
Expand Down Expand Up @@ -306,13 +304,14 @@ class DATE extends DataType {
return this._round(value);
}

uncast(value: null | typeof Raw | string | Date, _strict?: boolean): string | Date {
uncast(value: null | Raw | string | Date | { toDate: () => Date }, _strict?: boolean): string | Date | Raw {
const originValue = value;

if (value == null || value instanceof Raw) return value;
if (typeof value.toDate === 'function') {
value = value.toDate();
}
// type narrowing doesn't handle `return value` correctly
if (value == null) return value as null | undefined;
if (value instanceof Raw) return value;
// Date | Moment
if (typeof value === 'object' && 'toDate' in value) value = value.toDate();

// @deprecated
// vaguely standard date formats such as 2021-10-15 15:50:02,548
Expand All @@ -324,8 +323,8 @@ class DATE extends DataType {

// 1634611135776
// '2021-10-15T08:38:43.877Z'
if (!(value instanceof Date)) value = new Date(value);
if (isNaN(value)) throw new Error(util.format('invalid date: %s', originValue));
if (!(value instanceof Date)) value = new Date((value as string));
if (isNaN((value as any))) throw new Error(util.format('invalid date: %s', originValue));

return this._round(value);
}
Expand Down
2 changes: 1 addition & 1 deletion src/drivers/abstract/spellbook.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const SqlString = require('sqlstring');

const { copyExpr, findExpr, walkExpr } = require('../../expr');
const { formatExpr, formatConditions, collectLiteral, isAggregatorExpr } = require('../../expr_formatter');
const Raw = require('../../raw');
const Raw = require('../../raw').default;

/**
* Create a subquery to make sure OFFSET and LIMIT on left table takes effect.
Expand Down
2 changes: 1 addition & 1 deletion src/drivers/postgres/data_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const { default: DataTypes } = require('../../data_types');
const util = require('util');
const Raw = require('../../raw');
const Raw = require('../../raw').default;


class Postgres_DATE extends DataTypes.DATE {
Expand Down
3 changes: 3 additions & 0 deletions src/expr.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

const Raw = require('./raw').default;

/**
* This module contains a simple SQL expression parser which parses `select_expr` and `expr` in `WHERE`/`HAVING`/`ON` conditions. Most of {@link Spell}'s functionalities are made possible because of this parser. Currently, it cannot parse a full SQL.
* @module
Expand Down Expand Up @@ -133,6 +135,7 @@ function parseValue(value) {
* @returns {Object[]}
*/
function parseExprList(str, ...values) {
if (str instanceof Raw) return [ str ];
let i = 0;
let chr = str[i];
let valueIndex = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/query_object.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const util = require('util');
const { isPlainObject } = require('./utils');
const { parseExpr } = require('./expr');
const Raw = require('./raw');
const Raw = require('./raw').default;
// deferred to break cyclic dependencies
let Spell;

Expand Down
9 changes: 0 additions & 9 deletions src/raw.js

This file was deleted.

21 changes: 21 additions & 0 deletions src/raw.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default class Raw {
value: string;

// consumed in expr_formatter.js
type: string = 'raw';

constructor(value: string) {
if (typeof value !== 'string') {
throw new Error('invalid type of raw value');
}
this.value = value;
}

toString() {
return this.value;
}

static build(value: string) {
return new Raw(value);
}
};
2 changes: 1 addition & 1 deletion src/realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { findDriver, AbstractDriver } = require('./drivers');
const { camelCase } = require('./utils/string');
const { isBone } = require('./utils');
const sequelize = require('./adapters/sequelize');
const Raw = require('./raw');
const Raw = require('./raw').default;
const { LEGACY_TIMESTAMP_MAP } = require('./constants');

const SequelizeBone = sequelize(Bone);
Expand Down
25 changes: 19 additions & 6 deletions src/spell.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
Literal, command, Raw, Connection,
ResultSet, QueryResult,
QueryOptions, SetOptions, WithOptions,
Collection, WhereConditions, OrderOptions,
Collection, WhereConditions, OrderOptions, BoneColumns,
} from './types/common';
import { AbstractBone } from './types/abstract_bone';
import { Hint, IndexHint, CommonHintsArgs, HintInterface } from './hint';
Expand Down Expand Up @@ -134,15 +134,28 @@ export class Spell<T extends typeof AbstractBone, U = InstanceType<T> | Collecti
$limit(rowCount: number): Spell<T, U>;
limit(rowCount: number): Spell<T, U>;

count(name?: string): Spell<T, Extract<U, ResultSet<T> | number>>;
average(name?: string): Spell<T, Extract<U, ResultSet<T> | number>>;
minimum(name?: string): Spell<T, Extract<U, ResultSet<T> | number>>;
maximum(name?: string): Spell<T, Extract<U, ResultSet<T> | number>>;
sum(name?: string): Spell<T, Extract<U, ResultSet<T> | number>>;
// aggregator(name: string) for Model.first/all/last.aggregator(name) because of ts(2526)
count(name?: BoneColumns<T>): Spell<T, Extract<U, ResultSet<T> | number>>;
count(name?: Raw | string): Spell<T, Extract<U, ResultSet<T> | number>>;

average(name?: BoneColumns<T>): Spell<T, Extract<U, ResultSet<T> | number>>;
average(name?: Raw | string): Spell<T, Extract<U, ResultSet<T> | number>>;

minimum(name?: BoneColumns<T>): Spell<T, Extract<U, ResultSet<T> | number>>;
minimum(name?: Raw | string): Spell<T, Extract<U, ResultSet<T> | number>>;

maximum(name?: BoneColumns<T>): Spell<T, Extract<U, ResultSet<T> | number>>;
maximum(name?: Raw | string): Spell<T, Extract<U, ResultSet<T> | number>>;

sum(name?: BoneColumns<T>): Spell<T, Extract<U, ResultSet<T> | number>>;
sum(name?: Raw | string): Spell<T, Extract<U, ResultSet<T> | number>>;

batch(size?: number): AsyncIterable<T>;

increment(name: BoneColumns<T>, by?: number, options?: QueryOptions): Spell<T, QueryResult>;
increment(name: string, by?: number, options?: QueryOptions): Spell<T, QueryResult>;

decrement(name: BoneColumns<T>, by?: number, options?: QueryOptions): Spell<T, QueryResult>;
decrement(name: string, by?: number, options?: QueryOptions): Spell<T, QueryResult>;

toSqlString(): string;
Expand Down
8 changes: 6 additions & 2 deletions src/spell.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { parseExprList, parseExpr, walkExpr } = require('./expr');
const { isPlainObject } = require('./utils');
const { IndexHint, INDEX_HINT_TYPE, Hint } = require('./hint');
const { parseObject } = require('./query_object');
const Raw = require('./raw');
const Raw = require('./raw').default;
const { AGGREGATOR_MAP } = require('./constants');

/**
Expand Down Expand Up @@ -961,7 +961,11 @@ for (const aggregator in AGGREGATOR_MAP) {
configurable: true,
writable: true,
value: function Spell_aggregator(name = '*') {
if (name != '*' && parseExpr(name).type != 'id') {
if (name instanceof Raw) {
this.$select(Raw.build(`${func.toUpperCase()}(${name}) AS ${aggregator}`));
return this
}
if (name !== '*' && parseExpr(name).type !== 'id') {
throw new Error(`unexpected operand ${name} for ${func.toUpperCase()}()`);
}
this.$select(`${func}(${name}) as ${aggregator}`);
Expand Down
Loading