imodel 0.19.0 → 0.19.2

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/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * imodel v0.19.0
2
+ * imodel v0.19.2
3
3
  * (c) 2019-2026 undefined
4
4
  * @license undefined
5
5
  */
@@ -620,6 +620,7 @@ interface Hook<T extends Hooks[keyof Hooks]> {
620
620
  */
621
621
  declare function toNot(items?: WhereValue[] | null): WhereValue[] | null;
622
622
  type WhereItem = {
623
+ exists?: false | null | undefined;
623
624
  where?: null | undefined;
624
625
  or?: null | undefined;
625
626
  field: string | {
@@ -634,7 +635,16 @@ type WhereItem = {
634
635
  not?: boolean | undefined;
635
636
  operator?: string | null | undefined;
636
637
  };
638
+ type WhereExists = {
639
+ where?: null | undefined;
640
+ or?: null | undefined;
641
+ field?: null | undefined;
642
+ exists: true;
643
+ subquery: SelectItem[];
644
+ not?: boolean | undefined;
645
+ };
637
646
  type WhereRaw = {
647
+ exists?: false | null | undefined;
638
648
  field?: null | undefined;
639
649
  or?: null | undefined;
640
650
  where: readonly string[];
@@ -642,12 +652,13 @@ type WhereRaw = {
642
652
  not?: boolean | undefined;
643
653
  };
644
654
  type WhereOr = {
655
+ exists?: false | null | undefined;
645
656
  where?: null | undefined;
646
657
  field?: null | undefined;
647
658
  or: WhereValue[][];
648
659
  not?: boolean | undefined;
649
660
  };
650
- type WhereValue = WhereItem | WhereRaw | WhereOr;
661
+ type WhereValue = WhereItem | WhereExists | WhereRaw | WhereOr;
651
662
  type WhereLike = {
652
663
  toWhereValue(): WhereValue[][];
653
664
  };
@@ -738,6 +749,58 @@ declare class Where {
738
749
  * @returns {Where}
739
750
  */
740
751
  static and(items: [Wheres] | [TemplateStringsArray, ...any] | [string | string[], any] | [string | string[], string, any, boolean?]): Where;
752
+ /**
753
+ * @overload
754
+ * @param {Wheres} matches
755
+ * @returns {Where}
756
+ */
757
+ static where(matches: Wheres): Where;
758
+ /**
759
+ *
760
+ * @overload
761
+ * @param {TemplateStringsArray} where
762
+ * @param {...any} values
763
+ * @returns {Where}
764
+ */
765
+ static where(where: TemplateStringsArray, ...values: any[]): Where;
766
+ /**
767
+ * @overload
768
+ * @param {string} field
769
+ * @param {any} value
770
+ * @returns {Where}
771
+ */
772
+ static where(field: string, value: any): Where;
773
+ /**
774
+ * @overload
775
+ * @param {string[]} field
776
+ * @param {any[]} value
777
+ * @returns {Where}
778
+ */
779
+ static where(field: string[], value: any[]): Where;
780
+ /**
781
+ * @overload
782
+ * @param {string} field
783
+ * @param {string} operator
784
+ * @param {any} value
785
+ * @param {boolean} [not]
786
+ * @returns {Where}
787
+ */
788
+ static where(field: string, operator: string, value: any, not?: boolean | undefined): Where;
789
+ /**
790
+ * @overload
791
+ * @param {string[]} field
792
+ * @param {string} operator
793
+ * @param {any[]} value
794
+ * @param {boolean} [not]
795
+ * @returns {Where}
796
+ */
797
+ static where(field: string[], operator: string, value: any[], not?: boolean | undefined): Where;
798
+ /**
799
+ * @overload
800
+ * @param {[Wheres] | [TemplateStringsArray, ...any] | [string | string[], any] | [string | string[], string, any, boolean?]} items
801
+ * @returns {Where}
802
+ */
803
+ static where(items: [Wheres] | [TemplateStringsArray, ...any] | [string | string[], any] | [string | string[], string, any, boolean?]): Where;
741
804
  /**
742
805
  * @overload
743
806
  * @param {Wheres} matches
@@ -894,6 +957,18 @@ declare class Where {
894
957
  * @returns {Where}
895
958
  */
896
959
  static orNot(items: [Wheres] | [TemplateStringsArray, ...any] | [string | string[], any] | [string | string[], string, any, boolean?]): Where;
960
+ /**
961
+ *
962
+ * @param {...SelectItem} subquery
963
+ * @returns {Where}
964
+ */
965
+ static exists(...subquery: SelectItem[]): Where;
966
+ /**
967
+ *
968
+ * @param {...SelectItem} subquery
969
+ * @returns {Where}
970
+ */
971
+ static notExists(...subquery: SelectItem[]): Where;
897
972
  toWhereValue(): WhereValue[][];
898
973
  /**
899
974
  * @overload
@@ -1103,6 +1178,18 @@ declare class Where {
1103
1178
  * @returns {this}
1104
1179
  */
1105
1180
  orNot(items: [Wheres] | [TemplateStringsArray, ...any] | [string | string[], any] | [string | string[], string, any, boolean?]): this;
1181
+ /**
1182
+ *
1183
+ * @param {...SelectItem} subquery
1184
+ * @returns {this}
1185
+ */
1186
+ exists(...subquery: SelectItem[]): this;
1187
+ /**
1188
+ *
1189
+ * @param {...SelectItem} subquery
1190
+ * @returns {this}
1191
+ */
1192
+ notExists(...subquery: SelectItem[]): this;
1106
1193
  #private;
1107
1194
  }
1108
1195
 
@@ -1286,6 +1373,7 @@ interface Options {
1286
1373
  update?: Record<string, SetValue>;
1287
1374
  alias?: string;
1288
1375
  group?: string[];
1376
+ lock?: 'S' | 'X' | null;
1289
1377
  }
1290
1378
  interface Queryable<T extends Fields = Fields> extends TableDefine<T> {
1291
1379
  readonly options: Options;
@@ -1310,6 +1398,7 @@ interface JOIN {
1310
1398
  alias?: string;
1311
1399
  condition?: WhereValue[];
1312
1400
  }
1401
+ type LockType = 'S' | 'X';
1313
1402
  interface SelectItem {
1314
1403
  distinct?: boolean;
1315
1404
  select: [string, Select][];
@@ -1326,6 +1415,7 @@ interface SelectItem {
1326
1415
  offset?: number;
1327
1416
  /** 最大返回数 */
1328
1417
  limit?: number;
1418
+ lock?: LockType | null;
1329
1419
  }
1330
1420
  type GetName = (table?: string) => string;
1331
1421
  interface DBColumn {
@@ -1399,6 +1489,17 @@ interface Skip {
1399
1489
  interface TransactionFn {
1400
1490
  <T>(fn: (t: Connection) => PromiseLike<T> | T): Promise<T>;
1401
1491
  }
1492
+ type TransactionHandlerArray = [
1493
+ promise: TransactionHandler['promise'],
1494
+ commit: TransactionHandler['commit'],
1495
+ rollback: TransactionHandler['rollback']
1496
+ ];
1497
+ interface TransactionHandler extends TransactionHandlerArray {
1498
+ promise: Promise<void>;
1499
+ commit(): Promise<void>;
1500
+ rollback(e?: any): Promise<void>;
1501
+ [Symbol.dispose](): void;
1502
+ }
1402
1503
 
1403
1504
  declare const Destroy: unique symbol;
1404
1505
  interface Destroy {
@@ -1904,9 +2005,10 @@ declare class Connection<E extends {} = {}> {
1904
2005
  transaction<T>(fn: (t: Connection) => PromiseLike<T> | T): Promise<T>;
1905
2006
  /**
1906
2007
  * @overload
1907
- * @returns {[Promise<void>, commit: () => Promise<void>, rollback: (e?: any) => Promise<void>]}
2008
+ * @returns {TransactionHandler}
1908
2009
  */
1909
- transaction(): [Promise<void>, commit: () => Promise<void>, rollback: (e?: any) => Promise<void>];
2010
+ transaction(): TransactionHandler;
2011
+ [Symbol.dispose](): void;
1910
2012
  #private;
1911
2013
  }
1912
2014
 
@@ -1927,8 +2029,12 @@ declare function isPseudo(model: Queryable): boolean;
1927
2029
 
1928
2030
  /** @import { SelectItem } from './types' */
1929
2031
  declare class Subquery {
1930
- /** @returns {SelectItem[]} */
1931
- toSubquery(): SelectItem[];
2032
+ /**
2033
+ *
2034
+ * @param {boolean?} [lockable]
2035
+ * @returns {SelectItem[]}
2036
+ */
2037
+ toSubquery(lockable?: boolean | null): SelectItem[];
1932
2038
  }
1933
2039
 
1934
2040
  type QueryOptions<T extends Fields, TB extends unknown = any> = {
@@ -1995,10 +2101,10 @@ declare class Query<T extends Fields, TB extends unknown = any> extends Subquery
1995
2101
  withDeleted(): this;
1996
2102
  /**
1997
2103
  * 增加排序项
1998
- * @param {...string | boolean | [string, boolean?]} sort
2104
+ * @param {...string | null | boolean | [string, boolean?]} sort
1999
2105
  * @returns {this}
2000
2106
  */
2001
- sort(...sort: (string | boolean | [string, boolean?])[]): this;
2107
+ sort(...sort: (string | null | boolean | [string, boolean?])[]): this;
2002
2108
  /**
2003
2109
  * 设置获取到的最大数量
2004
2110
  * @param {number} [limit]
@@ -2132,6 +2238,11 @@ declare class Query<T extends Fields, TB extends unknown = any> extends Subquery
2132
2238
  * @param {boolean} [distinct]
2133
2239
  */
2134
2240
  distinct(distinct?: boolean): this;
2241
+ /**
2242
+ *
2243
+ * @param {LockType?} [lock]
2244
+ */
2245
+ lock(lock?: LockType | null): this;
2135
2246
  /**
2136
2247
  *
2137
2248
  * @param {object} a
@@ -2587,4 +2698,4 @@ declare function toBool(v: any): boolean;
2587
2698
  declare function setDevelopment(d?: boolean): void;
2588
2699
  declare let isDevelopment: boolean;
2589
2700
 
2590
- export { Build, type ClassDecorator, type Column, type ColumnOptions, Connection, type Constraint, Create, type DBColumn, type DBIndex, type DBTable, Destroy, type Environment, type FieldDecorator, type FieldDefine, type FieldDefineOption, type FieldDefineType, type FieldSpecific, type FieldSpecificValue, type FieldType, type FieldTypeDefine, type FieldValue, type Fields, type FindArg, type FindRange, type GetName, type Hook, type Hooks, type IConnection, type Index, type IndexInfo, type IndexOptions, type JOIN, type Join, type JoinType, type MainFieldType, type MaybePromise, type MethodDecorator, Model, type Options, PseudoDestroy, Query, type QueryOptions, type Queryable, Save, Scene, Select, type SelectItem, SetValue, type Skip, Submodel, type Support, type TableConnect, type TableConnection, type TableDefine, type TableType, type TableValue, type ToFieldType, type ToType, type TransactionFn, type VirtualTable, Where, type WhereItem, type WhereLike, type WhereOr, type WhereRaw, type WhereValue, type Wheres, afterCreate, afterCreateMany, afterDelete, afterUpdate, beforeCreate, beforeCreateMany, beforeDelete, beforeUpdate, bindHooks, coefficient, column, creating, decrement, defaultValue, field as define, deleted, deleting, divide, field$1 as field, getPrimaryFields, getPrimaryKeys, hooks, immutable, increment, index, isDevelopment, isPseudo, mergeHooks, model, multiply, now, primary, prop, pseudo, setDevelopment, sort, model as submodel, toBool, toNot, toPrimaries, toPrimary, uncreatable, undeleted, updating, uuid, values, where, withDeleted };
2701
+ export { Build, type ClassDecorator, type Column, type ColumnOptions, Connection, type Constraint, Create, type DBColumn, type DBIndex, type DBTable, Destroy, type Environment, type FieldDecorator, type FieldDefine, type FieldDefineOption, type FieldDefineType, type FieldSpecific, type FieldSpecificValue, type FieldType, type FieldTypeDefine, type FieldValue, type Fields, type FindArg, type FindRange, type GetName, type Hook, type Hooks, type IConnection, type Index, type IndexInfo, type IndexOptions, type JOIN, type Join, type JoinType, type LockType, type MainFieldType, type MaybePromise, type MethodDecorator, Model, type Options, PseudoDestroy, Query, type QueryOptions, type Queryable, Save, Scene, Select, type SelectItem, SetValue, type Skip, Submodel, type Support, type TableConnect, type TableConnection, type TableDefine, type TableType, type TableValue, type ToFieldType, type ToType, type TransactionFn, type TransactionHandler, type TransactionHandlerArray, type VirtualTable, Where, type WhereExists, type WhereItem, type WhereLike, type WhereOr, type WhereRaw, type WhereValue, type Wheres, afterCreate, afterCreateMany, afterDelete, afterUpdate, beforeCreate, beforeCreateMany, beforeDelete, beforeUpdate, bindHooks, coefficient, column, creating, decrement, defaultValue, field as define, deleted, deleting, divide, field$1 as field, getPrimaryFields, getPrimaryKeys, hooks, immutable, increment, index, isDevelopment, isPseudo, mergeHooks, model, multiply, now, primary, prop, pseudo, setDevelopment, sort, model as submodel, toBool, toNot, toPrimaries, toPrimary, uncreatable, undeleted, updating, uuid, values, where, withDeleted };
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * imodel v0.19.0
2
+ * imodel v0.19.2
3
3
  * (c) 2019-2026 undefined
4
4
  * @license undefined
5
5
  */
@@ -15,8 +15,12 @@ function setDevelopment(d) {
15
15
 
16
16
  /** @import { SelectItem } from './types' */
17
17
  class Subquery {
18
- /** @returns {SelectItem[]} */
19
- toSubquery() {
18
+ /**
19
+ *
20
+ * @param {boolean?} [lockable]
21
+ * @returns {SelectItem[]}
22
+ */
23
+ toSubquery(lockable) {
20
24
  throw new Error('toSubquery 方法未在子类中实现');
21
25
  }
22
26
  }
@@ -26,6 +30,7 @@ class Subquery {
26
30
  /** @typedef {WhereLike | Record<string, any> | (WhereLike | Record<string, any>)[]} Wheres */
27
31
  /**
28
32
  * @typedef {object} WhereItem
33
+ * @prop {false?} [exists]
29
34
  * @prop {null} [where]
30
35
  * @prop {null} [or]
31
36
  * @prop {string | {table?: string; field: string} | (string | {table?: string; field: string})[]} field
@@ -34,8 +39,18 @@ class Subquery {
34
39
  * @prop {boolean} [not]
35
40
  * @prop {string?} [operator]
36
41
  */
42
+ /**
43
+ * @typedef {object} WhereExists
44
+ * @prop {null} [where]
45
+ * @prop {null} [or]
46
+ * @prop {null} [field]
47
+ * @prop {true} exists
48
+ * @prop {SelectItem[]} subquery
49
+ * @prop {boolean} [not]
50
+ */
37
51
  /**
38
52
  * @typedef {object} WhereRaw
53
+ * @prop {false?} [exists]
39
54
  * @prop {null} [field]
40
55
  * @prop {null} [or]
41
56
  * @prop {readonly string[]} where
@@ -44,12 +59,13 @@ class Subquery {
44
59
  */
45
60
  /**
46
61
  * @typedef {object} WhereOr
62
+ * @prop {false?} [exists]
47
63
  * @prop {null} [where]
48
64
  * @prop {null} [field]
49
65
  * @prop {WhereValue[][]} or
50
66
  * @prop {boolean} [not]
51
67
  */
52
- /** @typedef {WhereItem | WhereRaw | WhereOr} WhereValue */
68
+ /** @typedef {WhereItem | WhereExists | WhereRaw | WhereOr} WhereValue */
53
69
  /**
54
70
  *
55
71
  * @param {*} v
@@ -317,6 +333,58 @@ class Where {
317
333
  static and(...items) {
318
334
  return new Where().#and(parse(items));
319
335
  }
336
+ /**
337
+ * @overload
338
+ * @param {Wheres} matches
339
+ * @returns {Where}
340
+ */
341
+ /**
342
+ *
343
+ * @overload
344
+ * @param {TemplateStringsArray} where
345
+ * @param {...any} values
346
+ * @returns {Where}
347
+ */
348
+ /**
349
+ * @overload
350
+ * @param {string} field
351
+ * @param {any} value
352
+ * @returns {Where}
353
+ */
354
+ /**
355
+ * @overload
356
+ * @param {string[]} field
357
+ * @param {any[]} value
358
+ * @returns {Where}
359
+ */
360
+ /**
361
+ * @overload
362
+ * @param {string} field
363
+ * @param {string} operator
364
+ * @param {any} value
365
+ * @param {boolean} [not]
366
+ * @returns {Where}
367
+ */
368
+ /**
369
+ * @overload
370
+ * @param {string[]} field
371
+ * @param {string} operator
372
+ * @param {any[]} value
373
+ * @param {boolean} [not]
374
+ * @returns {Where}
375
+ */
376
+ /**
377
+ * @overload
378
+ * @param {[Wheres] | [TemplateStringsArray, ...any] | [string | string[], any] | [string | string[], string, any, boolean?]} items
379
+ * @returns {Where}
380
+ */
381
+ /**
382
+ * @param {[Wheres] | [TemplateStringsArray, ...any] | [string | string[], any] | [string | string[], string, any, boolean?]} items
383
+ * @returns {Where}
384
+ */
385
+ static where(...items) {
386
+ return new Where().#and(parse(items));
387
+ }
320
388
  /**
321
389
  * @overload
322
390
  * @param {Wheres} matches
@@ -629,6 +697,52 @@ class Where {
629
697
  static orNot(...items) {
630
698
  return new Where().#or(toNot(parse(items)));
631
699
  }
700
+ /**
701
+ *
702
+ * @param {...SelectItem} subquery
703
+ * @returns {this}
704
+ */
705
+ exists(...subquery) {
706
+ return this.#and([{
707
+ exists: true,
708
+ subquery
709
+ }]);
710
+ }
711
+ /**
712
+ *
713
+ * @param {...SelectItem} subquery
714
+ * @returns {Where}
715
+ */
716
+ static exists(...subquery) {
717
+ return new Where().#and([{
718
+ exists: true,
719
+ subquery
720
+ }]);
721
+ }
722
+ /**
723
+ *
724
+ * @param {...SelectItem} subquery
725
+ * @returns {this}
726
+ */
727
+ notExists(...subquery) {
728
+ return this.#and([{
729
+ exists: true,
730
+ subquery,
731
+ not: true
732
+ }]);
733
+ }
734
+ /**
735
+ *
736
+ * @param {...SelectItem} subquery
737
+ * @returns {Where}
738
+ */
739
+ static notExists(...subquery) {
740
+ return new Where().#and([{
741
+ exists: true,
742
+ subquery,
743
+ not: true
744
+ }]);
745
+ }
632
746
  }
