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.
@@ -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 | { index: string } | string): typeof 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> | { index: string, type?: INDEX_HINT_TYPE, scope?: INDEX_HINT_SCOPE }, type?: INDEX_HINT_TYPE, scope?: INDEX_HINT_SCOPE): IndexHint;
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
- set index(values: string | Array<string>);
68
-
69
- get index(): Array<string>;
70
-
71
- set type(value: string);
72
-
73
- get type(): string;
74
-
75
- set scope(value: string);
76
-
77
- get scope(): string;
78
-
79
- toSqlString(): string;
80
-
81
- /**
82
- *
83
- * @param {IndexHint} hint
84
- * @returns {boolean}
85
- * @memberof IndexHint
86
- */
87
- isEqual(hint: IndexHint): boolean;
88
-
89
- /**
90
- * @static
91
- * @param {IndexHint} hints
92
- * @returns {Array<IndexHint>}
93
- * @memberof IndexHint
94
- */
95
- static merge(hints: Array<IndexHint>): Array<IndexHint>;
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 => !model.synchronized);
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 condtions
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 charactors that made a powerful querying interface possible.
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
- * cosnt posts = query.offset(page * pageSize).limit(pageSize);
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 everytime these methods were called. For brevity, only the methods start with `$` are documented.
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 caluse
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 => IndexHint.build(hint, INDEX_HINT_TYPE.use)));
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 => IndexHint.build(hint, INDEX_HINT_TYPE.force)));
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 => IndexHint.build(hint, INDEX_HINT_TYPE.ignore)));
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 Spell_aggreator(name = '*') {
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
  }