1 | "use strict";
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4 | return new (P || (P = Promise))(function (resolve, reject) {
|
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9 | });
|
10 | };
|
11 | Object.defineProperty(exports, "__esModule", { value: true });
|
12 | exports.Schema = void 0;
|
13 | const CustomError = require("./Error");
|
14 | const utils = require("./utils");
|
15 | const Internal = require("./Internal");
|
16 | const Document_1 = require("./Document");
|
17 | class DynamoDBType {
|
18 | constructor(obj) {
|
19 | Object.keys(obj).forEach((key) => {
|
20 | this[key] = obj[key];
|
21 | });
|
22 | }
|
23 | result(typeSettings) {
|
24 |
|
25 |
|
26 |
|
27 | const type = this.dynamodbType instanceof DynamoDBType ? this.dynamodbType : this;
|
28 | const dynamodbType = (() => {
|
29 | if (this.dynamodbType instanceof DynamoDBType) {
|
30 | return this.dynamodbType.dynamodbType;
|
31 | }
|
32 | else if (typeof this.dynamodbType === "function") {
|
33 | return this.dynamodbType(typeSettings);
|
34 | }
|
35 | else {
|
36 | return this.dynamodbType;
|
37 | }
|
38 | })();
|
39 | const result = {
|
40 | "name": this.name,
|
41 | dynamodbType,
|
42 | "nestedType": this.nestedType,
|
43 | "isOfType": this.jsType.func ? this.jsType.func : (val) => {
|
44 | return [{ "value": this.jsType, "type": "main" }, { "value": this.dynamodbType instanceof DynamoDBType ? type.jsType : null, "type": "underlying" }].filter((a) => Boolean(a.value)).find((jsType) => typeof jsType.value === "string" ? typeof val === jsType.value : val instanceof jsType.value);
|
45 | },
|
46 | "isSet": false,
|
47 | typeSettings
|
48 | };
|
49 | if (this.dynamicName) {
|
50 | result.dynamicName = () => this.dynamicName(typeSettings);
|
51 | }
|
52 | if (this.customType) {
|
53 | const functions = this.customType.functions(typeSettings);
|
54 | result.customType = Object.assign(Object.assign({}, this.customType), { functions });
|
55 | }
|
56 | const isSetAllowed = typeof type.set === "function" ? type.set(typeSettings) : type.set;
|
57 | if (isSetAllowed) {
|
58 | let typeName;
|
59 | if (type.customDynamoName) {
|
60 | typeName = typeof type.customDynamoName === "function" ? type.customDynamoName(typeSettings) : type.customDynamoName;
|
61 | }
|
62 | else {
|
63 | typeName = type.name;
|
64 | }
|
65 | result.set = {
|
66 | "name": `${this.name} Set`,
|
67 | "isSet": true,
|
68 | "dynamodbType": `${dynamodbType}S`,
|
69 | "isOfType": (val, type, settings = {}) => {
|
70 | if (type === "toDynamo") {
|
71 | return !settings.saveUnknown && Array.isArray(val) && val.every((subValue) => result.isOfType(subValue)) || val instanceof Set && [...val].every((subValue) => result.isOfType(subValue));
|
72 | }
|
73 | else {
|
74 | const setVal = val;
|
75 | return setVal.wrapperName === "Set" && setVal.type === typeName && Array.isArray(setVal.values);
|
76 | }
|
77 | },
|
78 | "toDynamo": (val) => ({ "wrapperName": "Set", "type": typeName, "values": [...val] }),
|
79 | "fromDynamo": (val) => new Set(val.values),
|
80 | typeSettings
|
81 | };
|
82 | if (this.dynamicName) {
|
83 | result.set.dynamicName = () => `${this.dynamicName(typeSettings)} Set`;
|
84 | }
|
85 | if (this.customType) {
|
86 | result.set.customType = {
|
87 | "functions": {
|
88 | "toDynamo": (val) => val.map(result.customType.functions.toDynamo),
|
89 | "fromDynamo": (val) => (Object.assign(Object.assign({}, val), { "values": val.values.map(result.customType.functions.fromDynamo) })),
|
90 | "isOfType": (val, type) => {
|
91 | if (type === "toDynamo") {
|
92 | return Array.isArray(val) && val.every((item) => result.customType.functions.isOfType(item, type));
|
93 | }
|
94 | else {
|
95 | const setVal = val;
|
96 | return setVal.wrapperName === "Set" && setVal.type === typeName && Array.isArray(setVal.values);
|
97 | }
|
98 | }
|
99 | }
|
100 | };
|
101 | }
|
102 | }
|
103 | return result;
|
104 | }
|
105 | }
|
106 | const attributeTypesMain = (() => {
|
107 | const numberType = new DynamoDBType({ "name": "Number", "dynamodbType": "N", "set": true, "jsType": "number" });
|
108 | const stringType = new DynamoDBType({ "name": "String", "dynamodbType": "S", "set": true, "jsType": "string" });
|
109 | return [
|
110 | new DynamoDBType({ "name": "Buffer", "dynamodbType": "B", "set": true, "jsType": Buffer, "customDynamoName": "Binary" }),
|
111 | new DynamoDBType({ "name": "Boolean", "dynamodbType": "BOOL", "jsType": "boolean" }),
|
112 | new DynamoDBType({ "name": "Array", "dynamodbType": "L", "jsType": { "func": Array.isArray }, "nestedType": true }),
|
113 | new DynamoDBType({ "name": "Object", "dynamodbType": "M", "jsType": { "func": (val) => Boolean(val) && val.constructor === Object && (val.wrapperName !== "Set" || Object.keys(val).length !== 3 || !val.type || !val.values) }, "nestedType": true }),
|
114 | numberType,
|
115 | stringType,
|
116 | new DynamoDBType({ "name": "Date", "dynamodbType": numberType, "customType": {
|
117 | "functions": (typeSettings) => ({
|
118 | "toDynamo": (val) => {
|
119 | if (typeSettings.storage === "seconds") {
|
120 | return Math.round(val.getTime() / 1000);
|
121 | }
|
122 | else {
|
123 | return val.getTime();
|
124 | }
|
125 | },
|
126 | "fromDynamo": (val) => {
|
127 | if (typeSettings.storage === "seconds") {
|
128 | return new Date(val * 1000);
|
129 | }
|
130 | else {
|
131 | return new Date(val);
|
132 | }
|
133 | },
|
134 | "isOfType": (val, type) => {
|
135 | return type === "toDynamo" ? val instanceof Date : typeof val === "number";
|
136 | }
|
137 | })
|
138 | }, "jsType": Date }),
|
139 | new DynamoDBType({ "name": "Combine", "dynamodbType": stringType, "set": false, "jsType": String }),
|
140 | new DynamoDBType({ "name": "Model", "customDynamoName": (typeSettings) => {
|
141 | const model = typeSettings.model.Model;
|
142 | const hashKey = model.getHashKey();
|
143 | const typeDetails = model.schemas[0].getAttributeTypeDetails(hashKey);
|
144 | return typeDetails.name;
|
145 | }, "dynamicName": (typeSettings) => typeSettings.model.Model.name, "dynamodbType": (typeSettings) => {
|
146 | const model = typeSettings.model.Model;
|
147 | const hashKey = model.getHashKey();
|
148 | const rangeKey = model.getRangeKey();
|
149 | return rangeKey ? "M" : model.schemas[0].getAttributeType(hashKey);
|
150 | }, "set": (typeSettings) => {
|
151 | return !typeSettings.model.Model.getRangeKey();
|
152 | }, "jsType": { "func": (val) => val.prototype instanceof Document_1.Document }, "customType": {
|
153 | "functions": (typeSettings) => ({
|
154 | "toDynamo": (val) => {
|
155 | var _a;
|
156 | const model = typeSettings.model.Model;
|
157 | const hashKey = model.getHashKey();
|
158 | const rangeKey = model.getRangeKey();
|
159 | if (rangeKey) {
|
160 | return {
|
161 | [hashKey]: val[hashKey],
|
162 | [rangeKey]: val[rangeKey]
|
163 | };
|
164 | }
|
165 | else {
|
166 | return (_a = val[hashKey]) !== null && _a !== void 0 ? _a : val;
|
167 | }
|
168 | },
|
169 | "fromDynamo": (val) => val,
|
170 | "isOfType": (val, type) => {
|
171 | var _a;
|
172 | const model = typeSettings.model.Model;
|
173 | const hashKey = model.getHashKey();
|
174 | const rangeKey = model.getRangeKey();
|
175 | if (rangeKey) {
|
176 | return typeof val === "object" && val[hashKey] && val[rangeKey];
|
177 | }
|
178 | else {
|
179 | return utils.dynamoose.getValueTypeCheckResult(model.schemas[0], (_a = val[hashKey]) !== null && _a !== void 0 ? _a : val, hashKey, { type }, {}).isValidType;
|
180 | }
|
181 | }
|
182 | })
|
183 | } })
|
184 | ];
|
185 | })();
|
186 | const attributeTypes = utils.array_flatten(attributeTypesMain.filter((checkType) => !checkType.customType).map((checkType) => checkType.result()).map((a) => [a, a.set])).filter((a) => Boolean(a));
|
187 | class Schema {
|
188 | constructor(object, settings = {}) {
|
189 | if (!object || typeof object !== "object" || Array.isArray(object)) {
|
190 | throw new CustomError.InvalidParameterType("Schema initalization parameter must be an object.");
|
191 | }
|
192 | if (Object.keys(object).length === 0) {
|
193 | throw new CustomError.InvalidParameter("Schema initalization parameter must not be an empty object.");
|
194 | }
|
195 | if (settings.timestamps === true) {
|
196 | settings.timestamps = {
|
197 | "createdAt": "createdAt",
|
198 | "updatedAt": "updatedAt"
|
199 | };
|
200 | }
|
201 | if (settings.timestamps) {
|
202 | const createdAtArray = Array.isArray(settings.timestamps.createdAt) ? settings.timestamps.createdAt : [settings.timestamps.createdAt];
|
203 | const updatedAtArray = Array.isArray(settings.timestamps.updatedAt) ? settings.timestamps.updatedAt : [settings.timestamps.updatedAt];
|
204 | [...createdAtArray, ...updatedAtArray].forEach((prop) => {
|
205 | if (object[prop]) {
|
206 | throw new CustomError.InvalidParameter("Timestamp attributes must not be defined in schema.");
|
207 | }
|
208 | object[prop] = Date;
|
209 | });
|
210 | }
|
211 | let parsedSettings = Object.assign({}, settings);
|
212 | const parsedObject = Object.assign({}, object);
|
213 | utils.object.entries(parsedObject).filter((entry) => entry[1] instanceof Schema).forEach((entry) => {
|
214 | const [key, value] = entry;
|
215 | let newValue = {
|
216 | "type": Object,
|
217 | "schema": value.schemaObject
|
218 | };
|
219 | if (key.endsWith(".schema")) {
|
220 | newValue = value.schemaObject;
|
221 | }
|
222 | const subSettings = Object.assign({}, value.settings);
|
223 | Object.entries(subSettings).forEach((entry) => {
|
224 | const [settingsKey, settingsValue] = entry;
|
225 | switch (settingsKey) {
|
226 | case "saveUnknown":
|
227 | subSettings[settingsKey] = typeof subSettings[settingsKey] === "boolean" ? [`${key}.**`] : settingsValue.map((val) => `${key}.${val}`);
|
228 | break;
|
229 | case "timestamps":
|
230 | subSettings[settingsKey] = Object.entries(subSettings[settingsKey]).reduce((obj, entity) => {
|
231 | const [subKey, subValue] = entity;
|
232 | obj[subKey] = Array.isArray(subValue) ? subValue.map((subValue) => `${key}.${subValue}`) : `${key}.${subValue}`;
|
233 | return obj;
|
234 | }, {});
|
235 | break;
|
236 | }
|
237 | });
|
238 | parsedSettings = utils.merge_objects.main({ "combineMethod": "array_merge_new_arrray" })(parsedSettings, subSettings);
|
239 | utils.object.set(parsedObject, key, newValue);
|
240 | });
|
241 |
|
242 | this.schemaObject = parsedObject;
|
243 | this.settings = parsedSettings;
|
244 | const checkAttributeNameDots = (object /*, existingKey = ""*/) => {
|
245 | Object.keys(object).forEach((key) => {
|
246 | if (key.includes(".")) {
|
247 | throw new CustomError.InvalidParameter("Attributes must not contain dots.");
|
248 | }
|
249 |
|
250 | if (typeof object[key] === "object" && object[key] !== null && object[key].schema) {
|
251 | checkAttributeNameDots(object[key].schema );
|
252 | }
|
253 | });
|
254 | };
|
255 | checkAttributeNameDots(this.schemaObject);
|
256 | const checkMultipleArraySchemaElements = (key) => {
|
257 | let attributeType = [];
|
258 | try {
|
259 | const tmpAttributeType = this.getAttributeType(key);
|
260 | attributeType = Array.isArray(tmpAttributeType) ? tmpAttributeType : [tmpAttributeType];
|
261 | }
|
262 | catch (e) { }
|
263 | if (attributeType.some((type) => type === "L") && (this.getAttributeValue(key).schema || []).length > 1) {
|
264 | throw new CustomError.InvalidParameter("You must only pass one element into schema array.");
|
265 | }
|
266 | };
|
267 | this.attributes().forEach((key) => checkMultipleArraySchemaElements(key));
|
268 | const hashrangeKeys = this.attributes().reduce((val, key) => {
|
269 | const hashKey = this.getAttributeSettingValue("hashKey", key);
|
270 | const rangeKey = this.getAttributeSettingValue("rangeKey", key);
|
271 | const isHashKey = Array.isArray(hashKey) ? hashKey.every((item) => Boolean(item)) : hashKey;
|
272 | const isRangeKey = Array.isArray(rangeKey) ? rangeKey.every((item) => Boolean(item)) : rangeKey;
|
273 | if (isHashKey) {
|
274 | val.hashKeys.push(key);
|
275 | }
|
276 | if (isRangeKey) {
|
277 | val.rangeKeys.push(key);
|
278 | }
|
279 | if (isHashKey && isRangeKey) {
|
280 | val.hashAndRangeKeyAttributes.push(key);
|
281 | }
|
282 | return val;
|
283 | }, { "hashKeys": [], "rangeKeys": [], "hashAndRangeKeyAttributes": [] });
|
284 | const keyTypes = ["hashKey", "rangeKey"];
|
285 | keyTypes.forEach((keyType) => {
|
286 | if (hashrangeKeys[`${keyType}s`].length > 1) {
|
287 | throw new CustomError.InvalidParameter(`Only one ${keyType} allowed per schema.`);
|
288 | }
|
289 | if (hashrangeKeys[`${keyType}s`].find((key) => key.includes("."))) {
|
290 | throw new CustomError.InvalidParameter(`${keyType} must be at root object and not nested in object or array.`);
|
291 | }
|
292 | });
|
293 | if (hashrangeKeys.hashAndRangeKeyAttributes.length > 0) {
|
294 | throw new CustomError.InvalidParameter(`Attribute ${hashrangeKeys.hashAndRangeKeyAttributes[0]} must not be both hashKey and rangeKey`);
|
295 | }
|
296 | this.attributes().forEach((key) => {
|
297 | if (key.includes(".") && this.getAttributeSettingValue("index", key)) {
|
298 | throw new CustomError.InvalidParameter("Index must be at root object and not nested in object or array.");
|
299 | }
|
300 | });
|
301 | }
|
302 | getCreateTableAttributeParams(model) {
|
303 | return __awaiter(this, void 0, void 0, function* () {
|
304 | const hashKey = this.getHashKey();
|
305 | const AttributeDefinitions = [
|
306 | {
|
307 | "AttributeName": hashKey,
|
308 | "AttributeType": this.getSingleAttributeType(hashKey)
|
309 | }
|
310 | ];
|
311 | const AttributeDefinitionsNames = [hashKey];
|
312 | const KeySchema = [
|
313 | {
|
314 | "AttributeName": hashKey,
|
315 | "KeyType": "HASH"
|
316 | }
|
317 | ];
|
318 | const rangeKey = this.getRangeKey();
|
319 | if (rangeKey) {
|
320 | AttributeDefinitions.push({
|
321 | "AttributeName": rangeKey,
|
322 | "AttributeType": this.getSingleAttributeType(rangeKey)
|
323 | });
|
324 | AttributeDefinitionsNames.push(rangeKey);
|
325 | KeySchema.push({
|
326 | "AttributeName": rangeKey,
|
327 | "KeyType": "RANGE"
|
328 | });
|
329 | }
|
330 | utils.array_flatten(yield Promise.all([this.getIndexAttributes(), this.getIndexRangeKeyAttributes()])).map((obj) => obj.attribute).forEach((index) => {
|
331 | if (AttributeDefinitionsNames.includes(index)) {
|
332 | return;
|
333 | }
|
334 | AttributeDefinitionsNames.push(index);
|
335 | AttributeDefinitions.push({
|
336 | "AttributeName": index,
|
337 | "AttributeType": this.getSingleAttributeType(index)
|
338 | });
|
339 | });
|
340 | return Object.assign({ AttributeDefinitions,
|
341 | KeySchema }, yield this.getIndexes(model));
|
342 | });
|
343 | }
|
344 |
|
345 | getSingleAttributeType(key, value, settings) {
|
346 | const attributeType = this.getAttributeType(key, value, settings);
|
347 | if (Array.isArray(attributeType)) {
|
348 | throw new CustomError.InvalidParameter(`You can not have multiple types for attribute definition: ${key}.`);
|
349 | }
|
350 | return attributeType;
|
351 | }
|
352 | getAttributeType(key, value, settings) {
|
353 | try {
|
354 | const typeDetails = this.getAttributeTypeDetails(key);
|
355 | return Array.isArray(typeDetails) ? typeDetails.map((detail) => detail.dynamodbType) : typeDetails.dynamodbType;
|
356 | }
|
357 | catch (e) {
|
358 | if ((settings === null || settings === void 0 ? void 0 : settings.unknownAttributeAllowed) && e.message === `Invalid Attribute: ${key}` && value) {
|
359 | return Object.keys(Document_1.Document.objectToDynamo(value, { "type": "value" }))[0];
|
360 | }
|
361 | else {
|
362 | throw e;
|
363 | }
|
364 | }
|
365 | }
|
366 |
|
367 | defaultCheck(key, value, settings) {
|
368 | return __awaiter(this, void 0, void 0, function* () {
|
369 | const isValueUndefined = typeof value === "undefined" || value === null;
|
370 | if (settings.defaults && isValueUndefined || settings.forceDefault && (yield this.getAttributeSettingValue("forceDefault", key))) {
|
371 | const defaultValue = yield this.getAttributeSettingValue("default", key);
|
372 | const isDefaultValueUndefined = typeof defaultValue === "undefined" || defaultValue === null;
|
373 | if (!isDefaultValueUndefined) {
|
374 | return defaultValue;
|
375 | }
|
376 | }
|
377 | });
|
378 | }
|
379 | getAttributeSettingValue(setting, key, settings = { "returnFunction": false }) {
|
380 | function func(attributeValue) {
|
381 | const defaultPropertyValue = (attributeValue || {})[setting];
|
382 | return typeof defaultPropertyValue === "function" && !settings.returnFunction ? defaultPropertyValue() : defaultPropertyValue;
|
383 | }
|
384 | const attributeValue = this.getAttributeValue(key);
|
385 | if (Array.isArray(attributeValue)) {
|
386 | return attributeValue.map(func);
|
387 | }
|
388 | else {
|
389 | return func(attributeValue);
|
390 | }
|
391 | }
|
392 | getTypePaths(object, settings = { "type": "toDynamo" }) {
|
393 | return Object.entries(object).reduce((result, entry) => {
|
394 | const [key, value] = entry;
|
395 | const fullKey = [settings.previousKey, key].filter((a) => Boolean(a)).join(".");
|
396 | let typeCheckResult;
|
397 | try {
|
398 | typeCheckResult = utils.dynamoose.getValueTypeCheckResult(this, value, fullKey, settings, {});
|
399 | }
|
400 | catch (e) {
|
401 | if (result && settings.includeAllProperties) {
|
402 | result[fullKey] = {
|
403 | "index": 0,
|
404 | "matchCorrectness": 0,
|
405 | "entryCorrectness": [0]
|
406 | };
|
407 | }
|
408 | return result;
|
409 | }
|
410 | const { typeDetails, matchedTypeDetailsIndex, matchedTypeDetailsIndexes } = typeCheckResult;
|
411 | const hasMultipleTypes = Array.isArray(typeDetails);
|
412 | const isObject = typeof value === "object";
|
413 | if (hasMultipleTypes) {
|
414 | if (matchedTypeDetailsIndexes.length > 1 && isObject) {
|
415 | result[fullKey] = matchedTypeDetailsIndexes.map((index) => {
|
416 | const entryCorrectness = utils.object.entries(value).map((entry) => {
|
417 | const [subKey, subValue] = entry;
|
418 | try {
|
419 | const { isValidType } = utils.dynamoose.getValueTypeCheckResult(this, subValue, `${fullKey}.${subKey}`, settings, { "typeIndexOptionMap": { [key]: index } });
|
420 | return isValidType ? 1 : 0;
|
421 | }
|
422 | catch (e) {
|
423 | return 0.5;
|
424 | }
|
425 | });
|
426 | return {
|
427 | index,
|
428 |
|
429 |
|
430 |
|
431 | "matchCorrectness": Math.min(...entryCorrectness),
|
432 | entryCorrectness
|
433 | };
|
434 | }).sort((a, b) => {
|
435 | if (a.matchCorrectness === b.matchCorrectness) {
|
436 | return b.entryCorrectness.reduce((a, b) => a + b, 0) - a.entryCorrectness.reduce((a, b) => a + b, 0);
|
437 | }
|
438 | else {
|
439 | return b.matchCorrectness - a.matchCorrectness;
|
440 | }
|
441 | }).map((a) => a.index)[0];
|
442 | }
|
443 | if (result[fullKey] === undefined) {
|
444 | result[fullKey] = matchedTypeDetailsIndex;
|
445 | }
|
446 | }
|
447 | else if (settings.includeAllProperties) {
|
448 | let matchCorrectness;
|
449 | try {
|
450 | const { isValidType } = utils.dynamoose.getValueTypeCheckResult(this, value, key, settings, {});
|
451 | matchCorrectness = isValidType ? 1 : 0;
|
452 | }
|
453 | catch (e) {
|
454 | matchCorrectness = 0.5;
|
455 | }
|
456 | result[fullKey] = {
|
457 | "index": 0,
|
458 | matchCorrectness,
|
459 | "entryCorrectness": [matchCorrectness]
|
460 | };
|
461 | }
|
462 | if (isObject) {
|
463 | result = Object.assign(Object.assign({}, result), this.getTypePaths(value, Object.assign(Object.assign({}, settings), { "previousKey": fullKey })));
|
464 | }
|
465 | return result;
|
466 | }, {});
|
467 | }
|
468 | }
|
469 | exports.Schema = Schema;
|
470 | Schema.attributeTypes = {
|
471 | "findDynamoDBType": (type) => attributeTypes.find((checkType) => checkType.dynamodbType === type),
|
472 | "findTypeForValue": (...args) => attributeTypes.find((checkType) => checkType.isOfType(...args))
|
473 | };
|
474 |
|
475 | Schema.prototype.getHashKey = function () {
|
476 | return Object.keys(this.schemaObject).find((key) => this.schemaObject[key].hashKey) || Object.keys(this.schemaObject)[0];
|
477 | };
|
478 | Schema.prototype.getRangeKey = function () {
|
479 | return Object.keys(this.schemaObject).find((key) => this.schemaObject[key].rangeKey);
|
480 | };
|
481 |
|
482 | Schema.prototype.requiredCheck = function (key, value) {
|
483 | return __awaiter(this, void 0, void 0, function* () {
|
484 | const isRequired = yield this.getAttributeSettingValue("required", key);
|
485 | if ((typeof value === "undefined" || value === null) && isRequired) {
|
486 | throw new CustomError.ValidationError(`${key} is a required property but has no value when trying to save document`);
|
487 | }
|
488 | });
|
489 | };
|
490 | Schema.prototype.getIndexAttributes = function () {
|
491 | return __awaiter(this, void 0, void 0, function* () {
|
492 | return (yield Promise.all(this.attributes().map((attribute) => __awaiter(this, void 0, void 0, function* () { return ({ "index": yield this.getAttributeSettingValue("index", attribute), attribute }); })))).filter((obj) => obj.index);
|
493 | });
|
494 | };
|
495 | Schema.prototype.getIndexRangeKeyAttributes = function () {
|
496 | return __awaiter(this, void 0, void 0, function* () {
|
497 | const indexes = yield this.getIndexAttributes();
|
498 | return indexes.map((index) => index.index.rangeKey).filter((a) => Boolean(a)).map((a) => ({ "attribute": a }));
|
499 | });
|
500 | };
|
501 | Schema.prototype.getIndexes = function (model) {
|
502 | return __awaiter(this, void 0, void 0, function* () {
|
503 | return (yield this.getIndexAttributes()).reduce((accumulator, currentValue) => {
|
504 | const indexValue = currentValue.index;
|
505 | const attributeValue = currentValue.attribute;
|
506 | const dynamoIndexObject = {
|
507 | "IndexName": indexValue.name || `${attributeValue}${indexValue.global ? "GlobalIndex" : "LocalIndex"}`,
|
508 | "KeySchema": [],
|
509 | "Projection": { "ProjectionType": "KEYS_ONLY" }
|
510 | };
|
511 | if (indexValue.project || typeof indexValue.project === "undefined" || indexValue.project === null) {
|
512 | dynamoIndexObject.Projection = Array.isArray(indexValue.project) ? { "ProjectionType": "INCLUDE", "NonKeyAttributes": indexValue.project } : { "ProjectionType": "ALL" };
|
513 | }
|
514 | if (indexValue.global) {
|
515 | dynamoIndexObject.KeySchema.push({ "AttributeName": attributeValue, "KeyType": "HASH" });
|
516 | if (indexValue.rangeKey) {
|
517 | dynamoIndexObject.KeySchema.push({ "AttributeName": indexValue.rangeKey, "KeyType": "RANGE" });
|
518 | }
|
519 | const throughputObject = utils.dynamoose.get_provisioned_throughput(indexValue.throughput ? indexValue : model.options.throughput === "ON_DEMAND" ? {} : model.options);
|
520 |
|
521 | if (throughputObject.ProvisionedThroughput) {
|
522 | dynamoIndexObject.ProvisionedThroughput = throughputObject.ProvisionedThroughput;
|
523 | }
|
524 | }
|
525 | else {
|
526 | dynamoIndexObject.KeySchema.push({ "AttributeName": this.getHashKey(), "KeyType": "HASH" });
|
527 | dynamoIndexObject.KeySchema.push({ "AttributeName": attributeValue, "KeyType": "RANGE" });
|
528 | }
|
529 | const accumulatorKey = indexValue.global ? "GlobalSecondaryIndexes" : "LocalSecondaryIndexes";
|
530 | if (!accumulator[accumulatorKey]) {
|
531 | accumulator[accumulatorKey] = [];
|
532 | }
|
533 | accumulator[accumulatorKey].push(dynamoIndexObject);
|
534 | return accumulator;
|
535 | }, {});
|
536 | });
|
537 | };
|
538 | Schema.prototype.getSettingValue = function (setting) {
|
539 | return this.settings[setting];
|
540 | };
|
541 | function attributesAction(object) {
|
542 | const typePaths = object && this.getTypePaths(object);
|
543 | const main = (object, existingKey = "") => {
|
544 | return Object.keys(object).reduce((accumulator, key) => {
|
545 | const keyWithExisting = `${existingKey ? `${existingKey}.` : ""}${key}`;
|
546 | accumulator.push(keyWithExisting);
|
547 | let attributeType;
|
548 | try {
|
549 | const tmpAttributeType = this.getAttributeType(keyWithExisting);
|
550 | attributeType = Array.isArray(tmpAttributeType) ? tmpAttributeType : [tmpAttributeType];
|
551 | }
|
552 | catch (e) { }
|
553 |
|
554 | function recursive(type, arrayTypeIndex) {
|
555 | if ((type === "M" || type === "L") && (object[key][arrayTypeIndex] || object[key]).schema) {
|
556 | accumulator.push(...main((object[key][arrayTypeIndex] || object[key]).schema, keyWithExisting));
|
557 | }
|
558 | }
|
559 | if (attributeType) {
|
560 | if (typePaths && typePaths[keyWithExisting] !== undefined) {
|
561 | const index = typePaths[keyWithExisting];
|
562 | const type = attributeType[index];
|
563 | recursive(type, index);
|
564 | }
|
565 | else {
|
566 | attributeType.forEach(recursive);
|
567 | }
|
568 | }
|
569 |
|
570 | return accumulator;
|
571 | }, []);
|
572 | };
|
573 | return main(this.schemaObject);
|
574 | }
|
575 | Schema.prototype.attributes = function (object) {
|
576 | return attributesAction.call(this, object);
|
577 | };
|
578 | Schema.prototype.getAttributeValue = function (key, settings) {
|
579 | const previousKeyParts = [];
|
580 | return ((settings === null || settings === void 0 ? void 0 : settings.standardKey) ? key : key.replace(/\.\d+/gu, ".0")).split(".").reduce((result, part) => {
|
581 | if (Array.isArray(result)) {
|
582 | const predefinedIndex = settings && settings.typeIndexOptionMap && settings.typeIndexOptionMap[previousKeyParts.join(".")];
|
583 | if (predefinedIndex !== undefined) {
|
584 | result = result[predefinedIndex];
|
585 | }
|
586 | else {
|
587 | result = result.find((item) => item.schema && item.schema[part]);
|
588 | }
|
589 | }
|
590 | previousKeyParts.push(part);
|
591 | return utils.object.get(result.schema, part);
|
592 | }, { "schema": this.schemaObject });
|
593 | };
|
594 | function retrieveTypeInfo(type, isSet, key, typeSettings) {
|
595 | const foundType = attributeTypesMain.find((checkType) => checkType.name.toLowerCase() === type.toLowerCase());
|
596 | if (!foundType) {
|
597 | throw new CustomError.InvalidType(`${key} contains an invalid type: ${type}`);
|
598 | }
|
599 | const parentType = foundType.result(typeSettings);
|
600 | if (!parentType.set && isSet) {
|
601 | throw new CustomError.InvalidType(`${key} with type: ${type} is not allowed to be a set`);
|
602 | }
|
603 | return isSet ? parentType.set : parentType;
|
604 | }
|
605 |
|
606 | Schema.prototype.getAttributeTypeDetails = function (key, settings = {}) {
|
607 | const standardKey = settings.standardKey ? key : key.replace(/\.\d+/gu, ".0");
|
608 | const val = this.getAttributeValue(standardKey, Object.assign(Object.assign({}, settings), { "standardKey": true }));
|
609 | if (!val) {
|
610 | throw new CustomError.UnknownAttribute(`Invalid Attribute: ${key}`);
|
611 | }
|
612 | let typeVal = typeof val === "object" && !Array.isArray(val) ? val.type : val;
|
613 | let typeSettings = {};
|
614 | if (typeof typeVal === "object" && !Array.isArray(typeVal)) {
|
615 | typeSettings = typeVal.settings || {};
|
616 | typeVal = typeVal.value;
|
617 | }
|
618 | const getType = (typeVal) => {
|
619 | let type;
|
620 | const isThisType = typeVal === Internal.Public.this;
|
621 | if (typeof typeVal === "function" || isThisType) {
|
622 | if (typeVal.prototype instanceof Document_1.Document || isThisType) {
|
623 | type = "model";
|
624 | if (isThisType) {
|
625 | typeSettings.model = {
|
626 | "Model": {
|
627 | "getHashKey": this.getHashKey.bind(this),
|
628 | "getRangeKey": this.getRangeKey.bind(this),
|
629 | "schemas": [this]
|
630 | }
|
631 | };
|
632 | }
|
633 | else {
|
634 | typeSettings.model = typeVal;
|
635 | }
|
636 | }
|
637 | else {
|
638 | const regexFuncName = /^Function ([^(]+)\(/iu;
|
639 | [, type] = typeVal.toString().match(regexFuncName);
|
640 | }
|
641 | }
|
642 | else {
|
643 | type = typeVal;
|
644 | }
|
645 | return type;
|
646 | };
|
647 | const result = (Array.isArray(typeVal) ? typeVal : [typeVal]).map((item, index) => {
|
648 | item = typeof item === "object" && !Array.isArray(item) && item.type ? item.type : item;
|
649 | if (typeof item === "object" && !Array.isArray(item)) {
|
650 | typeSettings = item.settings || {};
|
651 | item = item.value;
|
652 | }
|
653 | let type = getType(item);
|
654 | const isSet = type.toLowerCase() === "set";
|
655 | if (isSet) {
|
656 | let schemaValue = this.getAttributeSettingValue("schema", key);
|
657 | if (Array.isArray(schemaValue[index])) {
|
658 | schemaValue = schemaValue[index];
|
659 | }
|
660 | type = getType(schemaValue[0]);
|
661 | }
|
662 | const returnObject = retrieveTypeInfo(type, isSet, key, typeSettings);
|
663 | return returnObject;
|
664 | });
|
665 | const returnObject = result.length < 2 ? result[0] : result;
|
666 | return returnObject;
|
667 | };
|
668 |
|
\ | No newline at end of file |