leoric 2.7.2 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/History.md +28 -0
- package/index.d.ts +20 -808
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/adapters/sequelize.d.ts +190 -0
- package/src/adapters/sequelize.js +21 -17
- package/src/bone.d.ts +53 -0
- package/src/bone.js +2 -2
- package/src/decorators.js.map +1 -1
- package/src/decorators.ts +2 -2
- package/src/drivers/index.d.ts +188 -0
- package/src/expr.js +2 -1
- package/src/{types/hint.d.ts → hint.d.ts} +49 -31
- package/src/hint.js +7 -1
- package/src/realm.js +2 -2
- package/src/spell.d.ts +160 -0
- package/src/spell.js +24 -9
- package/src/types/abstract_bone.d.ts +360 -0
- package/src/types/common.d.ts +115 -2
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
export interface BaseHintInterface {
|
|
2
|
+
index: string;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface HintInterface extends BaseHintInterface {
|
|
6
|
+
type?: INDEX_HINT_TYPE;
|
|
7
|
+
scope?: INDEX_HINT_SCOPE;
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
export class Hint {
|
|
2
|
-
static build(hint: Hint |
|
|
11
|
+
static build(hint: Hint | BaseHintInterface | string): typeof Hint;
|
|
3
12
|
|
|
4
13
|
constructor(text: string);
|
|
5
14
|
|
|
@@ -36,6 +45,11 @@ export enum INDEX_HINT_SCOPE {
|
|
|
36
45
|
groupBy = 'group by',
|
|
37
46
|
}
|
|
38
47
|
|
|
48
|
+
export enum INDEX_HINT_SCOPE_TYPE {
|
|
49
|
+
join = 'join',
|
|
50
|
+
orderBy = 'orderBy',
|
|
51
|
+
groupBy = 'groupBy',
|
|
52
|
+
}
|
|
39
53
|
export class IndexHint {
|
|
40
54
|
/**
|
|
41
55
|
* build index hint
|
|
@@ -53,7 +67,7 @@ export class IndexHint {
|
|
|
53
67
|
* scope: INDEX_HINT_SCOPE.groupBy,
|
|
54
68
|
* })
|
|
55
69
|
*/
|
|
56
|
-
static build(hint: string | Array<string> |
|
|
70
|
+
static build(hint: string | Array<string> | HintInterface, type?: INDEX_HINT_TYPE, scope?: INDEX_HINT_SCOPE): IndexHint;
|
|
57
71
|
|
|
58
72
|
/**
|
|
59
73
|
* Creates an instance of IndexHint.
|
|
@@ -64,33 +78,37 @@ export class IndexHint {
|
|
|
64
78
|
*/
|
|
65
79
|
constructor(index: string, type?: INDEX_HINT_TYPE, scope?: INDEX_HINT_SCOPE);
|
|
66
80
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
81
|
+
set index(values: string | Array<string>);
|
|
82
|
+
|
|
83
|
+
get index(): Array<string>;
|
|
84
|
+
|
|
85
|
+
set type(value: string);
|
|
86
|
+
|
|
87
|
+
get type(): string;
|
|
88
|
+
|
|
89
|
+
set scope(value: string);
|
|
90
|
+
|
|
91
|
+
get scope(): string;
|
|
92
|
+
|
|
93
|
+
toSqlString(): string;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
*
|
|
97
|
+
* @param {IndexHint} hint
|
|
98
|
+
* @returns {boolean}
|
|
99
|
+
* @memberof IndexHint
|
|
100
|
+
*/
|
|
101
|
+
isEqual(hint: IndexHint): boolean;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @static
|
|
105
|
+
* @param {IndexHint} hints
|
|
106
|
+
* @returns {Array<IndexHint>}
|
|
107
|
+
* @memberof IndexHint
|
|
108
|
+
*/
|
|
109
|
+
static merge(hints: Array<IndexHint>): Array<IndexHint>;
|
|
96
110
|
}
|
|
111
|
+
|
|
112
|
+
export type CommonHintsArgs = string | HintInterface | Hint | IndexHint | {
|
|
113
|
+
[key in INDEX_HINT_SCOPE_TYPE]?: string | Array<string>
|
|
114
|
+
};
|
package/src/hint.js
CHANGED
|
@@ -94,7 +94,7 @@ class IndexHint {
|
|
|
94
94
|
|
|
95
95
|
if (isPlainObject(hint)) {
|
|
96
96
|
if (hint.index != null) {
|
|
97
|
-
return new IndexHint(hint.index, hint.type, hint.scope);
|
|
97
|
+
return new IndexHint(hint.index, hint.type || type, hint.scope || scope);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
for (const key in INDEX_HINT_SCOPE) {
|
|
@@ -105,6 +105,8 @@ class IndexHint {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
if (hint instanceof IndexHint) return hint;
|
|
109
|
+
|
|
108
110
|
throw new SyntaxError(format('Unknown index hint %s', hint));
|
|
109
111
|
}
|
|
110
112
|
|
|
@@ -218,4 +220,8 @@ module.exports = {
|
|
|
218
220
|
IndexHint,
|
|
219
221
|
INDEX_HINT_TYPE,
|
|
220
222
|
INDEX_HINT_SCOPE,
|
|
223
|
+
INDEX_HINT_SCOPE_TYPE: Object.keys(INDEX_HINT_SCOPE).reduce((result, entry) => {
|
|
224
|
+
result[entry] = entry;
|
|
225
|
+
return result;
|
|
226
|
+
}, {}),
|
|
221
227
|
};
|
package/src/realm.js
CHANGED
|
@@ -83,7 +83,6 @@ async function loadModels(Spine, models, opts) {
|
|
|
83
83
|
const columns = schemaInfo[model.physicTable] || schemaInfo[model.table];
|
|
84
84
|
if (!model.attributes) initAttributes(model, columns);
|
|
85
85
|
model.load(columns);
|
|
86
|
-
Spine.models[model.name] = model;
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
for (const model of models) {
|
|
@@ -158,8 +157,9 @@ class Realm {
|
|
|
158
157
|
models = Object.values(this.models);
|
|
159
158
|
}
|
|
160
159
|
|
|
160
|
+
for (const model of models) this.Bone.models[model.name] = model;
|
|
161
161
|
// models could be connected already if cached
|
|
162
|
-
models = models.filter(model =>
|
|
162
|
+
models = models.filter(model => model.synchronized == null);
|
|
163
163
|
|
|
164
164
|
if (models.length > 0) {
|
|
165
165
|
await loadModels(this.Bone, models, this.options);
|
package/src/spell.d.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Literal, command, Raw, Connection,
|
|
3
|
+
ResultSet, QueryResult,
|
|
4
|
+
QueryOptions, SetOptions, WithOptions,
|
|
5
|
+
Collection, WhereConditions, OrderOptions,
|
|
6
|
+
} from './types/common';
|
|
7
|
+
import { AbstractBone } from './types/abstract_bone';
|
|
8
|
+
import { Hint, IndexHint, CommonHintsArgs, HintInterface } from './hint';
|
|
9
|
+
|
|
10
|
+
interface SpellBookFormatStandardResult {
|
|
11
|
+
sql?: string;
|
|
12
|
+
values?: Array<Literal> | {
|
|
13
|
+
[key: string]: Literal
|
|
14
|
+
};
|
|
15
|
+
[key: string]: Literal
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Join {
|
|
19
|
+
[key: string]: {
|
|
20
|
+
Model: typeof AbstractBone;
|
|
21
|
+
on: ExprBinaryOperator
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface ExprIdentifier {
|
|
26
|
+
type: 'id';
|
|
27
|
+
value: string;
|
|
28
|
+
qualifiers?: string[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface ExprFunc {
|
|
32
|
+
type: 'func';
|
|
33
|
+
name: string;
|
|
34
|
+
args: (ExprLiteral | ExprIdentifier)[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface ExprLiteral {
|
|
38
|
+
type: 'literal';
|
|
39
|
+
value: Literal;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface ExprBinaryOperator {
|
|
43
|
+
type: 'op';
|
|
44
|
+
name: string;
|
|
45
|
+
args: [ExprIdentifier, ExprLiteral, ExprLiteral];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface ExprTernaryOperator {
|
|
49
|
+
type: 'op';
|
|
50
|
+
name: 'between' | 'not between';
|
|
51
|
+
args: [ExprIdentifier, ExprLiteral, ExprLiteral];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type ExprOperator = ExprBinaryOperator | ExprTernaryOperator;
|
|
55
|
+
type SpellColumn = ExprIdentifier | Raw;
|
|
56
|
+
|
|
57
|
+
interface SpellOptions {
|
|
58
|
+
command?: command;
|
|
59
|
+
columns: SpellColumn[];
|
|
60
|
+
table: ExprIdentifier;
|
|
61
|
+
whereConditions: ExprOperator[];
|
|
62
|
+
groups: (ExprIdentifier | ExprFunc)[];
|
|
63
|
+
orders: (ExprIdentifier | ExprFunc)[];
|
|
64
|
+
havingCondtions: ExprOperator[];
|
|
65
|
+
joins: Join;
|
|
66
|
+
skip: number;
|
|
67
|
+
scopes: Function[];
|
|
68
|
+
subqueryIndex: number;
|
|
69
|
+
rowCount?: number;
|
|
70
|
+
connection?: Connection;
|
|
71
|
+
sets?: { [key: string]: Literal } | { [key: string]: Literal }[];
|
|
72
|
+
hints?: Array<Hint | IndexHint>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface SpellMeta extends SpellOptions {
|
|
76
|
+
Model: typeof AbstractBone;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type SpellBookFormatResult<T> = SpellBookFormatStandardResult | T;
|
|
80
|
+
|
|
81
|
+
export class Spellbook {
|
|
82
|
+
|
|
83
|
+
format(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
84
|
+
|
|
85
|
+
formatInsert(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
86
|
+
formatSelect(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
87
|
+
formatUpdate(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
88
|
+
formatDelete(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
89
|
+
formatUpsert(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export class Spell<T extends typeof AbstractBone, U = InstanceType<T> | Collection<InstanceType<T>> | ResultSet | number | null> extends Promise<U> {
|
|
93
|
+
constructor(Model: T, opts: SpellOptions);
|
|
94
|
+
|
|
95
|
+
command: string;
|
|
96
|
+
scopes: Function[];
|
|
97
|
+
|
|
98
|
+
select(...names: Array<string | Raw> | Array<(name: string) => boolean>): Spell<T, U>;
|
|
99
|
+
insert(opts: SetOptions<T>): Spell<T, QueryResult>;
|
|
100
|
+
update(opts: SetOptions<T>): Spell<T, QueryResult>;
|
|
101
|
+
upsert(opts: SetOptions<T>): Spell<T, QueryResult>;
|
|
102
|
+
delete(): Spell<T, QueryResult>;
|
|
103
|
+
|
|
104
|
+
from(table: string | Spell<T>): Spell<T, U>;
|
|
105
|
+
|
|
106
|
+
with(opts: WithOptions): Spell<T, U>;
|
|
107
|
+
with(...qualifiers: string[]): Spell<T, U>;
|
|
108
|
+
|
|
109
|
+
join<V extends typeof AbstractBone>(Model: V, onConditions: string, ...values: Literal[]): Spell<T, U>;
|
|
110
|
+
join<V extends typeof AbstractBone>(Model: V, onConditions: WhereConditions<T>): Spell<T, U>;
|
|
111
|
+
|
|
112
|
+
$where(conditions: WhereConditions<T>): this;
|
|
113
|
+
$where(conditions: string, ...values: Literal[]): this;
|
|
114
|
+
where(conditions: WhereConditions<T>): Spell<T, U>;
|
|
115
|
+
where(conditions: string, ...values: Literal[]): Spell<T, U>;
|
|
116
|
+
|
|
117
|
+
orWhere(conditions: WhereConditions<T>): Spell<T, U>;
|
|
118
|
+
orWhere(conditions: string, ...values: Literal[]): Spell<T, U>;
|
|
119
|
+
|
|
120
|
+
group(...names: Array<string | Raw>): Spell<T, ResultSet>;
|
|
121
|
+
|
|
122
|
+
having(conditions: string, ...values: Literal[]): Spell<T, ResultSet>;
|
|
123
|
+
having(conditions: WhereConditions<T>): Spell<T, ResultSet>;
|
|
124
|
+
|
|
125
|
+
orHaving(conditions: string, ...values: Literal[]): Spell<T, ResultSet>;
|
|
126
|
+
orHaving(conditions: WhereConditions<T>): Spell<T, ResultSet>;
|
|
127
|
+
|
|
128
|
+
order(name: string, order?: 'desc' | 'asc'): Spell<T, U>;
|
|
129
|
+
order(opts: OrderOptions<T>): Spell<T, U>;
|
|
130
|
+
|
|
131
|
+
offset(skip: number): Spell<T, U>;
|
|
132
|
+
limit(skip: number): Spell<T, U>;
|
|
133
|
+
|
|
134
|
+
count(name?: string): Spell<T, Extract<U, ResultSet | number>>;
|
|
135
|
+
average(name?: string): Spell<T, Extract<U, ResultSet | number>>;
|
|
136
|
+
minimum(name?: string): Spell<T, Extract<U, ResultSet | number>>;
|
|
137
|
+
maximum(name?: string): Spell<T, Extract<U, ResultSet | number>>;
|
|
138
|
+
sum(name?: string): Spell<T, Extract<U, ResultSet | number>>;
|
|
139
|
+
|
|
140
|
+
batch(size?: number): AsyncIterable<T>;
|
|
141
|
+
|
|
142
|
+
increment(name: string, by?: number, options?: QueryOptions): Spell<T, QueryResult>;
|
|
143
|
+
decrement(name: string, by?: number, options?: QueryOptions): Spell<T, QueryResult>;
|
|
144
|
+
|
|
145
|
+
toSqlString(): string;
|
|
146
|
+
toString(): string;
|
|
147
|
+
|
|
148
|
+
all: Spell<T, U>;
|
|
149
|
+
first: Spell<T, InstanceType<T>>;
|
|
150
|
+
last: Spell<T, InstanceType<T>>;
|
|
151
|
+
get(index: number): Spell<T, InstanceType<T>>;
|
|
152
|
+
|
|
153
|
+
unscoped: Spell<T, U>;
|
|
154
|
+
unparanoid: Spell<T, U>;
|
|
155
|
+
|
|
156
|
+
optimizerHints(...hints: Array<string | HintInterface | Hint | IndexHint>): Spell<T, U>;
|
|
157
|
+
useIndex(...hints: Array<CommonHintsArgs>): Spell<T, U>;
|
|
158
|
+
forceIndex(...hints: Array<CommonHintsArgs>): Spell<T, U>;
|
|
159
|
+
ignoreIndex(...hints: Array<CommonHintsArgs>): Spell<T, U>;
|
|
160
|
+
}
|
package/src/spell.js
CHANGED
|
@@ -14,7 +14,7 @@ const Raw = require('./raw');
|
|
|
14
14
|
const { AGGREGATOR_MAP } = require('./constants');
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* check condition to avoid use virtual fields as where
|
|
17
|
+
* check condition to avoid use virtual fields as where conditions
|
|
18
18
|
* @param {Bone} Model
|
|
19
19
|
* @param {Array<Object>} conds
|
|
20
20
|
*/
|
|
@@ -283,7 +283,7 @@ function scopeDeletedAt(spell) {
|
|
|
283
283
|
scopeDeletedAt.__paranoid = true;
|
|
284
284
|
|
|
285
285
|
/**
|
|
286
|
-
* Spell is the query builder of Leoric which has several important
|
|
286
|
+
* Spell is the query builder of Leoric which has several important characters that made a powerful querying interface possible.
|
|
287
287
|
*
|
|
288
288
|
* - Deferred
|
|
289
289
|
* - Method chaining
|
|
@@ -298,10 +298,10 @@ scopeDeletedAt.__paranoid = true;
|
|
|
298
298
|
*
|
|
299
299
|
* const query = Post.find('createdAt > ?', new Date(2012, 4, 15));
|
|
300
300
|
* const [ { count } ] = query.count();
|
|
301
|
-
*
|
|
301
|
+
* const posts = query.offset(page * pageSize).limit(pageSize);
|
|
302
302
|
* this.body = { count, posts }
|
|
303
303
|
*
|
|
304
|
-
* `query.count()` and `query.offset()` won't interfere with each other because `new Spell` gets returned
|
|
304
|
+
* `query.count()` and `query.offset()` won't interfere with each other because `new Spell` gets returned every time these methods were called. For brevity, only the methods start with `$` are documented.
|
|
305
305
|
*
|
|
306
306
|
* For performance reason, {@link Bone} use the prefixed with `$` ones mostly.
|
|
307
307
|
* @alias Spell
|
|
@@ -743,7 +743,7 @@ class Spell {
|
|
|
743
743
|
$having(conditions, ...values) {
|
|
744
744
|
const Model = this.Model;
|
|
745
745
|
for (const condition of parseConditions(Model, conditions, ...values)) {
|
|
746
|
-
// Postgres can't have alias in HAVING
|
|
746
|
+
// Postgres can't have alias in HAVING clause
|
|
747
747
|
// https://stackoverflow.com/questions/32730296/referring-to-a-select-aggregate-column-alias-in-the-having-clause-in-postgres
|
|
748
748
|
if (Model.driver.type === 'postgres' && !(condition instanceof Raw)) {
|
|
749
749
|
const { value } = condition.args[0];
|
|
@@ -844,7 +844,12 @@ class Spell {
|
|
|
844
844
|
* @memberof Spell
|
|
845
845
|
*/
|
|
846
846
|
$useIndex(...hints) {
|
|
847
|
-
this.hints.push(...hints.map(hint =>
|
|
847
|
+
this.hints.push(...hints.map((hint) => {
|
|
848
|
+
if (hint instanceof IndexHint && hint.type !== INDEX_HINT_TYPE.use) {
|
|
849
|
+
console.warn('Do not recommend set non-use index hint in useIndex');
|
|
850
|
+
}
|
|
851
|
+
return IndexHint.build(hint, INDEX_HINT_TYPE.use)
|
|
852
|
+
}));
|
|
848
853
|
return this;
|
|
849
854
|
}
|
|
850
855
|
|
|
@@ -858,7 +863,12 @@ class Spell {
|
|
|
858
863
|
* @memberof Spell
|
|
859
864
|
*/
|
|
860
865
|
$forceIndex(...hints) {
|
|
861
|
-
this.hints.push(...hints.map(hint =>
|
|
866
|
+
this.hints.push(...hints.map((hint) => {
|
|
867
|
+
if (hint instanceof Hint || (hint instanceof IndexHint && hint.type !== INDEX_HINT_TYPE.force)) {
|
|
868
|
+
console.warn('Do not recommend set non-force index hint in forceIndex');
|
|
869
|
+
}
|
|
870
|
+
return IndexHint.build(hint, INDEX_HINT_TYPE.force);
|
|
871
|
+
}));
|
|
862
872
|
return this;
|
|
863
873
|
}
|
|
864
874
|
|
|
@@ -872,7 +882,12 @@ class Spell {
|
|
|
872
882
|
* @memberof Spell
|
|
873
883
|
*/
|
|
874
884
|
$ignoreIndex(...hints) {
|
|
875
|
-
this.hints.push(...hints.map(hint =>
|
|
885
|
+
this.hints.push(...hints.map((hint) => {
|
|
886
|
+
if (hint instanceof IndexHint && hint.type !== INDEX_HINT_TYPE.ignore) {
|
|
887
|
+
console.warn('Do not recommend set non-ignore index hint in ignoreIndex');
|
|
888
|
+
}
|
|
889
|
+
return IndexHint.build(hint, INDEX_HINT_TYPE.ignore)
|
|
890
|
+
}));
|
|
876
891
|
return this;
|
|
877
892
|
}
|
|
878
893
|
|
|
@@ -941,7 +956,7 @@ for (const aggregator in AGGREGATOR_MAP) {
|
|
|
941
956
|
Object.defineProperty(Spell.prototype, `$${aggregator}`, {
|
|
942
957
|
configurable: true,
|
|
943
958
|
writable: true,
|
|
944
|
-
value: function
|
|
959
|
+
value: function Spell_aggregator(name = '*') {
|
|
945
960
|
if (name != '*' && parseExpr(name).type != 'id') {
|
|
946
961
|
throw new Error(`unexpected operand ${name} for ${func.toUpperCase()}()`);
|
|
947
962
|
}
|