@flowerforce/flowerbase 1.7.3-beta.2 → 1.7.3-beta.3
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/dist/services/mongodb-atlas/index.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/index.js +26 -5
- package/dist/services/mongodb-atlas/model.d.ts +4 -1
- package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/services/mongodb-atlas/__tests__/findOneAndUpdate.test.ts +34 -0
- package/src/services/mongodb-atlas/__tests__/realmCompatibility.test.ts +25 -0
- package/src/services/mongodb-atlas/index.ts +30 -8
- package/src/services/mongodb-atlas/model.ts +9 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/mongodb-atlas/index.ts"],"names":[],"mappings":"AAuBA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/mongodb-atlas/index.ts"],"names":[],"mappings":"AAuBA,OAAO,EAGL,oBAAoB,EAErB,MAAM,SAAS,CAAA;AA0tChB,QAAA,MAAM,YAAY,EAAE,oBA6BlB,CAAA;AAEF,eAAe,YAAY,CAAA"}
|
|
@@ -8,15 +8,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
+
var t = {};
|
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
+
t[p] = s[p];
|
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
+
t[p[i]] = s[p[i]];
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
11
22
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
23
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
24
|
};
|
|
14
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
|
|
15
27
|
const get_1 = __importDefault(require("lodash/get"));
|
|
16
28
|
const isEqual_1 = __importDefault(require("lodash/isEqual"));
|
|
17
29
|
const set_1 = __importDefault(require("lodash/set"));
|
|
18
30
|
const unset_1 = __importDefault(require("lodash/unset"));
|
|
19
|
-
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
|
|
20
31
|
const utils_1 = require("../../monitoring/utils");
|
|
21
32
|
const machines_1 = require("../../utils/roles/machines");
|
|
22
33
|
const utils_2 = require("../../utils/roles/machines/utils");
|
|
@@ -92,6 +103,15 @@ const normalizeInsertManyResult = (result) => {
|
|
|
92
103
|
return result;
|
|
93
104
|
return Object.assign(Object.assign({}, result), { insertedIds: Object.values(result.insertedIds) });
|
|
94
105
|
};
|
|
106
|
+
const normalizeFindOneAndUpdateOptions = (options) => {
|
|
107
|
+
if (!options)
|
|
108
|
+
return undefined;
|
|
109
|
+
const { returnNewDocument } = options, rest = __rest(options, ["returnNewDocument"]);
|
|
110
|
+
if (typeof returnNewDocument !== 'boolean' || typeof rest.returnDocument !== 'undefined') {
|
|
111
|
+
return rest;
|
|
112
|
+
}
|
|
113
|
+
return Object.assign(Object.assign({}, rest), { returnDocument: returnNewDocument ? 'after' : 'before' });
|
|
114
|
+
};
|
|
95
115
|
const hasAtomicOperators = (data) => Object.keys(data).some((key) => key.startsWith('$'));
|
|
96
116
|
const normalizeUpdatePayload = (data) => hasAtomicOperators(data) ? data : { $set: data };
|
|
97
117
|
const hasOperatorExpressions = (value) => isPlainObject(value) && Object.keys(value).some((key) => key.startsWith('$'));
|
|
@@ -569,6 +589,7 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
|
|
|
569
589
|
findOneAndUpdate: (query, data, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
570
590
|
var _a;
|
|
571
591
|
try {
|
|
592
|
+
const normalizedOptions = normalizeFindOneAndUpdateOptions(options);
|
|
572
593
|
if (!run_as_system) {
|
|
573
594
|
(0, utils_3.checkDenyOperation)(normalizedRules, collection.collectionName, model_1.CRUD_OPERATIONS.UPDATE);
|
|
574
595
|
const formattedQuery = (0, utils_3.getFormattedQuery)(filters, query, user);
|
|
@@ -605,8 +626,8 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
|
|
|
605
626
|
if (!status || !areDocumentsEqual) {
|
|
606
627
|
throw new Error('Update not permitted');
|
|
607
628
|
}
|
|
608
|
-
const updateResult =
|
|
609
|
-
? yield collection.findOneAndUpdate({ $and: safeQuery }, normalizedData,
|
|
629
|
+
const updateResult = normalizedOptions
|
|
630
|
+
? yield collection.findOneAndUpdate({ $and: safeQuery }, normalizedData, normalizedOptions)
|
|
610
631
|
: yield collection.findOneAndUpdate({ $and: safeQuery }, normalizedData);
|
|
611
632
|
if (!updateResult) {
|
|
612
633
|
emitMongoEvent('findOneAndUpdate');
|
|
@@ -625,8 +646,8 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
|
|
|
625
646
|
emitMongoEvent('findOneAndUpdate');
|
|
626
647
|
return sanitizedDoc;
|
|
627
648
|
}
|
|
628
|
-
const updateResult =
|
|
629
|
-
? yield collection.findOneAndUpdate(query, data,
|
|
649
|
+
const updateResult = normalizedOptions
|
|
650
|
+
? yield collection.findOneAndUpdate(query, data, normalizedOptions)
|
|
630
651
|
: yield collection.findOneAndUpdate(query, data);
|
|
631
652
|
emitMongoEvent('findOneAndUpdate');
|
|
632
653
|
return updateResult;
|
|
@@ -29,11 +29,11 @@ export type GetOperatorsFunction = (collection: Collection<Document>, { rules, c
|
|
|
29
29
|
collName: string;
|
|
30
30
|
monitoringOrigin?: string;
|
|
31
31
|
}) => {
|
|
32
|
+
findOneAndUpdate: (filter: MongoFilter<Document>, update: UpdateFilter<Document> | Document[], options?: RealmCompatibleFindOneAndUpdateOptions) => Promise<Document | null>;
|
|
32
33
|
findOne: (filter?: MongoFilter<Document>, projection?: Document, options?: FindOneOptions) => ReturnType<Method<'findOne'>>;
|
|
33
34
|
deleteOne: (...params: Parameters<Method<'deleteOne'>>) => ReturnType<Method<'deleteOne'>>;
|
|
34
35
|
insertOne: (...params: Parameters<Method<'insertOne'>>) => ReturnType<Method<'insertOne'>>;
|
|
35
36
|
updateOne: (...params: Parameters<Method<'updateOne'>>) => ReturnType<Method<'updateOne'>>;
|
|
36
|
-
findOneAndUpdate: (filter: MongoFilter<Document>, update: UpdateFilter<Document> | Document[], options?: FindOneAndUpdateOptions) => Promise<Document | null>;
|
|
37
37
|
find: (filter?: MongoFilter<Document>, projection?: Document, options?: FindOptions) => FindCursor;
|
|
38
38
|
count: (...params: Parameters<Method<'countDocuments'>>) => ReturnType<Method<'countDocuments'>>;
|
|
39
39
|
countDocuments: (...params: Parameters<Method<'countDocuments'>>) => ReturnType<Method<'countDocuments'>>;
|
|
@@ -43,6 +43,9 @@ export type GetOperatorsFunction = (collection: Collection<Document>, { rules, c
|
|
|
43
43
|
updateMany: (...params: Parameters<Method<'updateMany'>>) => ReturnType<Method<'updateMany'>>;
|
|
44
44
|
deleteMany: (...params: Parameters<Method<'deleteMany'>>) => ReturnType<Method<'deleteMany'>>;
|
|
45
45
|
};
|
|
46
|
+
export type RealmCompatibleFindOneAndUpdateOptions = FindOneAndUpdateOptions & {
|
|
47
|
+
returnNewDocument?: boolean;
|
|
48
|
+
};
|
|
46
49
|
export declare enum CRUD_OPERATIONS {
|
|
47
50
|
CREATE = "CREATE",
|
|
48
51
|
READ = "READ",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/services/mongodb-atlas/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,UAAU,EACV,QAAQ,EACR,UAAU,EACV,uBAAuB,EACvB,cAAc,EACd,WAAW,EACX,MAAM,IAAI,WAAW,EACrB,YAAY,EACZ,MAAM,EACP,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAA;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAA;AAElD,MAAM,MAAM,oBAAoB,GAAG,CACjC,GAAG,EAAE,eAAe,EACpB,EACE,KAAK,EACL,IAAI,EACJ,aAAa,EACb,UAAU,EACX,EAAE;IACD,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,UAAU,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACtC,KACE;IACH,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QACtB,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,CAAC,oBAAoB,CAAC,CAAA;KACnE,CAAA;IACD,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE,oBAAoB,KAAK,aAAa,CAAA;CAChE,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,IAAI;IACxD,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAA;CAC5C,CAAA;AACD,KAAK,MAAM,CAAC,CAAC,SAAS,MAAM,UAAU,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;AAE3E,MAAM,MAAM,oBAAoB,GAAG,CACjC,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,EAChC,EACE,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,aAAa,EACb,gBAAgB,EACjB,EAAE;IACD,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,KACE;IACH,
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/services/mongodb-atlas/model.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -91,4 +91,38 @@ describe('mongodb-atlas findOneAndUpdate', () => {
|
|
|
91
91
|
).rejects.toThrow('Update not permitted')
|
|
92
92
|
expect(findOneAndUpdate).not.toHaveBeenCalled()
|
|
93
93
|
})
|
|
94
|
+
|
|
95
|
+
it('maps returnNewDocument=true to returnDocument=after', async () => {
|
|
96
|
+
const id = new ObjectId()
|
|
97
|
+
const existingDoc = { _id: id, value: 100, userId: 'user-1' }
|
|
98
|
+
const updatedDoc = { _id: id, value: 101, userId: 'user-1' }
|
|
99
|
+
const findOne = jest.fn().mockResolvedValue(existingDoc)
|
|
100
|
+
const findOneAndUpdate = jest.fn().mockResolvedValue(updatedDoc)
|
|
101
|
+
const collection = {
|
|
102
|
+
collectionName: 'todos',
|
|
103
|
+
findOne,
|
|
104
|
+
findOneAndUpdate
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const app = createAppWithCollection(collection)
|
|
108
|
+
const operators = MongoDbAtlas(app as any, {
|
|
109
|
+
rules: createRules(),
|
|
110
|
+
user: { id: 'user-1' }
|
|
111
|
+
})
|
|
112
|
+
.db('db')
|
|
113
|
+
.collection('todos')
|
|
114
|
+
|
|
115
|
+
const result = await operators.findOneAndUpdate(
|
|
116
|
+
{ _id: id },
|
|
117
|
+
{ $inc: { value: 1 } },
|
|
118
|
+
{ returnNewDocument: true } as any
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
expect(result).toEqual(updatedDoc)
|
|
122
|
+
expect(findOneAndUpdate).toHaveBeenCalledWith(
|
|
123
|
+
{ $and: [{ _id: id }] },
|
|
124
|
+
{ $inc: { value: 1 } },
|
|
125
|
+
{ returnDocument: 'after' }
|
|
126
|
+
)
|
|
127
|
+
})
|
|
94
128
|
})
|
|
@@ -153,6 +153,31 @@ describe('mongodb-atlas Realm compatibility', () => {
|
|
|
153
153
|
expect(aggregate).not.toHaveBeenCalled()
|
|
154
154
|
})
|
|
155
155
|
|
|
156
|
+
it('supports Realm returnNewDocument option in findOneAndUpdate', async () => {
|
|
157
|
+
const id = new ObjectId()
|
|
158
|
+
const findOneAndUpdate = jest.fn().mockResolvedValue({ _id: id, value: 101 })
|
|
159
|
+
const collection = {
|
|
160
|
+
collectionName: 'todos',
|
|
161
|
+
findOneAndUpdate
|
|
162
|
+
}
|
|
163
|
+
const operators = MongoDbAtlas(createAppWithCollection(collection) as any, {
|
|
164
|
+
run_as_system: true
|
|
165
|
+
}).db('db').collection('todos')
|
|
166
|
+
|
|
167
|
+
const result = await operators.findOneAndUpdate(
|
|
168
|
+
{ _id: id },
|
|
169
|
+
{ $inc: { value: 1 } } as any,
|
|
170
|
+
{ returnNewDocument: true } as any
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
expect(result).toEqual({ _id: id, value: 101 })
|
|
174
|
+
expect(findOneAndUpdate).toHaveBeenCalledWith(
|
|
175
|
+
{ _id: id },
|
|
176
|
+
{ $inc: { value: 1 } },
|
|
177
|
+
{ returnDocument: 'after' }
|
|
178
|
+
)
|
|
179
|
+
})
|
|
180
|
+
|
|
156
181
|
it('supports operator updates in updateMany without using invalid aggregate stages', async () => {
|
|
157
182
|
const id = new ObjectId()
|
|
158
183
|
const find = jest.fn().mockReturnValue({
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
import cloneDeep from 'lodash/cloneDeep'
|
|
1
2
|
import get from 'lodash/get'
|
|
2
3
|
import isEqual from 'lodash/isEqual'
|
|
3
4
|
import set from 'lodash/set'
|
|
4
5
|
import unset from 'lodash/unset'
|
|
5
|
-
import cloneDeep from 'lodash/cloneDeep'
|
|
6
6
|
import {
|
|
7
7
|
ClientSession,
|
|
8
8
|
ClientSessionOptions,
|
|
9
9
|
Collection,
|
|
10
10
|
Document,
|
|
11
11
|
EventsDescription,
|
|
12
|
+
FindOneAndUpdateOptions,
|
|
12
13
|
FindOneOptions,
|
|
13
14
|
FindOptions,
|
|
14
|
-
FindOneAndUpdateOptions,
|
|
15
15
|
Filter as MongoFilter,
|
|
16
16
|
UpdateFilter,
|
|
17
17
|
WithId
|
|
@@ -21,7 +21,12 @@ import { buildRulesMeta } from '../../monitoring/utils'
|
|
|
21
21
|
import { checkValidation } from '../../utils/roles/machines'
|
|
22
22
|
import { getWinningRole } from '../../utils/roles/machines/utils'
|
|
23
23
|
import { emitServiceEvent } from '../monitoring'
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
CRUD_OPERATIONS,
|
|
26
|
+
GetOperatorsFunction,
|
|
27
|
+
MongodbAtlasFunction,
|
|
28
|
+
RealmCompatibleFindOneAndUpdateOptions
|
|
29
|
+
} from './model'
|
|
25
30
|
import {
|
|
26
31
|
applyAccessControlToPipeline,
|
|
27
32
|
checkDenyOperation,
|
|
@@ -115,6 +120,22 @@ const normalizeInsertManyResult = <T extends { insertedIds?: Record<string, unkn
|
|
|
115
120
|
}
|
|
116
121
|
}
|
|
117
122
|
|
|
123
|
+
const normalizeFindOneAndUpdateOptions = (
|
|
124
|
+
options?: RealmCompatibleFindOneAndUpdateOptions
|
|
125
|
+
): FindOneAndUpdateOptions | undefined => {
|
|
126
|
+
if (!options) return undefined
|
|
127
|
+
|
|
128
|
+
const { returnNewDocument, ...rest } = options
|
|
129
|
+
if (typeof returnNewDocument !== 'boolean' || typeof rest.returnDocument !== 'undefined') {
|
|
130
|
+
return rest
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
...rest,
|
|
135
|
+
returnDocument: returnNewDocument ? 'after' : 'before'
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
118
139
|
const hasAtomicOperators = (data: Document) => Object.keys(data).some((key) => key.startsWith('$'))
|
|
119
140
|
|
|
120
141
|
const normalizeUpdatePayload = (data: Document) =>
|
|
@@ -653,9 +674,10 @@ const getOperators: GetOperatorsFunction = (
|
|
|
653
674
|
findOneAndUpdate: async (
|
|
654
675
|
query: MongoFilter<Document>,
|
|
655
676
|
data: UpdateFilter<Document> | Document[],
|
|
656
|
-
options?:
|
|
677
|
+
options?: RealmCompatibleFindOneAndUpdateOptions
|
|
657
678
|
) => {
|
|
658
679
|
try {
|
|
680
|
+
const normalizedOptions = normalizeFindOneAndUpdateOptions(options)
|
|
659
681
|
if (!run_as_system) {
|
|
660
682
|
checkDenyOperation(normalizedRules, collection.collectionName, CRUD_OPERATIONS.UPDATE)
|
|
661
683
|
const formattedQuery = getFormattedQuery(filters, query, user)
|
|
@@ -702,8 +724,8 @@ const getOperators: GetOperatorsFunction = (
|
|
|
702
724
|
throw new Error('Update not permitted')
|
|
703
725
|
}
|
|
704
726
|
|
|
705
|
-
const updateResult =
|
|
706
|
-
? await collection.findOneAndUpdate({ $and: safeQuery }, normalizedData,
|
|
727
|
+
const updateResult = normalizedOptions
|
|
728
|
+
? await collection.findOneAndUpdate({ $and: safeQuery }, normalizedData, normalizedOptions)
|
|
707
729
|
: await collection.findOneAndUpdate({ $and: safeQuery }, normalizedData)
|
|
708
730
|
if (!updateResult) {
|
|
709
731
|
emitMongoEvent('findOneAndUpdate')
|
|
@@ -729,8 +751,8 @@ const getOperators: GetOperatorsFunction = (
|
|
|
729
751
|
return sanitizedDoc
|
|
730
752
|
}
|
|
731
753
|
|
|
732
|
-
const updateResult =
|
|
733
|
-
? await collection.findOneAndUpdate(query, data,
|
|
754
|
+
const updateResult = normalizedOptions
|
|
755
|
+
? await collection.findOneAndUpdate(query, data, normalizedOptions)
|
|
734
756
|
: await collection.findOneAndUpdate(query, data)
|
|
735
757
|
emitMongoEvent('findOneAndUpdate')
|
|
736
758
|
return updateResult
|
|
@@ -59,6 +59,11 @@ export type GetOperatorsFunction = (
|
|
|
59
59
|
monitoringOrigin?: string
|
|
60
60
|
}
|
|
61
61
|
) => {
|
|
62
|
+
findOneAndUpdate: (
|
|
63
|
+
filter: MongoFilter<Document>,
|
|
64
|
+
update: UpdateFilter<Document> | Document[],
|
|
65
|
+
options?: RealmCompatibleFindOneAndUpdateOptions
|
|
66
|
+
) => Promise<Document | null>
|
|
62
67
|
findOne: (
|
|
63
68
|
filter?: MongoFilter<Document>,
|
|
64
69
|
projection?: Document,
|
|
@@ -71,11 +76,6 @@ export type GetOperatorsFunction = (
|
|
|
71
76
|
updateOne: (
|
|
72
77
|
...params: Parameters<Method<'updateOne'>>
|
|
73
78
|
) => ReturnType<Method<'updateOne'>>
|
|
74
|
-
findOneAndUpdate: (
|
|
75
|
-
filter: MongoFilter<Document>,
|
|
76
|
-
update: UpdateFilter<Document> | Document[],
|
|
77
|
-
options?: FindOneAndUpdateOptions
|
|
78
|
-
) => Promise<Document | null>
|
|
79
79
|
find: (
|
|
80
80
|
filter?: MongoFilter<Document>,
|
|
81
81
|
projection?: Document,
|
|
@@ -102,6 +102,10 @@ export type GetOperatorsFunction = (
|
|
|
102
102
|
) => ReturnType<Method<'deleteMany'>>
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
export type RealmCompatibleFindOneAndUpdateOptions = FindOneAndUpdateOptions & {
|
|
106
|
+
returnNewDocument?: boolean
|
|
107
|
+
}
|
|
108
|
+
|
|
105
109
|
|
|
106
110
|
export enum CRUD_OPERATIONS {
|
|
107
111
|
CREATE = "CREATE",
|