@nocobase/plugin-field-sort 1.5.0-alpha.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.
Files changed (142) hide show
  1. package/LICENSE.txt +159 -0
  2. package/README.md +1 -0
  3. package/client.d.ts +2 -0
  4. package/client.js +1 -0
  5. package/dist/client/index.d.ts +15 -0
  6. package/dist/client/index.js +10 -0
  7. package/dist/client/locale.d.ts +10 -0
  8. package/dist/client/sort-interface.d.ts +131 -0
  9. package/dist/externalVersion.js +18 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/index.js +48 -0
  12. package/dist/locale/en-US.json +1 -0
  13. package/dist/locale/zh-CN.json +1 -0
  14. package/dist/node_modules/@nocobase/lock-manager/LICENSE +661 -0
  15. package/dist/node_modules/@nocobase/lock-manager/lib/index.d.ts +10 -0
  16. package/dist/node_modules/@nocobase/lock-manager/lib/index.js +1 -0
  17. package/dist/node_modules/@nocobase/lock-manager/lib/lock-manager.d.ts +46 -0
  18. package/dist/node_modules/@nocobase/lock-manager/lib/lock-manager.js +171 -0
  19. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/client.js +12 -0
  20. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/assign.d.ts +17 -0
  21. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/assign.js +143 -0
  22. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/client.d.ts +30 -0
  23. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/client.js +88 -0
  24. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/collections-graph.d.ts +24 -0
  25. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/collections-graph.js +107 -0
  26. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/common.d.ts +14 -0
  27. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/common.js +87 -0
  28. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/date.d.ts +38 -0
  29. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/date.js +214 -0
  30. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/dayjs.d.ts +10 -0
  31. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/dayjs.js +72 -0
  32. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/forEach.d.ts +9 -0
  33. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/forEach.js +45 -0
  34. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/fs-exists.d.ts +9 -0
  35. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/fs-exists.js +46 -0
  36. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/getValuesByPath.d.ts +9 -0
  37. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/getValuesByPath.js +71 -0
  38. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/handlebars.d.ts +10 -0
  39. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/handlebars.js +73 -0
  40. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/i18n.d.ts +10 -0
  41. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/i18n.js +43 -0
  42. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/index.d.ts +38 -0
  43. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/index.js +105 -0
  44. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/isPortalInBody.d.ts +13 -0
  45. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/isPortalInBody.js +54 -0
  46. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/isValidFilter.d.ts +9 -0
  47. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/isValidFilter.js +63 -0
  48. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/json-templates.d.ts +9 -0
  49. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/json-templates.js +141 -0
  50. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/koa-multer.d.ts +15 -0
  51. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/koa-multer.js +92 -0
  52. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/log.d.ts +9 -0
  53. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/log.js +39 -0
  54. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/measure-execution-time.d.ts +9 -0
  55. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/measure-execution-time.js +44 -0
  56. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/merge.d.ts +9 -0
  57. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/merge.js +55 -0
  58. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/mixin/AsyncEmitter.d.ts +11 -0
  59. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/mixin/AsyncEmitter.js +80 -0
  60. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/mixin/index.d.ts +9 -0
  61. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/mixin/index.js +48 -0
  62. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/notification.d.ts +9 -0
  63. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/notification.js +43 -0
  64. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/number.d.ts +9 -0
  65. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/number.js +45 -0
  66. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/parse-date.d.ts +15 -0
  67. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/parse-date.js +262 -0
  68. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/parse-filter.d.ts +67 -0
  69. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/parse-filter.js +320 -0
  70. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/parseHTML.d.ts +15 -0
  71. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/parseHTML.js +42 -0
  72. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/perf-hooks.d.ts +14 -0
  73. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/perf-hooks.js +69 -0
  74. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/registry.d.ts +22 -0
  75. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/registry.js +69 -0
  76. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/requireModule.d.ts +12 -0
  77. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/requireModule.js +90 -0
  78. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/server.d.ts +19 -0
  79. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/server.js +50 -0
  80. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/toposort.d.ts +18 -0
  81. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/toposort.js +83 -0
  82. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/uid.d.ts +9 -0
  83. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/uid.js +44 -0
  84. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/url.d.ts +14 -0
  85. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/url.js +46 -0
  86. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/wrap-middleware.d.ts +1 -0
  87. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/lib/wrap-middleware.js +63 -0
  88. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/package.json +20 -0
  89. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/plugin-symlink.d.ts +6 -0
  90. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/plugin-symlink.js +102 -0
  91. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/server.d.ts +2 -0
  92. package/dist/node_modules/@nocobase/lock-manager/node_modules/@nocobase/utils/server.js +12 -0
  93. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/.eslintrc.js +5 -0
  94. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/.github/workflows/ci.yml +24 -0
  95. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/.github/workflows/lint.yml +23 -0
  96. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/bench/bench-multipart-fields-100mb-big.js +149 -0
  97. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/bench/bench-multipart-fields-100mb-small.js +143 -0
  98. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/bench/bench-multipart-files-100mb-big.js +154 -0
  99. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/bench/bench-multipart-files-100mb-small.js +148 -0
  100. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js +101 -0
  101. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js +84 -0
  102. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/lib/index.js +57 -0
  103. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/lib/types/multipart.js +653 -0
  104. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/lib/types/urlencoded.js +350 -0
  105. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/lib/utils.js +596 -0
  106. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/package.json +22 -0
  107. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/test/common.js +109 -0
  108. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/test/test-types-multipart-charsets.js +94 -0
  109. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/test/test-types-multipart-stream-pause.js +102 -0
  110. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/test/test-types-multipart.js +1053 -0
  111. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/test/test-types-urlencoded.js +488 -0
  112. package/dist/node_modules/@nocobase/lock-manager/node_modules/busboy/test/test.js +20 -0
  113. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/index.js +104 -0
  114. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/lib/counter.js +28 -0
  115. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/lib/file-appender.js +67 -0
  116. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/lib/make-middleware.js +173 -0
  117. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/lib/multer-error.js +24 -0
  118. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/lib/remove-uploaded-files.js +28 -0
  119. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/package.json +52 -0
  120. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/storage/disk.js +66 -0
  121. package/dist/node_modules/@nocobase/lock-manager/node_modules/multer/storage/memory.js +21 -0
  122. package/dist/node_modules/@nocobase/lock-manager/node_modules/streamsearch/.eslintrc.js +5 -0
  123. package/dist/node_modules/@nocobase/lock-manager/node_modules/streamsearch/.github/workflows/ci.yml +24 -0
  124. package/dist/node_modules/@nocobase/lock-manager/node_modules/streamsearch/.github/workflows/lint.yml +23 -0
  125. package/dist/node_modules/@nocobase/lock-manager/node_modules/streamsearch/lib/sbmh.js +267 -0
  126. package/dist/node_modules/@nocobase/lock-manager/node_modules/streamsearch/package.json +34 -0
  127. package/dist/node_modules/@nocobase/lock-manager/node_modules/streamsearch/test/test.js +70 -0
  128. package/dist/node_modules/@nocobase/lock-manager/package.json +1 -0
  129. package/dist/node_modules/@nocobase/lock-manager/src/__tests__/lock-manager.test.ts +169 -0
  130. package/dist/node_modules/@nocobase/lock-manager/src/index.ts +11 -0
  131. package/dist/node_modules/@nocobase/lock-manager/src/lock-manager.ts +169 -0
  132. package/dist/server/action.d.ts +26 -0
  133. package/dist/server/action.js +168 -0
  134. package/dist/server/index.d.ts +10 -0
  135. package/dist/server/index.js +48 -0
  136. package/dist/server/plugin.d.ts +19 -0
  137. package/dist/server/plugin.js +69 -0
  138. package/dist/server/sort-field.d.ts +24 -0
  139. package/dist/server/sort-field.js +197 -0
  140. package/package.json +16 -0
  141. package/server.d.ts +2 -0
  142. package/server.js +1 -0
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "streamsearch",
3
+ "version": "1.1.0",
4
+ "author": "Brian White <mscdex@mscdex.net>",
5
+ "description": "Streaming Boyer-Moore-Horspool searching for node.js",
6
+ "main": "./lib/sbmh.js",
7
+ "engines": {
8
+ "node": ">=10.0.0"
9
+ },
10
+ "devDependencies": {
11
+ "@mscdex/eslint-config": "^1.1.0",
12
+ "eslint": "^7.32.0"
13
+ },
14
+ "scripts": {
15
+ "test": "node test/test.js",
16
+ "lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js lib test",
17
+ "lint:fix": "npm run lint -- --fix"
18
+ },
19
+ "keywords": [
20
+ "stream",
21
+ "horspool",
22
+ "boyer-moore-horspool",
23
+ "boyer-moore",
24
+ "search"
25
+ ],
26
+ "licenses": [{
27
+ "type": "MIT",
28
+ "url": "http://github.com/mscdex/streamsearch/raw/master/LICENSE"
29
+ }],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "http://github.com/mscdex/streamsearch.git"
33
+ }
34
+ }
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+
5
+ const StreamSearch = require('../lib/sbmh.js');
6
+
7
+ [
8
+ {
9
+ needle: '\r\n',
10
+ chunks: [
11
+ 'foo',
12
+ ' bar',
13
+ '\r',
14
+ '\n',
15
+ 'baz, hello\r',
16
+ '\n world.',
17
+ '\r\n Node.JS rules!!\r\n\r\n',
18
+ ],
19
+ expect: [
20
+ [false, 'foo'],
21
+ [false, ' bar'],
22
+ [ true, null],
23
+ [false, 'baz, hello'],
24
+ [ true, null],
25
+ [false, ' world.'],
26
+ [ true, null],
27
+ [ true, ' Node.JS rules!!'],
28
+ [ true, ''],
29
+ ],
30
+ },
31
+ {
32
+ needle: '---foobarbaz',
33
+ chunks: [
34
+ '---foobarbaz',
35
+ 'asdf',
36
+ '\r\n',
37
+ '---foobarba',
38
+ '---foobar',
39
+ 'ba',
40
+ '\r\n---foobarbaz--\r\n',
41
+ ],
42
+ expect: [
43
+ [ true, null],
44
+ [false, 'asdf'],
45
+ [false, '\r\n'],
46
+ [false, '---foobarba'],
47
+ [false, '---foobarba'],
48
+ [ true, '\r\n'],
49
+ [false, '--\r\n'],
50
+ ],
51
+ },
52
+ ].forEach((test, i) => {
53
+ console.log(`Running test #${i + 1}`);
54
+ const { needle, chunks, expect } = test;
55
+
56
+ const results = [];
57
+ const ss = new StreamSearch(Buffer.from(needle),
58
+ (isMatch, data, start, end) => {
59
+ if (data)
60
+ data = data.toString('latin1', start, end);
61
+ else
62
+ data = null;
63
+ results.push([isMatch, data]);
64
+ });
65
+
66
+ for (const chunk of chunks)
67
+ ss.push(Buffer.from(chunk));
68
+
69
+ assert.deepStrictEqual(results, expect);
70
+ });
@@ -0,0 +1 @@
1
+ {"name":"@nocobase/lock-manager","version":"1.5.0-alpha.1","main":"lib/index.js","license":"AGPL-3.0","devDependencies":{"@nocobase/utils":"1.4.0-alpha.11","async-mutex":"^0.5.0"},"_lastModified":"2024-11-19T15:52:57.858Z"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { Mutex, tryAcquire } from 'async-mutex';
11
+
12
+ import { LockManager, LockAcquireError } from '../lock-manager';
13
+
14
+ function sleep(ms = 1000) {
15
+ return new Promise((resolve) => {
16
+ setTimeout(resolve, ms);
17
+ });
18
+ }
19
+
20
+ describe('lock manager', () => {
21
+ describe.skip('mutex example', () => {
22
+ it('acquire and release', async () => {
23
+ const order = [];
24
+ const lock = new Mutex();
25
+ const release1 = await lock.acquire();
26
+ order.push(1);
27
+ expect(release1).toBeDefined();
28
+ expect(lock.isLocked()).toBe(true);
29
+ setTimeout(async () => {
30
+ order.push(2);
31
+ await lock.release();
32
+ order.push(3);
33
+ expect(lock.isLocked()).toBe(true);
34
+ }, 200);
35
+ order.push(4);
36
+ const release2 = await lock.acquire();
37
+ order.push(5);
38
+ expect(lock.isLocked()).toBe(true);
39
+ await release2();
40
+ order.push(6);
41
+ expect(lock.isLocked()).toBe(false);
42
+ expect(order).toEqual([1, 4, 2, 3, 5, 6]);
43
+ });
44
+
45
+ it('tryAcquire', async () => {
46
+ const order = [];
47
+ const lock = new Mutex();
48
+ const l1 = tryAcquire(lock);
49
+ expect(l1.isLocked()).toBe(false);
50
+ const release1 = await lock.acquire();
51
+ expect(lock.isLocked()).toBe(true);
52
+ const l2 = tryAcquire(lock);
53
+ await expect(async () => {
54
+ const r2 = await l2.acquire();
55
+ }).rejects.toThrow();
56
+ await release1();
57
+ });
58
+ });
59
+
60
+ describe('local lock', () => {
61
+ const lockManager = new LockManager();
62
+
63
+ it('acquire and release', async () => {
64
+ const order = [];
65
+ const r1 = await lockManager.acquire('test');
66
+ order.push(1);
67
+ setTimeout(async () => {
68
+ order.push(2);
69
+ await r1();
70
+ order.push(3);
71
+ }, 200);
72
+ order.push(4);
73
+ const r2 = await lockManager.acquire('test');
74
+ order.push(5);
75
+ await r2();
76
+ order.push(6);
77
+ expect(order).toEqual([1, 4, 2, 3, 5, 6]);
78
+ });
79
+
80
+ it('acquire and release with timeout', async () => {
81
+ const order = [];
82
+ const r1 = await lockManager.acquire('test', 200);
83
+ order.push(1);
84
+ setTimeout(async () => {
85
+ order.push(2);
86
+ await r1();
87
+ order.push(3);
88
+ }, 400);
89
+ order.push(4);
90
+ const r2 = await lockManager.acquire('test', 200);
91
+ order.push(5);
92
+ await sleep(300);
93
+ await r2();
94
+ order.push(6);
95
+ expect(order).toEqual([1, 4, 5, 2, 3, 6]);
96
+ });
97
+
98
+ it('runExclusive', async () => {
99
+ const order = [];
100
+ setTimeout(async () => {
101
+ await lockManager.runExclusive('test', async () => {
102
+ order.push(1);
103
+ await sleep(100);
104
+ order.push(2);
105
+ });
106
+ }, 100);
107
+ order.push(3);
108
+ await lockManager.runExclusive('test', async () => {
109
+ order.push(4);
110
+ await sleep(400);
111
+ order.push(5);
112
+ });
113
+ order.push(6);
114
+ await sleep(200);
115
+ expect(order).toEqual([3, 4, 5, 1, 6, 2]);
116
+ });
117
+
118
+ it('runExclusive with timeout', async () => {
119
+ const order = [];
120
+ setTimeout(async () => {
121
+ await lockManager.runExclusive(
122
+ 'test',
123
+ async () => {
124
+ order.push(1);
125
+ await sleep(200);
126
+ order.push(2);
127
+ },
128
+ 200,
129
+ );
130
+ }, 100);
131
+ order.push(3);
132
+ await lockManager.runExclusive(
133
+ 'test',
134
+ async () => {
135
+ order.push(4);
136
+ await sleep(400);
137
+ order.push(5);
138
+ },
139
+ 200,
140
+ );
141
+ order.push(6);
142
+ await sleep(200);
143
+ expect(order).toEqual([3, 4, 5, 1, 6, 2]);
144
+ });
145
+
146
+ it('tryAcquire', async () => {
147
+ const release = await lockManager.acquire('test');
148
+ await expect(lockManager.tryAcquire('test')).rejects.toThrowError(LockAcquireError);
149
+ await release();
150
+ const lock = await lockManager.tryAcquire('test');
151
+ expect(lock.acquire).toBeTypeOf('function');
152
+ expect(lock.runExclusive).toBeTypeOf('function');
153
+
154
+ const order = [];
155
+ const r1 = await lock.acquire(200);
156
+ order.push(1);
157
+ setTimeout(async () => {
158
+ order.push(2);
159
+ await r1();
160
+ order.push(3);
161
+ }, 100);
162
+ const r2 = await lock.acquire(200);
163
+ order.push(4);
164
+ await sleep(300);
165
+ await r2();
166
+ expect(order).toEqual([1, 2, 3, 4]);
167
+ });
168
+ });
169
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ export * from './lock-manager';
11
+ export { default } from './lock-manager';
@@ -0,0 +1,169 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { Registry } from '@nocobase/utils';
11
+ import { Mutex, MutexInterface, E_CANCELED } from 'async-mutex';
12
+
13
+ export type Releaser = () => void | Promise<void>;
14
+
15
+ export interface ILock {
16
+ acquire(ttl: number): Releaser | Promise<Releaser>;
17
+ runExclusive<T>(fn: () => Promise<T>, ttl: number): Promise<T>;
18
+ }
19
+
20
+ export interface ILockAdapter {
21
+ connect(): Promise<void>;
22
+ close(): Promise<void>;
23
+ acquire(key: string, ttl: number): Releaser | Promise<Releaser>;
24
+ runExclusive<T>(key: string, fn: () => Promise<T>, ttl: number): Promise<T>;
25
+ tryAcquire(key: string, timeout?: number): Promise<ILock>;
26
+ }
27
+
28
+ export class LockAbortError extends Error {
29
+ constructor(message, options) {
30
+ super(message, options);
31
+ }
32
+ }
33
+
34
+ export class LockAcquireError extends Error {
35
+ constructor(message, options?) {
36
+ super(message, options);
37
+ }
38
+ }
39
+
40
+ class LocalLockAdapter implements ILockAdapter {
41
+ static locks = new Map<string, MutexInterface>();
42
+
43
+ async connect() {}
44
+ async close() {}
45
+
46
+ private getLock(key: string): MutexInterface {
47
+ let lock = (<typeof LocalLockAdapter>this.constructor).locks.get(key);
48
+ if (!lock) {
49
+ lock = new Mutex();
50
+ (<typeof LocalLockAdapter>this.constructor).locks.set(key, lock);
51
+ }
52
+ return lock;
53
+ }
54
+
55
+ async acquire(key: string, ttl: number) {
56
+ const lock = this.getLock(key);
57
+ const release = (await lock.acquire()) as Releaser;
58
+ const timer = setTimeout(() => {
59
+ if (lock.isLocked()) {
60
+ release();
61
+ }
62
+ }, ttl);
63
+ return () => {
64
+ release();
65
+ clearTimeout(timer);
66
+ };
67
+ }
68
+
69
+ async runExclusive<T>(key: string, fn: () => Promise<T>, ttl: number): Promise<T> {
70
+ const lock = this.getLock(key);
71
+ let timer;
72
+ try {
73
+ timer = setTimeout(() => {
74
+ if (lock.isLocked()) {
75
+ lock.release();
76
+ }
77
+ }, ttl);
78
+ return lock.runExclusive(fn);
79
+ } catch (e) {
80
+ if (e === E_CANCELED) {
81
+ throw new LockAbortError('Lock aborted', { cause: E_CANCELED });
82
+ } else {
83
+ throw e;
84
+ }
85
+ } finally {
86
+ clearTimeout(timer);
87
+ }
88
+ }
89
+
90
+ async tryAcquire(key: string) {
91
+ const lock = this.getLock(key);
92
+ if (lock.isLocked()) {
93
+ throw new LockAcquireError('lock is locked');
94
+ }
95
+ return {
96
+ acquire: async (ttl) => {
97
+ return this.acquire(key, ttl);
98
+ },
99
+ runExclusive: async (fn: () => Promise<any>, ttl) => {
100
+ return this.runExclusive(key, fn, ttl);
101
+ },
102
+ };
103
+ }
104
+ }
105
+
106
+ export interface LockAdapterConfig<C extends ILockAdapter = ILockAdapter> {
107
+ Adapter: new (...args: any[]) => C;
108
+ options?: Record<string, any>;
109
+ }
110
+
111
+ export interface LockManagerOptions {
112
+ defaultAdapter?: string;
113
+ }
114
+
115
+ export class LockManager {
116
+ private registry = new Registry<LockAdapterConfig>();
117
+ private adapters = new Map<string, ILockAdapter>();
118
+
119
+ constructor(private options: LockManagerOptions = {}) {
120
+ this.registry.register('local', {
121
+ Adapter: LocalLockAdapter,
122
+ });
123
+ }
124
+
125
+ registerAdapter(name: string, adapterConfig: LockAdapterConfig) {
126
+ this.registry.register(name, adapterConfig);
127
+ }
128
+
129
+ private async getAdapter(): Promise<ILockAdapter> {
130
+ const type = this.options.defaultAdapter || 'local';
131
+ let client = this.adapters.get(type);
132
+ if (!client) {
133
+ const adapter = this.registry.get(type);
134
+ if (!adapter) {
135
+ throw new Error(`Lock adapter "${type}" not registered`);
136
+ }
137
+
138
+ const { Adapter, options } = adapter;
139
+ client = new Adapter(options);
140
+ await client.connect();
141
+ this.adapters.set(type, client);
142
+ }
143
+
144
+ return client;
145
+ }
146
+
147
+ public async close() {
148
+ for (const client of this.adapters.values()) {
149
+ await client.close();
150
+ }
151
+ }
152
+
153
+ public async acquire(key: string, ttl = 500): Promise<Releaser> {
154
+ const client = await this.getAdapter();
155
+ return client.acquire(key, ttl);
156
+ }
157
+
158
+ public async runExclusive<T>(key: string, fn: () => Promise<T>, ttl = 500): Promise<T> {
159
+ const client = await this.getAdapter();
160
+ return client.runExclusive(key, fn, ttl);
161
+ }
162
+
163
+ public async tryAcquire(key: string) {
164
+ const client = await this.getAdapter();
165
+ return client.tryAcquire(key);
166
+ }
167
+ }
168
+
169
+ export default LockManager;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { Collection, TargetKey, Model } from '@nocobase/database';
10
+ import { Context } from '@nocobase/actions';
11
+ import { SortField } from './sort-field';
12
+ export declare function move(ctx: Context, next: any): Promise<any>;
13
+ interface MoveOptions {
14
+ insertAfter?: boolean;
15
+ }
16
+ export declare class SortableCollection {
17
+ collection: Collection;
18
+ field: SortField;
19
+ scopeKey: string;
20
+ constructor(collection: Collection, fieldName?: string);
21
+ move(sourceInstanceId: TargetKey, targetInstanceId: TargetKey, options?: MoveOptions): Promise<void>;
22
+ changeScope(sourceInstanceId: TargetKey, targetScope: any, method?: string): Promise<void>;
23
+ sticky(sourceInstanceId: TargetKey): Promise<void>;
24
+ sameScopeMove(sourceInstance: Model, targetInstance: Model, options: MoveOptions): Promise<void>;
25
+ }
26
+ export {};
@@ -0,0 +1,168 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var action_exports = {};
28
+ __export(action_exports, {
29
+ SortableCollection: () => SortableCollection,
30
+ move: () => move
31
+ });
32
+ module.exports = __toCommonJS(action_exports);
33
+ var import_database = require("@nocobase/database");
34
+ var import_sort_field = require("./sort-field");
35
+ async function move(ctx, next) {
36
+ const repository = ctx.getCurrentRepository();
37
+ if (repository.move) {
38
+ ctx.body = await repository.move(ctx.action.params);
39
+ return next();
40
+ }
41
+ if (!repository.database) {
42
+ return ctx.throw(new Error(`Repository can not handle action move for ${ctx.action.resourceName}`));
43
+ }
44
+ const { sourceId, targetId, targetScope, sticky, method } = ctx.action.params;
45
+ let sortField = ctx.action.params.sortField;
46
+ if (repository instanceof import_database.BelongsToManyRepository) {
47
+ throw new Error("Sorting association as 'belongs-to-many' type is not supported.");
48
+ }
49
+ if (repository instanceof import_database.HasManyRepository && !sortField) {
50
+ sortField = `${repository.association.foreignKey}Sort`;
51
+ }
52
+ const sortableCollection = new SortableCollection(repository.collection, sortField);
53
+ if (sourceId && targetId) {
54
+ await sortableCollection.move(sourceId, targetId, {
55
+ insertAfter: method === "insertAfter"
56
+ });
57
+ }
58
+ if (sourceId && targetScope) {
59
+ await sortableCollection.changeScope(sourceId, targetScope, method);
60
+ }
61
+ if (sourceId && sticky) {
62
+ await sortableCollection.sticky(sourceId);
63
+ }
64
+ ctx.body = "ok";
65
+ await next();
66
+ }
67
+ class SortableCollection {
68
+ collection;
69
+ field;
70
+ scopeKey;
71
+ constructor(collection, fieldName = "sort") {
72
+ this.collection = collection;
73
+ this.field = collection.getField(fieldName);
74
+ if (!(this.field instanceof import_sort_field.SortField)) {
75
+ throw new Error(`${fieldName} is not a sort field`);
76
+ }
77
+ this.scopeKey = this.field.get("scopeKey");
78
+ }
79
+ // insert source position to target position
80
+ async move(sourceInstanceId, targetInstanceId, options = {}) {
81
+ const sourceInstance = await this.collection.repository.findByTargetKey(sourceInstanceId);
82
+ const targetInstance = await this.collection.repository.findByTargetKey(targetInstanceId);
83
+ if (this.scopeKey && sourceInstance.get(this.scopeKey) !== targetInstance.get(this.scopeKey)) {
84
+ await sourceInstance.update({
85
+ [this.scopeKey]: targetInstance.get(this.scopeKey)
86
+ });
87
+ }
88
+ await this.sameScopeMove(sourceInstance, targetInstance, options);
89
+ }
90
+ async changeScope(sourceInstanceId, targetScope, method) {
91
+ const sourceInstance = await this.collection.repository.findByTargetKey(sourceInstanceId);
92
+ const targetScopeValue = targetScope[this.scopeKey];
93
+ if (targetScopeValue && sourceInstance.get(this.scopeKey) !== targetScopeValue) {
94
+ await sourceInstance.update(
95
+ {
96
+ [this.scopeKey]: targetScopeValue
97
+ },
98
+ {
99
+ silent: false
100
+ }
101
+ );
102
+ if (method === "prepend") {
103
+ await this.sticky(sourceInstanceId);
104
+ }
105
+ }
106
+ }
107
+ async sticky(sourceInstanceId) {
108
+ const sourceInstance = await this.collection.repository.findByTargetKey(sourceInstanceId);
109
+ await sourceInstance.update(
110
+ {
111
+ [this.field.get("name")]: 0
112
+ },
113
+ {
114
+ silent: true
115
+ }
116
+ );
117
+ }
118
+ async sameScopeMove(sourceInstance, targetInstance, options) {
119
+ const fieldName = this.field.get("name");
120
+ const sourceSort = sourceInstance.get(fieldName);
121
+ let targetSort = targetInstance.get(fieldName);
122
+ if (options.insertAfter) {
123
+ targetSort = targetSort + 1;
124
+ }
125
+ const scopeValue = this.scopeKey ? sourceInstance.get(this.scopeKey) : null;
126
+ let updateCondition;
127
+ let change;
128
+ if (targetSort > sourceSort) {
129
+ updateCondition = {
130
+ [import_database.Op.gt]: sourceSort,
131
+ [import_database.Op.lte]: targetSort
132
+ };
133
+ change = -1;
134
+ } else {
135
+ updateCondition = {
136
+ [import_database.Op.lt]: sourceSort,
137
+ [import_database.Op.gte]: targetSort
138
+ };
139
+ change = 1;
140
+ }
141
+ const where = {
142
+ [fieldName]: updateCondition
143
+ };
144
+ if (scopeValue) {
145
+ where[this.scopeKey] = {
146
+ [import_database.Op.eq]: scopeValue
147
+ };
148
+ }
149
+ await this.collection.model.increment(fieldName, {
150
+ where,
151
+ by: change,
152
+ silent: true
153
+ });
154
+ await sourceInstance.update(
155
+ {
156
+ [fieldName]: targetSort
157
+ },
158
+ {
159
+ silent: true
160
+ }
161
+ );
162
+ }
163
+ }
164
+ // Annotate the CommonJS export names for ESM import in node:
165
+ 0 && (module.exports = {
166
+ SortableCollection,
167
+ move
168
+ });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ export { default } from './plugin';
10
+ export { move } from './action';