633
747
 
634
748
  const deleted = Symbol();
@@ -693,28 +807,33 @@ var values = /*#__PURE__*/Object.freeze({
693
807
  /** @import { Options, Queryable } from '../types' */
694
808
  /**
695
809
  *
696
- * @param {Queryable} model
810
+ * @param {Partial<Queryable>} queryable
697
811
  * @returns {Options}
698
812
  */
699
- function getOptions(model) {
813
+ function getOptions({
814
+ fields,
815
+ pseudo,
816
+ options: modelOptions
817
+ }) {
700
818
  const options = {
701
- ...model.options
819
+ where: [],
820
+ ...modelOptions
702
821
  };
703
- if (!model.pseudo) {
822
+ if (!pseudo || !fields) {
704
823
  return options;
705
824
  }
706
- if (!(model.pseudo in model.fields)) {
825
+ if (!(pseudo in fields)) {
707
826
  return options;
708
827
  }
709
828
  if (options.range === undeleted) {
710
829
  options.where = [...options.where, {
711
- field: model.pseudo,
830
+ field: pseudo,
712
831
  operator: '<>',
713
832
  value: 0
714
833
  }];
715
834
  } else if (options.range !== withDeleted) {
716
835
  options.where = [...options.where, {
717
- field: model.pseudo,
836
+ field: pseudo,
718
837
  operator: '=',
719
838
  value: 0
720
839
  }];
@@ -2026,6 +2145,7 @@ function toSelectItem(select, fieldColumns) {
2026
2145
  */
2027
2146
  function select2column(columns, fieldColumns, select) {
2028
2147
  /** @type {[string, Select][]} */
2148
+ // eslint-disable-next-line no-nested-ternary
2029
2149
  const list = Array.isArray(select) ? select.map(v => typeof v === 'string' ? [v, {
2030
2150
  field: v
2031
2151
  }] : v) : select ? Object.entries(select) : [];
@@ -2068,11 +2188,14 @@ function getDefaultSort(columns, noColumn) {
2068
2188
 
2069
2189
  /**
2070
2190
  *
2071
- * @param {[field: string, desc: boolean][]} sort
2072
- * @param {Record<string, string>?} fieldColumns
2191
+ * @param {[field: string, desc: boolean][]?} [sort]
2192
+ * @param {Record<string, string>?} [fieldColumns]
2073
2193
  * @returns {[field: string, desc: boolean][]}
2074
2194
  */
2075
2195
  function sort2column(sort, fieldColumns) {
2196
+ if (!sort) {
2197
+ return [];
2198
+ }
2076
2199
  if (!fieldColumns) {
2077
2200
  return sort;
2078
2201
  }
@@ -2080,7 +2203,7 @@ function sort2column(sort, fieldColumns) {
2080
2203
  }
2081
2204
 
2082
2205
  /** @import Connection from './index.mjs' */
2083
- /** @import { Environment, FieldDefine, Fields, Skip, TableDefine, FieldType, TableConnection, SelectItem } from '../types' */
2206
+ /** @import { Environment, FieldDefine, Fields, Skip, TableDefine, FieldType, TableConnection, SelectItem, LockType } from '../types' */
2084
2207
  /**
2085
2208
  * @param {string[] | boolean | null} [items]
2086
2209
  */
@@ -2138,10 +2261,11 @@ function getSelectFields(select, columns, tableFields, baseFieldSet) {
2138
2261
  * @param {[string, FieldDefine<TableDefine>][]} fields
2139
2262
  * @param {Set<string>} baseParentFieldSet
2140
2263
  * @param {Environment} env
2264
+ * @param {LockType?} [lock]
2141
2265
  * @param {Record<string, string[] | undefined>?} [returnFields]
2142
2266
  * @returns {Promise<any[]>}
2143
2267
  */
2144
- async function findSub(conn, list, fields, baseParentFieldSet, env, returnFields) {
2268
+ async function findSub(conn, list, fields, baseParentFieldSet, env, lock, returnFields) {
2145
2269
  if (!list.length) {
2146
2270
  return list;
2147
2271
  }
@@ -2181,13 +2305,14 @@ async function findSub(conn, list, fields, baseParentFieldSet, env, returnFields
2181
2305
  columns,
2182
2306
  select,
2183
2307
  where,
2184
- sort: getDefaultSort(columns, noColumn) || [],
2308
+ sort: getDefaultSort(columns, noColumn),
2185
2309
  group: [],
2186
- having: []
2310
+ having: [],
2311
+ lock
2187
2312
  }];
2188
2313
  /** @type {PromiseLike<object[]>} */
2189
2314
  const result = table && typeof table === 'object' ? table.select(env, conn, selects) : conn.select(env, selects);
2190
- let promise = result.then(list => findSub(conn, list, tableFields, baseFieldSet, env, fieldMap));
2315
+ let promise = result.then(list => findSub(conn, list, tableFields, baseFieldSet, env, lock, fieldMap));
2191
2316
  promises.push(array ? promise.then(subList => {
2192
2317
  for (const item of list) {
2193
2318
  item[key] = subList.filter(createFilter(item, mapList));
@@ -2222,7 +2347,8 @@ async function search(conn, that, p, env, returnFields, skip) {
2222
2347
  const {
2223
2348
  sort,
2224
2349
  offset,
2225
- limit
2350
+ limit,
2351
+ lock
2226
2352
  } = options;
2227
2353
  const [columns, fieldColumns, tableFields] = toColumns(fields);
2228
2354
  const where = where2column(options.where, fieldColumns);
@@ -2234,7 +2360,7 @@ async function search(conn, that, p, env, returnFields, skip) {
2234
2360
  const baseFieldSet = new Set(Object.keys(fieldColumns || columns));
2235
2361
  const selected = fieldMap && getSelectFields(fieldMap[''] || [], columns, tableFields, baseFieldSet) || null;
2236
2362
  const select = select2column(columns, fieldColumns, selected);
2237
- const sorted = sort?.length ? sort2column(sort, fieldColumns) : getDefaultSort(columns);
2363
+ const sorted = sort2column(sort, fieldColumns);
2238
2364
  /** @type {SelectItem[]} */
2239
2365
  const selects = [{
2240
2366
  table: typeof table === 'string' ? table : '',
@@ -2243,16 +2369,17 @@ async function search(conn, that, p, env, returnFields, skip) {
2243
2369
  where,
2244
2370
  offset,
2245
2371
  limit,
2246
- sort: sorted || [],
2372
+ sort: sorted,
2247
2373
  group: [],
2248
- having: []
2374
+ having: [],
2375
+ lock
2249
2376
  }];
2250
2377
  const list = table && typeof table === 'object' ? await table.select(env, conn, selects) : await conn.select(env, selects);
2251
2378
  if (!list.length) {
2252
2379
  return [];
2253
2380
  }
2254
2381
  if (returnFields) {
2255
- await findSub(conn, list, tableFields, baseFieldSet, env, fieldMap);
2382
+ await findSub(conn, list, tableFields, baseFieldSet, env, lock, fieldMap);
2256
2383
  }
2257
2384
  return list;
2258
2385
  }
@@ -2274,10 +2401,10 @@ async function first(conn, that, p, env, skip) {
2274
2401
  table,
2275
2402
  fields
2276
2403
  } = p;
2277
- // @ts-ignore
2278
2404
  const options = getOptions(p);
2279
2405
  const {
2280
- sort
2406
+ sort,
2407
+ lock
2281
2408
  } = options;
2282
2409
  const [columns, fieldColumns, tableFields] = toColumns(fields);
2283
2410
  const where = where2column(options.where, fieldColumns);
@@ -2292,14 +2419,15 @@ async function first(conn, that, p, env, skip) {
2292
2419
  columns,
2293
2420
  where,
2294
2421
  limit: 1,
2295
- sort: sort?.length ? sort2column(sort, fieldColumns) || [] : getDefaultSort(columns) || [],
2422
+ sort: sort2column(sort, fieldColumns),
2296
2423
  select: select2column(columns, fieldColumns),
2297
2424
  group: [],
2298
- having: []
2425
+ having: [],
2426
+ lock
2299
2427
  }];
2300
2428
  const list = table && typeof table === 'object' ? await table.select(env, conn, selects) : await conn.select(env, selects);
2301
2429
  const baseFieldSet = new Set(Object.keys(fieldColumns || columns));
2302
- const [item] = await findSub(conn, list, tableFields, baseFieldSet, env);
2430
+ const [item] = await findSub(conn, list, tableFields, baseFieldSet, env, lock);
2303
2431
  if (!item) {
2304
2432
  return null;
2305
2433
  }
@@ -2471,9 +2599,10 @@ function table2db(tables) {
2471
2599
  /**
2472
2600
  * @template {Fields} T
2473
2601
  * @param {Queryable<T>} queryable
2602
+ * @param {boolean?} [lockable]
2474
2603
  * @returns {SelectItem[]}
2475
2604
  */
2476
- function toSelect(queryable) {
2605
+ function toSelect(queryable, lockable) {
2477
2606
  const [columns, fieldColumns, tableFields] = toColumns(queryable.fields);
2478
2607
  const {
2479
2608
  table
@@ -2481,7 +2610,8 @@ function toSelect(queryable) {
2481
2610
  const options = getOptions(queryable);
2482
2611
  const {
2483
2612
  offset,
2484
- limit
2613
+ limit,
2614
+ lock
2485
2615
  } = options;
2486
2616
  const where = where2column(options.where, fieldColumns);
2487
2617
  where.push(...getFixedValueWhere(columns));
@@ -2497,10 +2627,11 @@ function toSelect(queryable) {
2497
2627
  limit,
2498
2628
  where,
2499
2629
  select,
2500
- sort: sort?.length ? sort2column(sort, fieldColumns) : getDefaultSort(columns),
2630
+ sort: sort2column(sort, fieldColumns),
2501
2631
  group: options.group || [],
2502
2632
  distinct: Boolean(options.distinct),
2503
- having: []
2633
+ having: [],
2634
+ lock: lockable ? lock : null
2504
2635
  }];
2505
2636
  return result;
2506
2637
  }
@@ -3357,7 +3488,7 @@ class Connection {
3357
3488
  table
3358
3489
  } = queryable;
3359
3490
  const conn = await this.#getTableConnection(queryable.connect);
3360
- const selects = toSelect(queryable);
3491
+ const selects = toSelect(queryable, true);
3361
3492
  const result = table && typeof table === 'object' ? await table.select(this.#env, conn, selects) : await conn.select(this.#env, selects);
3362
3493
  return result;
3363
3494
  }
@@ -3526,6 +3657,9 @@ class Connection {
3526
3657
  }
3527
3658
  return false;
3528
3659
  }
3660
+ [Symbol.dispose]() {
3661
+ this.abort();
3662
+ }
3529
3663
  /**
3530
3664
  * @param {string} table
3531
3665
  * @returns {Promise<DBTable?>}
@@ -3566,12 +3700,19 @@ class Connection {
3566
3700
  */
3567
3701
  /**
3568
3702
  * @overload
3569
- * @returns {[Promise<void>, commit: () => Promise<void>, rollback: (e?: any) => Promise<void>]}
3703
+ * @returns {TransactionHandler}
3570
3704
  */
3571
3705
  /**
3572
3706
  *
3573
- * @param {(t: Connection, signal: AbortSignal) => any} [fn]
3574
- * @returns {any}
3707
+ * @template T
3708
+ * @param {(t: Connection, signal: AbortSignal) => PromiseLike<T> | T} [fn]
3709
+ * @returns {Promise<T> | TransactionHandler}
3710
+ */
3711
+ /**
3712
+ *
3713
+ * @template T
3714
+ * @param {(t: Connection, signal: AbortSignal) => PromiseLike<T> | T} [fn]
3715
+ * @returns {Promise<T> | TransactionHandler}
3575
3716
  */
3576
3717
  transaction(fn) {
3577
3718
  if (typeof fn === 'function') {
@@ -3601,13 +3742,24 @@ class Connection {
3601
3742
  }
3602
3743
  return donePromise;
3603
3744
  }).then(() => {}, () => {});
3604
- return [abortedPromise, async () => {
3745
+ const handler = /** @type {TransactionHandler} */[abortedPromise, () => {
3605
3746
  commit();
3606
3747
  return dbiPromise;
3607
- }, async () => {
3608
- rollback();
3748
+ }, e => {
3749
+ rollback(e);
3609
3750
  return dbiPromise;
3610
3751
  }];
3752
+ handler.promise = abortedPromise;
3753
+ handler.commit = () => {
3754
+ commit();
3755
+ return dbiPromise;
3756
+ };
3757
+ handler.rollback = e => {
3758
+ rollback(e);
3759
+ return dbiPromise;
3760
+ };
3761
+ handler[Symbol.dispose] = commit;
3762
+ return handler;
3611
3763
  }
3612
3764
  }
3613
3765
 
@@ -4868,7 +5020,7 @@ function toBool(v) {
4868
5020
  return !falseValues.has(v.toLowerCase());
4869
5021
  }
4870
5022
 
4871
- /** @import { FieldDefine, Fields, Options, Queryable, Select, TableConnect, VirtualTable } from './types' */
5023
+ /** @import { FieldDefine, Fields, LockType, Options, Queryable, Select, TableConnect, VirtualTable } from './types' */
4872
5024
  /** @import { WhereValue, Wheres } from './Where.mjs' */
4873
5025
  /**
4874
5026
  *
@@ -4971,8 +5123,9 @@ class Query extends Subquery {
4971
5123
  get options() {
4972
5124
  return this.#options;
4973
5125
  }
4974
- toSubquery() {
4975
- return toSelect(this);
5126
+ /** @param {boolean?} [lockable] */
5127
+ toSubquery(lockable) {
5128
+ return toSelect(this, lockable);
4976
5129
  }
4977
5130
  /**
4978
5131
  * @param {QueryOptions<T, TB> | Query<T, TB>} options
@@ -5048,7 +5201,7 @@ class Query extends Subquery {
5048
5201
  }
5049
5202
  /**
5050
5203
  * 增加排序项
5051
- * @param {...string | boolean | [string, boolean?]} sort
5204
+ * @param {...string | null | boolean | [string, boolean?]} sort
5052
5205
  * @returns {this}
5053
5206
  */
5054
5207
  sort(...sort) {
@@ -5065,10 +5218,19 @@ class Query extends Subquery {
5065
5218
  desc = value[1] === true;
5066
5219
  [value] = value;
5067
5220
  }
5068
- if (typeof value !== 'string') {
5221
+ if (typeof value === 'string') {
5222
+ list.push([value, desc]);
5223
+ continue;
5224
+ }
5225
+ if (value !== null) {
5069
5226
  continue;
5070
5227
  }
5071
- list.push([value, desc]);
5228
+ /** @type {[string, boolean, number][]} */
5229
+ const sorted = Object.entries(this.fields).map(([f, d]) => [f, (d.sort || 0) < 0, Math.abs(d.sort || 0)]);
5230
+ const sortFields = sorted.filter(v => v[2]).sort(([,, a], [,, b]) => a - b);
5231
+ for (const [field, desc] of sortFields) {
5232
+ list.push([field, desc]);
5233
+ }
5072
5234
  }
5073
5235
  if (list.length) {
5074
5236
  this.#options.sort = [...(this.#options.sort || []), ...list];
@@ -5389,6 +5551,15 @@ class Query extends Subquery {
5389
5551
  this.#options.distinct = Boolean(distinct);
5390
5552
  return this;
5391
5553
  }
5554
+ /**
5555
+ *
5556
+ * @param {LockType?} [lock]
5557
+ */
5558
+ lock(lock) {
5559
+ const type = typeof lock === 'string' && lock.toUpperCase() || null;
5560
+ this.#options.lock = type === 'S' || type === 'X' ? type : null;
5561
+ return this;
5562
+ }
5392
5563
  }
5393
5564
 
5394
5565
  /** @import { Fields, IndexInfo, FieldDefine } from './types' */
package/migrate.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * imodel v0.19.0
2
+ * imodel v0.19.2
3
3
  * (c) 2019-2026 undefined
4
4
  * @license undefined
5
5
  */
package/migrate.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * imodel v0.19.0
2
+ * imodel v0.19.2
3
3
  * (c) 2019-2026 undefined
4
4
  * @license undefined
5
5
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imodel",
3
- "version": "0.19.0",
3
+ "version": "0.19.2",
4
4
  "main": "index.mjs",
5
5
  "type": "module",
6
6
  "repository": {