diff --git a/PENDING_CHANGELOG.md b/PENDING_CHANGELOG.md index fb95ea1e2..5ecfb9ebe 100644 --- a/PENDING_CHANGELOG.md +++ b/PENDING_CHANGELOG.md @@ -12,3 +12,5 @@ - `output` has changed to `convertToNative` - For more information please refer to the AWS-SDK v3 changelogs - Node.js >=v10 now required +- Renamed `Document` to `Item` + - The largest user facing API change here is changing `{"return": "document"}` to `{"return": "item"}` and `{"return": "documents"}` to `{"return": "items"}` diff --git a/docs/docs/getting_started/Introduction.mdx b/docs/docs/getting_started/Introduction.mdx index 155ba8688..6f2ca1ad1 100644 --- a/docs/docs/getting_started/Introduction.mdx +++ b/docs/docs/getting_started/Introduction.mdx @@ -15,8 +15,8 @@ Dynamoose is a modeling tool for Amazon's DynamoDB. Dynamoose is heavily inspire - Type safety - High level API - Easy to use syntax -- Ability to transform data before saving or retrieving documents +- Ability to transform data before saving or retrieving items - Strict data modeling (validation, required attributes, and more) - Support for DynamoDB Transactions - Powerful Conditional/Filtering Support -- Callback & Promise support \ No newline at end of file +- Callback & Promise support diff --git a/docs/docs/getting_started/TypeScript.md b/docs/docs/getting_started/TypeScript.md index f63478f5d..e5922b4fd 100644 --- a/docs/docs/getting_started/TypeScript.md +++ b/docs/docs/getting_started/TypeScript.md @@ -38,9 +38,9 @@ No. There is no differences between using Dynamoose with TypeScript and JavaScri ### What does TypeScript support mean? What typings are included? -TypeScript support includes support for all functions/methods, and properties of Dynamoose. It does **not** have typings or contracts between your Schema and Documents you create. All type checks between your Schema and Documents is handled at runtime as part of Dynamoose, and not part of the TypeScript typings. +TypeScript support includes support for all functions/methods, and properties of Dynamoose. It does **not** have typings or contracts between your Schema and Items you create. All type checks between your Schema and Items is handled at runtime as part of Dynamoose, and not part of the TypeScript typings. -At some point we hope to explore the potiental of adding typings to ensure your Documents conform to your Schemas. However this raises a lot of questions regarding if it's even possible to have such dynamic typings in TypeScript, as well as edge cases that have not been considered yet. +At some point we hope to explore the potiental of adding typings to ensure your Items conform to your Schemas. However this raises a lot of questions regarding if it's even possible to have such dynamic typings in TypeScript, as well as edge cases that have not been considered yet. ### What should I do if I have additional questions? diff --git a/docs/docs/guide/Condition.md b/docs/docs/guide/Condition.md index 2333f6468..61bb87b4e 100644 --- a/docs/docs/guide/Condition.md +++ b/docs/docs/guide/Condition.md @@ -101,7 +101,7 @@ You will use this function with a comparison function which will complete the fi ```js new dynamoose.Condition().filter("id"); // Currently this condition has no filter behavior and will represent an empty conditional -new dynamoose.Condition().filter("id").eq(1); // Since this condition has a comparison function (eq) after the filter it will complete the filter conditional and only represent documents where `id` = 1 +new dynamoose.Condition().filter("id").eq(1); // Since this condition has a comparison function (eq) after the filter it will complete the filter conditional and only represent items where `id` = 1 ``` ## condition.where(key) @@ -117,17 +117,17 @@ This function is identical to [`condition.filter(key)`](#conditionfilterkey) and This comparison function will check to see if the given filter key is equal to the value you pass in as a parameter. ```js -new dynamoose.Condition().filter("name").eq("Tom"); // Condition all documents where `name` equals `Tom` +new dynamoose.Condition().filter("name").eq("Tom"); // Condition all items where `name` equals `Tom` ``` ## condition.exists() -This comparison function will check to see if the given filter key exists in the document. +This comparison function will check to see if the given filter key exists in the item. ```js -new dynamoose.Condition().filter("phoneNumber").exists(); // Represents all documents where `phoneNumber` exists in the document +new dynamoose.Condition().filter("phoneNumber").exists(); // Represents all items where `phoneNumber` exists in the item -new dynamoose.Condition().filter("phoneNumber").not().exists(); // Represents all documents where `phoneNumber` does not exist in the document +new dynamoose.Condition().filter("phoneNumber").not().exists(); // Represents all items where `phoneNumber` does not exist in the item ``` ## condition.lt(value) @@ -135,7 +135,7 @@ new dynamoose.Condition().filter("phoneNumber").not().exists(); // Represents al This comparison function will check to see if the given filter key is less than the value you pass in as a parameter. ```js -new dynamoose.Condition().filter("age").lt(5); // Represents all documents where `age` is less than 5 +new dynamoose.Condition().filter("age").lt(5); // Represents all items where `age` is less than 5 ``` ## condition.le(value) @@ -143,7 +143,7 @@ new dynamoose.Condition().filter("age").lt(5); // Represents all documents where This comparison function will check to see if the given filter key is less than or equal to the value you pass in as a parameter. ```js -new dynamoose.Condition().filter("age").le(5); // Represents all documents where `age` is less than or equal to 5 +new dynamoose.Condition().filter("age").le(5); // Represents all items where `age` is less than or equal to 5 ``` ## condition.gt(value) @@ -151,7 +151,7 @@ new dynamoose.Condition().filter("age").le(5); // Represents all documents where This comparison function will check to see if the given filter key is greater than the value you pass in as a parameter. ```js -new dynamoose.Condition().filter("age").gt(5); // Represents all documents where `age` is greater than 5 +new dynamoose.Condition().filter("age").gt(5); // Represents all items where `age` is greater than 5 ``` ## condition.ge(value) @@ -159,7 +159,7 @@ new dynamoose.Condition().filter("age").gt(5); // Represents all documents where This comparison function will check to see if the given filter key is greater than or equal to the value you pass in as a parameter. ```js -new dynamoose.Condition().filter("age").ge(5); // Represents all documents where `age` is greater than or equal to 5 +new dynamoose.Condition().filter("age").ge(5); // Represents all items where `age` is greater than or equal to 5 ``` ## condition.beginsWith(value) @@ -167,7 +167,7 @@ new dynamoose.Condition().filter("age").ge(5); // Represents all documents where This comparison function will check to see if the given filter key begins with the value you pass in as a parameter. ```js -new dynamoose.Condition().filter("name").beginsWith("T"); // Represents all documents where `name` begins with `T` +new dynamoose.Condition().filter("name").beginsWith("T"); // Represents all items where `name` begins with `T` ``` ## condition.contains(value) @@ -175,15 +175,15 @@ new dynamoose.Condition().filter("name").beginsWith("T"); // Represents all docu This comparison function will check to see if the given filter key contains the value you pass in as a parameter. ```js -new dynamoose.Condition().filter("name").contains("om"); // Represents all documents where `name` contains `om` +new dynamoose.Condition().filter("name").contains("om"); // Represents all items where `name` contains `om` ``` ## condition.in(values) -This comparison function will check to see if the given filter key equals any of the documents you pass in in the values array you pass in. The `values` parameter must be an array and will only represent documents where the value for the given key exists in the array you pass in. +This comparison function will check to see if the given filter key equals any of the items you pass in in the values array you pass in. The `values` parameter must be an array and will only represent items where the value for the given key exists in the array you pass in. ```js -new dynamoose.Condition("name").in(["Charlie", "Bob"]) // Represents all documents where `name` = `Charlie` OR `Bob` +new dynamoose.Condition("name").in(["Charlie", "Bob"]) // Represents all items where `name` = `Charlie` OR `Bob` ``` ## condition.between(a, b) @@ -191,5 +191,5 @@ new dynamoose.Condition("name").in(["Charlie", "Bob"]) // Represents all documen This comparison function will check to see if the given filter key is between the two values you pass in as parameters. ```js -new dynamoose.Condition().filter("age").between(5, 9); // Represents all documents where `age` is between 5 and 9 +new dynamoose.Condition().filter("age").between(5, 9); // Represents all items where `age` is between 5 and 9 ``` diff --git a/docs/docs/guide/Document.md b/docs/docs/guide/Document.md index 7974c8a24..7e0247e00 100644 --- a/docs/docs/guide/Document.md +++ b/docs/docs/guide/Document.md @@ -1,10 +1,10 @@ -A document represents an item for a given model in DynamoDB. This item can created locally (meaning it's not yet saved in DynamoDB), or created from an item already stored in DynamoDB (ex. `Model.get`). +The Dynamoose item represents an item for a given model in DynamoDB. This item can created locally (meaning it's not yet saved in DynamoDB), or created from an item already stored in DynamoDB (ex. `Model.get`). -A document/item is similar to a row in a relational database or a document in MongoDB. +A item is similar to a row in a relational database or a document in MongoDB. ## new Model(object) -In order to create a new document you just pass in your object into an instance of your model. +In order to create a new item you just pass in your object into an instance of your model. ```js const User = dynamoose.model("User", {"id": Number, "name": String}); @@ -14,12 +14,12 @@ const myUser = new User({ }); console.log(myUser.id); // 1 -// myUser is now a document instance of the User model +// myUser is now a item instance of the User model ``` -## document.save([settings,] [callback]) +## item.save([settings,] [callback]) -This saves a document to DynamoDB. This method uses the `putItem` DynamoDB API call to store your object in the given table associated with the model. This method is overwriting, and will overwrite the data you currently have in place for the existing key for your table. +This saves a item to DynamoDB. This method uses the `putItem` DynamoDB API call to store your object in the given table associated with the model. This method is overwriting, and will overwrite the data you currently have in place for the existing key for your table. This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. Nothing will be passed into the result for the promise or callback. @@ -27,8 +27,8 @@ You can also pass a settings object in as the first parameter. The following opt | Name | Type | Default | Notes | |---|---|---|---| -| overwrite | boolean | true | If an existing document with the same hash key should be overwritten in the database. You can set this to false to not overwrite an existing document with the same hash key. | -| return | string | `document` | If the function should return the `document` or `request`. If you set this to `request` the request that would be made to DynamoDB will be returned, but no requests will be made to DynamoDB. | +| overwrite | boolean | true | If an existing item with the same hash key should be overwritten in the database. You can set this to false to not overwrite an existing item with the same hash key. | +| return | string | `item` | If the function should return the `item` or `request`. If you set this to `request` the request that would be made to DynamoDB will be returned, but no requests will be made to DynamoDB. | | condition | [`dynamoose.Condition`](Condition) | `null` | This is an optional instance of a Condition for the save. | Both `settings` and `callback` parameters are optional. You can pass in a `callback` without `settings`, just by passing in one argument and having that argument be the `callback`. You are not required to pass in `settings` if you just want to pass in a `callback`. @@ -58,9 +58,9 @@ myUser.save((error) => { }); ``` -## document.delete([callback]) +## item.delete([callback]) -This deletes the given document from DynamoDB. This method uses the `deleteItem` DynamoDB API call to delete your object in the given table associated with the model. +This deletes the given item from DynamoDB. This method uses the `deleteItem` DynamoDB API call to delete your object in the given table associated with the model. This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. Nothing will be passed into the result for the promise or callback. @@ -86,9 +86,9 @@ myUser.delete((error) => { }); ``` -## document.populate([settings], [callback]) +## item.populate([settings], [callback]) -This allows you to populate a document with document instances for the subdocuments you are referencing in your schema. This function will return a promise, or call the `callback` paramter function upon completion. +This allows you to populate a item with item instances for the subitems you are referencing in your schema. This function will return a promise, or call the `callback` paramter function upon completion. The `settings` parameter is an object you can pass in with the following properties: @@ -117,9 +117,9 @@ user.populate((populatedUser, error) => { }); ``` -## document.serialize([serializer]) +## item.serialize([serializer]) -This function serializes the document with the given serializer. The serializer parameter can either be a string or object. If it is an object you can pass in the same serializer as you do into [`Model.serializer.add`](Model#modelserializeraddname-serializer). If you pass in a string it will use the registered serializer with that name that is attached to the Model. +This function serializes the item with the given serializer. The serializer parameter can either be a string or object. If it is an object you can pass in the same serializer as you do into [`Model.serializer.add`](Model#modelserializeraddname-serializer). If you pass in a string it will use the registered serializer with that name that is attached to the Model. This function will return an object. @@ -140,7 +140,7 @@ const myUser = new User({"id": 1, "name": "Bob"}); myUser.serialize(); // {"id": 1, "name": "Bob"} ``` -## document.original() +## item.original() This function returns the original item that was received from DynamoDB. This function will return a JSON object that represents the original item. In the event no item has been retrieved from DynamoDB `null` will be returned. @@ -153,18 +153,18 @@ console.log(user); // {"id": 1, "name": "Tim"} console.log(user.original()); // {"id": 1, "name": "Bob"} ``` -## document.toJSON() +## item.toJSON() -This function returns a JSON object representation of the document. This is most commonly used when comparing a document to an object you receive elsewhere without worrying about prototypes. +This function returns a JSON object representation of the item. This is most commonly used when comparing a item to an object you receive elsewhere without worrying about prototypes. ```js const user = new User({"id": 1, "name": "Tim"}); -console.log(user); // Document {"id": 1, "name": "Tim"} +console.log(user); // Item {"id": 1, "name": "Tim"} console.log(user.toJSON()); // {"id": 1, "name": "Tim"} ``` -Due to the fact that a document instance is based on an object it is rare that you will have to use this function since you can access all the properties of the document directly. For example, both of the results will yield the same output. +Due to the fact that a item instance is based on an object it is rare that you will have to use this function since you can access all the properties of the item directly. For example, both of the results will yield the same output. ```js const user = new User({"id": 1, "name": "Tim"}); diff --git a/docs/docs/guide/Model.md b/docs/docs/guide/Model.md index 852887a5c..1014fda10 100644 --- a/docs/docs/guide/Model.md +++ b/docs/docs/guide/Model.md @@ -1,10 +1,10 @@ -The Model object represents a table in DynamoDB. It takes in both a name and a schema and has methods to retrieve, and save documents in the database. +The Model object represents a table in DynamoDB. It takes in both a name and a schema and has methods to retrieve, and save items in the database. -## dynamoose.model[<Document>](name, [schema][, config]) +## dynamoose.model[<Item>](name, [schema][, config]) -This method is the basic entry point for creating a model in Dynamoose. When you call this method a new model is created, and it returns a Document initializer that you can use to create instances of the given model. +This method is the basic entry point for creating a model in Dynamoose. When you call this method a new model is created, and it returns a Item initializer that you can use to create instances of the given model. -The `name` parameter is a string representing the table name that will be used to store documents created by this model. Prefixes and suffixes may be added to this name using the `config` options. +The `name` parameter is a string representing the table name that will be used to store items created by this model. Prefixes and suffixes may be added to this name using the `config` options. The `schema` parameter can either be an object OR a [Schema](Schema.md) instance. If you pass in an object for the `schema` parameter it will create a Schema instance for you automatically. @@ -18,14 +18,14 @@ const Cat = dynamoose.model("Cat", new dynamoose.Schema({"name": String})); const Cat = dynamoose.model("Cat", new dynamoose.Schema({"name": String}), {"create": false}); ``` -An optional TypeScript class which extends `Document` can be provided right before the function bracket. This provides type checking when using operations like `Model.create()`. +An optional TypeScript class which extends `Item` can be provided right before the function bracket. This provides type checking when using operations like `Model.create()`. ```ts import * as dynamoose from "dynamoose"; -import {Document} from "dynamoose/dist/Document"; +import {Item} from "dynamoose/dist/Item"; // Strongly typed model -class Cat extends Document { +class Cat extends Item { id: number; name: string; } @@ -38,7 +38,7 @@ CatModel.create({"id": 1, "random": "string"}); const cat = await CatModel.get(1); ``` -You can also pass in an array of Schema instances or schema objects into the `schema` paremeter. This is useful for cases of single table design where you want one model to have multiple options for a schema. Behind the scenes Dynamoose will automatically pick the closest schema to match to your document, and use that schema for all operations pertaining to that document. If no matching schema can be found, it will default to the first schema in the array. +You can also pass in an array of Schema instances or schema objects into the `schema` paremeter. This is useful for cases of single table design where you want one model to have multiple options for a schema. Behind the scenes Dynamoose will automatically pick the closest schema to match to your item, and use that schema for all operations pertaining to that item. If no matching schema can be found, it will default to the first schema in the array. :::note If you use multiple schemas in one model, the hash & range keys must match for all schemas. @@ -73,11 +73,11 @@ The `config` parameter is an object used to customize settings for the model. | waitForActive.check.timeout | How many milliseconds before Dynamoose should timeout and stop checking if the table is active. | Number | 180000 | | waitForActive.check.frequency | How many milliseconds Dynamoose should delay between checks to see if the table is active. If this number is set to 0 it will use `setImmediate()` to run the check again. | Number | 1000 | | update | If Dynamoose should update the capacity of the existing table to match the model throughput. If this is a boolean of `true` all update actions will be run. If this is an array of strings, only the actions in the array will be run. The array can include the following settings to update, `ttl`, `indexes`, `throughput`. | Boolean \| [String] | false | -| expires | The setting to describe the time to live for documents created. If you pass in a number it will be used for the `expires.ttl` setting, with default values for everything else. If this is `undefined`, no time to live will be active on the model. | Number \| Object | undefined | -| expires.ttl | The default amount of time the document should stay alive from creation time in milliseconds. | Number | undefined | -| expires.attribute | The attribute name for where the document time to live attribute. | String | `ttl` | -| expires.items | The options for documents with ttl. | Object | {} | -| expires.items.returnExpired | If Dynamoose should include expired documents when returning retrieved documents. | Boolean | true | +| expires | The setting to describe the time to live for items created. If you pass in a number it will be used for the `expires.ttl` setting, with default values for everything else. If this is `undefined`, no time to live will be active on the model. | Number \| Object | undefined | +| expires.ttl | The default amount of time the item should stay alive from creation time in milliseconds. | Number | undefined | +| expires.attribute | The attribute name for where the item time to live attribute. | String | `ttl` | +| expires.items | The options for items with ttl. | Object | {} | +| expires.items.returnExpired | If Dynamoose should include expired items when returning retrieved items. | Boolean | true | The default object is listed below. @@ -163,16 +163,16 @@ async function printTableRequest() { ## Model.get(key[, settings][, callback]) -You can use Model.get to retrieve a document from DynamoDB. This method uses the `getItem` DynamoDB API call to retrieve the object. +You can use Model.get to retrieve a item from DynamoDB. This method uses the `getItem` DynamoDB API call to retrieve the object. -This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. A Document instance will be the result of the promise or callback response. In the event no item can be found in DynamoDB this method will return undefined. +This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. A Item instance will be the result of the promise or callback response. In the event no item can be found in DynamoDB this method will return undefined. You can also pass in an object for the optional `settings` parameter that is an object. The table below represents the options for the `settings` object. | Name | Description | Type | Default | |------|-------------|------|---------| -| return | What the function should return. Can be `document`, or `request`. In the event this is set to `request` the request Dynamoose will make to DynamoDB will be returned, and no request to DynamoDB will be made. If this is `request`, the function will not be async anymore. | String | `document` | -| attributes | What document attributes should be retrieved & returned. This will use the underlying `ProjectionExpression` DynamoDB option to ensure only the attributes you request will be sent over the wire. If this value is `undefined`, then all attributes will be returned. | [String] | undefined | +| return | What the function should return. Can be `item`, or `request`. In the event this is set to `request` the request Dynamoose will make to DynamoDB will be returned, and no request to DynamoDB will be made. If this is `request`, the function will not be async anymore. | String | `item` | +| attributes | What item attributes should be retrieved & returned. This will use the underlying `ProjectionExpression` DynamoDB option to ensure only the attributes you request will be sent over the wire. If this value is `undefined`, then all attributes will be returned. | [String] | undefined | | consistent | Whether to perform a strongly consistent read or not. If this value is `undefined`, then no `ConsistentRead` parameter will be included in the request, and DynamoDB will default to an eventually consistent read. | boolean | undefined | ```js @@ -258,23 +258,23 @@ User.get({"id": 1}, (error, myUser) => { ## Model.batchGet(keys[, settings][, callback]) -You can use Model.batchGet to retrieve multiple documents from DynamoDB. This method uses the `batchGetItem` DynamoDB API call to retrieve the object. +You can use Model.batchGet to retrieve multiple items from DynamoDB. This method uses the `batchGetItem` DynamoDB API call to retrieve the object. -This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. An array of Document instances will be the result of the promise or callback response. In the event no documents can be found in DynamoDB this method will return an empty array. +This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. An array of Item instances will be the result of the promise or callback response. In the event no items can be found in DynamoDB this method will return an empty array. The array you receive back is a standard JavaScript array of objects. However, the array has some special properties with extra information about your scan operation that you can access. This does not prevent the ability do running loops or accessing the objects within the array. The extra properties attached to the array are: -- `unprocessedKeys` - In the event there are more documents to get in DynamoDB this property will be equal to an array of unprocessed keys. You can take this property and call `batchGet` again to retrieve those documents. Normally DynamoDB returns this property as a DynamoDB object, but Dynamoose returns it and handles it as a standard JS object without the DynamoDB types. -- `populate` - A function that is an alias to [`document.populate`](Document#documentpopulatesettings-callback) and will populate all documents in the array. +- `unprocessedKeys` - In the event there are more items to get in DynamoDB this property will be equal to an array of unprocessed keys. You can take this property and call `batchGet` again to retrieve those items. Normally DynamoDB returns this property as a DynamoDB object, but Dynamoose returns it and handles it as a standard JS object without the DynamoDB types. +- `populate` - A function that is an alias to [`item.populate`](Item#itempopulatesettings-callback) and will populate all items in the array. You can also pass in an object for the optional `settings` parameter that is an object. The table below represents the options for the `settings` object. | Name | Description | Type | Default | |------|-------------|------|---------| -| return | What the function should return. Can be `documents`, or `request`. In the event this is set to `request` the request Dynamoose will make to DynamoDB will be returned, and no request to DynamoDB will be made. If this is `request`, the function will not be async anymore. | String | `documents` | -| attributes | What document attributes should be retrieved & returned. This will use the underlying `AttributesToGet` DynamoDB option to ensure only the attributes you request will be sent over the wire. If this value is `undefined`, then all attributes will be returned. | [String] | undefined | +| return | What the function should return. Can be `items`, or `request`. In the event this is set to `request` the request Dynamoose will make to DynamoDB will be returned, and no request to DynamoDB will be made. If this is `request`, the function will not be async anymore. | String | `items` | +| attributes | What item attributes should be retrieved & returned. This will use the underlying `AttributesToGet` DynamoDB option to ensure only the attributes you request will be sent over the wire. If this value is `undefined`, then all attributes will be returned. | [String] | undefined | ```js const User = dynamoose.model("User", {"id": Number, "name": String}); @@ -374,9 +374,9 @@ User.batchGet([{"id": 1}, {"id": 2}], (error, myUsers) => { }); ``` -## Model.create(document, [settings], [callback]) +## Model.create(item, [settings], [callback]) -This function lets you create a new document for a given model. This function is almost identical to creating a new document and calling `document.save`, with one key difference, this function will default to setting `overwrite` to false. +This function lets you create a new item for a given model. This function is almost identical to creating a new item and calling `item.save`, with one key difference, this function will default to setting `overwrite` to false. If you do not pass in a `callback` parameter a promise will be returned. @@ -401,9 +401,9 @@ User.create({"id": 1, "name": "Tim"}, (error, user) => { // If a user with `id= }); ``` -## Model.batchPut(documents, [settings], [callback]) +## Model.batchPut(items, [settings], [callback]) -This saves documents to DynamoDB. This method uses the `batchWriteItem` DynamoDB API call to store your objects in the given table associated with the model. This method is overwriting, and will overwrite the data you currently have in place for the existing key for your table. +This saves items to DynamoDB. This method uses the `batchWriteItem` DynamoDB API call to store your objects in the given table associated with the model. This method is overwriting, and will overwrite the data you currently have in place for the existing key for your table. This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. Nothing will be passed into the result for the promise or callback. @@ -467,10 +467,10 @@ You can also pass in a `settings` object parameter to define extra settings for | Name | Description | Type | Default | |------|-------------|------|---------| -| return | What the function should return. Can be `document`, or `request`. In the event this is set to `request` the request Dynamoose will make to DynamoDB will be returned, and no request to DynamoDB will be made. | String | `document` | +| return | What the function should return. Can be `item`, or `request`. In the event this is set to `request` the request Dynamoose will make to DynamoDB will be returned, and no request to DynamoDB will be made. | String | `item` | | condition | This is an optional instance of a Condition for the update. | [dynamoose.Condition](Condition.md) | `null` -There are two different methods for specifying what you'd like to edit in the document. The first is you can just pass in the attribute name as the key, and the new value as the value. This will set the given attribute to the new value. +There are two different methods for specifying what you'd like to edit in the item. The first is you can just pass in the attribute name as the key, and the new value as the value. This will set the given attribute to the new value. ```js // The code below will set `name` to Bob for the user where `id` = 1 @@ -489,7 +489,7 @@ User.update({"id": 1}, {"name": "Bob"}, (error, user) => { ``` ```js -// The following code below will only update the document if the `active` property on the existing document is set to true +// The following code below will only update the item if the `active` property on the existing item is set to true const condition = new dynamoose.Condition().where("active").eq(true); @@ -511,30 +511,30 @@ The other method you can use is by using specific update types. These update typ - `$SET` - This method will set the attribute to the new value (as shown above) - `$ADD` - This method will add the value to the attribute. If the attribute is a number it will add the value to the existing number. If the attribute is a list, it will add the value to the list. Although this method only works for sets in DynamoDB, Dynamoose will automatically update this method to work for lists/arrays as well according to your schema. This update type does not work for any other attribute type. -- `$REMOVE` - This method will remove the attribute from the document. Since this method doesn't require values you can pass in an array of attribute names. +- `$REMOVE` - This method will remove the attribute from the item. Since this method doesn't require values you can pass in an array of attribute names. - `$DELETE` - This method will delete one or more elements from a Set. ```js await User.update({"id": 1}, {"$SET": {"name": "Bob"}, "$ADD": {"age": 1}}); -// This will set the document name to Bob and increase the age by 1 for the user where id = 1 +// This will set the item name to Bob and increase the age by 1 for the user where id = 1 await User.update({"id": 1}, {"$REMOVE": ["address"]}); await User.update({"id": 1}, {"$REMOVE": {"address": null}}); -// These two function calls will delete the `address` attribute for the document where id = 1 +// These two function calls will delete the `address` attribute for the item where id = 1 await User.update({"id": 1}, {"$SET": {"name": "Bob"}, "$ADD": {"friends": "Tim"}}); await User.update({"id": 1}, {"$SET": {"name": "Bob"}, "$ADD": {"friends": ["Tim"]}}); -// This will set the document name to Bob and append Tim to the list/array/set of friends where id = 1 +// This will set the item name to Bob and append Tim to the list/array/set of friends where id = 1 await User.update({"id": 1}, {"$DELETE": {"friends": ["Tim"]}}); -// This will delete the element Tim from the friends set on the document where id = 1 +// This will delete the element Tim from the friends set on the item where id = 1 ``` You are allowed to combine these two methods into one update object. ```js await User.update({"id": 1}, {"name": "Bob", "$ADD": {"age": 1}}); -// This will set the document name to Bob and increase the age by 1 for the user where id = 1 +// This will set the item name to Bob and increase the age by 1 for the user where id = 1 ``` The `validate` Schema attribute property will only be run on `$SET` values. This is due to the fact that Dynamoose is unaware of what the existing value is in the database for `$ADD` properties. @@ -637,7 +637,7 @@ User.delete({"id": 1}, (error) => { ## Model.batchDelete(keys[, settings][, callback]) -You can use Model.batchDelete to delete documents from DynamoDB. This method uses the `batchWriteItem` DynamoDB API call to delete the objects. +You can use Model.batchDelete to delete items from DynamoDB. This method uses the `batchWriteItem` DynamoDB API call to delete the objects. `keys` can be an array of strings representing the hashKey and/or an array of objects containing the hashKey & rangeKey. @@ -674,7 +674,7 @@ User.batchDelete([1, 2], (error, response) => { if (error) { console.error(error); } else { - console.log(`Successfully deleted documents. ${response.unprocessedItems.count} of unprocessed documents.`); + console.log(`Successfully deleted items. ${response.unprocessedItems.count} of unprocessed items.`); } }); ``` @@ -714,7 +714,7 @@ const User = dynamoose.model("User", {"id": Number, "name": {"type": String, "ra try { const response = await User.batchDelete([{"id": 1, "name": "Tim"}, {"id": 2, "name": "Charlie"}]); - console.log(`Successfully deleted document. ${response.unprocessedItems.count} of unprocessed documents.`); + console.log(`Successfully deleted item. ${response.unprocessedItems.count} of unprocessed items.`); } catch (error) { console.error(error); } @@ -725,7 +725,7 @@ User.batchDelete([{"id": 1, "name": "Tim"}, {"id": 2, "name": "Charlie"}], (erro if (error) { console.error(error); } else { - console.log(`Successfully deleted document. ${response.unprocessedItems.count} of unprocessed documents.`); + console.log(`Successfully deleted item. ${response.unprocessedItems.count} of unprocessed items.`); } }); ``` @@ -735,7 +735,7 @@ const User = dynamoose.model("User", {"id": Number, "name": String}); try { const response = await User.batchDelete([{"id": 1}, {"id": 2}]); - console.log(`Successfully deleted document. ${response.unprocessedItems.count} of unprocessed documents.`); + console.log(`Successfully deleted item. ${response.unprocessedItems.count} of unprocessed items.`); } catch (error) { console.error(error); } @@ -746,7 +746,7 @@ User.batchDelete([{"id": 1}, {"id": 2}], (error, response) => { if (error) { console.error(error); } else { - console.log(`Successfully deleted document. ${response.unprocessedItems.count} of unprocessed documents.`); + console.log(`Successfully deleted item. ${response.unprocessedItems.count} of unprocessed items.`); } }); ``` @@ -901,18 +901,18 @@ const models = await User.scanAll(); User.scanAll((err, models) => {}); ``` -## Model.methods.document.set(name, function) +## Model.methods.item.set(name, function) -This function allows you to add a method to the model documents that you can call later. When Dynamoose calls your `function` parameter, `this` will be set to the underlying document. If an existing method exists with the given name, it will be overwritten, except if you are trying to replace an internal method, then this function will fail silently. +This function allows you to add a method to the model items that you can call later. When Dynamoose calls your `function` parameter, `this` will be set to the underlying item. If an existing method exists with the given name, it will be overwritten, except if you are trying to replace an internal method, then this function will fail silently. ```js // Setup: const User = new dynamoose.model("Model", ModelSchema); -User.methods.document.set("setName", async function () { +User.methods.item.set("setName", async function () { this.name = await getRandomName(); }); // OR -User.methods.document.set("setName", function (cb) { +User.methods.item.set("setName", function (cb) { getRandomName((err, name) => { if (err) { cb(err); @@ -939,11 +939,11 @@ You can also pass parameters into your custom method. It is important to note th ```js // Setup: const User = new dynamoose.model("Model", ModelSchema); -User.methods.document.set("setName", async function (firstName, lastName) { +User.methods.item.set("setName", async function (firstName, lastName) { this.name = await verifyName(`${firstName} ${lastName}`); }); // OR -User.methods.document.set("scanAll", function (firstName, lastName, cb) { +User.methods.item.set("scanAll", function (firstName, lastName, cb) { verifyName(`${firstName} ${lastName}`, (err, name) => { if (err) { cb(err); @@ -965,12 +965,12 @@ await user.setName("Charlie", "Fish"); console.log("Set name"); ``` -## Model.methods.document.delete(name) +## Model.methods.item.delete(name) -This allows you to delete an existing method from the document. If no existing method is assigned for that name, the function will do nothing and no error will be thrown. +This allows you to delete an existing method from the item. If no existing method is assigned for that name, the function will do nothing and no error will be thrown. ```js -User.methods.document.delete("setName"); +User.methods.item.delete("setName"); const user = new User(); // The following lines will throw an error @@ -981,7 +981,7 @@ user.setName((err) => {}); ## Model.serializeMany(items[, serializer]) -This function takes in an array of `items` and serializes all of them. This function is very similar to [`document.serialize`](Document#documentserializeserializer) except it takes in an array of documents to serialize and returns an array of those documents. +This function takes in an array of `items` and serializes all of them. This function is very similar to [`item.serialize`](Item#itemserializeserializer) except it takes in an array of items to serialize and returns an array of those items. ```js User.serializeMany(await User.scan().exec(), "myCustomSerializer"); @@ -997,7 +997,7 @@ The `serializer` parameter can be an object containing the following properties. | --- | --- | --- | | include | [string] | The properties you wish to include when serializing. | | exclude | [string] | The properties you wish to exclude when serializing. | -| modify | (serialized: Object, original: Object) => Object | A function you want to use to modify the object in the serializer. The `serialized` parameter is the new object (after `include` & `exclude` have been applied). The `original` parameter is the original document (before `include` & `exclude` have been applied). | +| modify | (serialized: Object, original: Object) => Object | A function you want to use to modify the object in the serializer. The `serialized` parameter is the new object (after `include` & `exclude` have been applied). The `original` parameter is the original item (before `include` & `exclude` have been applied). | ```js User.serializer.add("myCustomSerializer", { @@ -1030,7 +1030,7 @@ User.serializer.delete("myCustomSerializer"); ## Model.serializer.default.set([name]) -This function sets the default serializer for the given model. By default the default serializer has the same behavior as [`document.toJSON`](Document#documenttojson). The default serializer will be used for [`Model.serializeMany`](#modelserializemanyitems-serializer) and [`document.serialize`](Document#documentserializeserializer) if you don't pass anything into the `serializer` parameter. +This function sets the default serializer for the given model. By default the default serializer has the same behavior as [`item.toJSON`](Item#itemtojson). The default serializer will be used for [`Model.serializeMany`](#modelserializemanyitems-serializer) and [`item.serialize`](Item#itemserializeserializer) if you don't pass anything into the `serializer` parameter. ```js User.serializer.default.set("myCustomSerializer"); diff --git a/docs/docs/guide/Query.md b/docs/docs/guide/Query.md index 2fb06c1c6..a35194628 100644 --- a/docs/docs/guide/Query.md +++ b/docs/docs/guide/Query.md @@ -2,16 +2,16 @@ Dynamoose provides the ability to query a model by using the `Model.query` funct ## Model.query([filter]) -This is the basic entry point to construct a query request. When running a query you must specify at least the hashKey of the document(s). This can either be the hashKey of the table, or the hashKey of an index. The filter property is optional and can either be an object or a string representing the key you which to first filter on. In the event you don't pass in any parameters and don't call any other methods on the query object it will query with no filters or options. +This is the basic entry point to construct a query request. When running a query you must specify at least the hashKey of the item(s). This can either be the hashKey of the table, or the hashKey of an index. The filter property is optional and can either be an object or a string representing the key you which to first filter on. In the event you don't pass in any parameters and don't call any other methods on the query object it will query with no filters or options. ```js -Cat.query("breed").contains("Terrier").exec() // will query all documents where the hashKey `breed` contains `Terrier` -Cat.query({"breed": {"contains": "Terrier"}}).exec() // will query all documents where the hashKey `breed` contains `Terrier` +Cat.query("breed").contains("Terrier").exec() // will query all items where the hashKey `breed` contains `Terrier` +Cat.query({"breed": {"contains": "Terrier"}}).exec() // will query all items where the hashKey `breed` contains `Terrier` ``` If you pass an object into `Model.query` the object for each key should contain the comparison type. For example, in the last example above, `contains` was our comparison type. This comparison type must match one of the comparison type functions listed on this page. -`Model.query()` combines both the `KeyConditionExpression` and the `FilterExpression` from DynamoDB. If you query for an attribute that you defined as your hashKey or rangeKey DynamoDB will use `KeyConditionExpression`. This could be the most performant and cost efficient way to query for. If querying for attributes that are not defined as your hashKey or rangeKey DynamoDB might select more documents at first and then filter the result which could have a bad impact on performance and costs. +`Model.query()` combines both the `KeyConditionExpression` and the `FilterExpression` from DynamoDB. If you query for an attribute that you defined as your hashKey or rangeKey DynamoDB will use `KeyConditionExpression`. This could be the most performant and cost efficient way to query for. If querying for attributes that are not defined as your hashKey or rangeKey DynamoDB might select more items at first and then filter the result which could have a bad impact on performance and costs. ## Conditionals @@ -29,7 +29,7 @@ Cat.query("name").eq("Will").exec((error, results) => { console.error(error); } else { console.log(results); - // [ Document { name: 'Will', breed: 'Terrier', id: 1 }, + // [ Item { name: 'Will', breed: 'Terrier', id: 1 }, // lastKey: undefined, // count: 1, // queriedCount: 2, @@ -53,29 +53,29 @@ The extra properties attached to the array are: | Name | Description | |---|---| -| `lastKey` | In the event there are more documents to query in DynamoDB this property will be equal to an object that you can pass into [`query.startAt(key)`](#querystartatkey) to retrieve more documents. Normally DynamoDB returns this property as a DynamoDB object, but Dynamoose returns it and handles it as a standard JS object without the DynamoDB types. | -| `count` | The count property from DynamoDB, which represents how many documents were returned from DynamoDB. This should always equal the number of documents in the array. | -| `queriedCount` | How many documents DynamoDB queried. This doesn't necessarily represent how many documents were returned from DynamoDB due to filters that might have been applied to the query request. | +| `lastKey` | In the event there are more items to query in DynamoDB this property will be equal to an object that you can pass into [`query.startAt(key)`](#querystartatkey) to retrieve more items. Normally DynamoDB returns this property as a DynamoDB object, but Dynamoose returns it and handles it as a standard JS object without the DynamoDB types. | +| `count` | The count property from DynamoDB, which represents how many items were returned from DynamoDB. This should always equal the number of items in the array. | +| `queriedCount` | How many items DynamoDB queried. This doesn't necessarily represent how many items were returned from DynamoDB due to filters that might have been applied to the query request. | | `timesQueried` | How many times Dynamoose made a query request to DynamoDB. This will always equal 1, unless you used the `query.all` or `query.parallel` method. | -| `populate` | A function that is an alias to [`document.populate`](Document#documentpopulatesettings-callback) and will populate all documents in the array. | +| `populate` | A function that is an alias to [`item.populate`](Item#itempopulatesettings-callback) and will populate all items in the array. | ## query.limit(count) -This function will limit the number of documents that DynamoDB will query in this request. Unlike most SQL databases this does not guarantee the response will contain 5 documents. Instead DynamoDB will only query a maximum of 5 documents to see if they match and should be returned. The `count` parameter passed in should be a number representing how many documents you wish DynamoDB to query. +This function will limit the number of items that DynamoDB will query in this request. Unlike most SQL databases this does not guarantee the response will contain 5 items. Instead DynamoDB will only query a maximum of 5 items to see if they match and should be returned. The `count` parameter passed in should be a number representing how many items you wish DynamoDB to query. ```js -Cat.query("name").eq("Will").limit(5); // Limit query request to 5 documents +Cat.query("name").eq("Will").limit(5); // Limit query request to 5 items ``` ## query.startAt(key) -In the event there are more documents to query in a previous response, Dynamoose will return a key in the `.lastKey` property. You can pass that object into this property to further query documents in your table. +In the event there are more items to query in a previous response, Dynamoose will return a key in the `.lastKey` property. You can pass that object into this property to further query items in your table. Although the `.lastKey` property returns a standard (non DynamoDB) object, you can pass a standard object OR DynamoDB object into this function, and it will handle either case. ```js const response = await Cat.query("name").eq("Will").exec(); -const moreDocuments = Cat.query("name").eq("Will").startAt(response.lastKey); +const moreItems = Cat.query("name").eq("Will").startAt(response.lastKey); ``` ## query.attributes(attributes) @@ -83,14 +83,14 @@ const moreDocuments = Cat.query("name").eq("Will").startAt(response.lastKey); This function will limit which attributes DynamoDB returns for each item in the table. This can limit the size of the DynamoDB response and helps you only retrieve the data you need. The `attributes` property passed into this function should be an array of strings representing the property names you wish DynamoDB to return. ```js -Cat.query("name").eq("Will").attributes(["id", "name"]); // Return all documents but only return the `id` & `name` properties for each item +Cat.query("name").eq("Will").attributes(["id", "name"]); // Return all items but only return the `id` & `name` properties for each item ``` This function uses the `ProjectionExpression` DynamoDB property to save bandwidth and not send the entire item over the wire. ## query.count() -Instead of returning an array of documents this function will cause the query operation to return a special object with the count information for the query. The response you will receive from the query operation with this setting will be an object with the properties `count` & `queriedCount`, which have the same values as described in [`query.exec([callback])`](#queryexeccallback). +Instead of returning an array of items this function will cause the query operation to return a special object with the count information for the query. The response you will receive from the query operation with this setting will be an object with the properties `count` & `queriedCount`, which have the same values as described in [`query.exec([callback])`](#queryexeccallback). Using this option will save bandwidth by setting the DynamoDB `Select` option to `COUNT`. @@ -117,7 +117,7 @@ Cat.query("name").eq("Will").using("name-index"); // Run the query on the `name- ## query.sort(order) -This function sorts the documents you receive back by the rangeKey. By default, if not provided, it will sort in ascending order. +This function sorts the items you receive back by the rangeKey. By default, if not provided, it will sort in ascending order. The order parameter must be a string either equal to `ascending` or `descending`. @@ -133,17 +133,17 @@ Under the hood this sets the `ScanIndexForward` property when making the request ## query.all([delay[, max]]) -Unlike most other query functions that directly change the DynamoDB query request, this function is purely internal and unique to Dynamoose. If a query result is more than the AWS query response limit, DynamoDB paginates the results so you would have to send multiple requests. This function sends continuous query requests upon receiving the response until all documents have been received (by checking and making new requests with the `lastKey` property from the previous response). This can be useful if you wish to get all the documents from the table and don't want to worry about checking the `lastKey` property and sending a new query request yourself. +Unlike most other query functions that directly change the DynamoDB query request, this function is purely internal and unique to Dynamoose. If a query result is more than the AWS query response limit, DynamoDB paginates the results so you would have to send multiple requests. This function sends continuous query requests upon receiving the response until all items have been received (by checking and making new requests with the `lastKey` property from the previous response). This can be useful if you wish to get all the items from the table and don't want to worry about checking the `lastKey` property and sending a new query request yourself. Two parameters can be specified on this setting: - `delay` - Number (default: 0) - The number of milliseconds to delay between receiving of the response of one query request and sending of the request for the next query request. - `max` - Number (default: 0) - The maximum number of requests that should be made to DynamoDB, regardless of if the `lastKey` property still exists in the response. In the event this is set to 0, an unlimited number of requests will be made to DynamoDB, so long as the `lastKey` property still exists. -The documents for all of the requests will be merged into a single array with the `count` & `queriedCount` properties being summed in the response. If you set a maximum number of query requests and there is still a `lastKey` on the response that will be returned to you. +The items for all of the requests will be merged into a single array with the `count` & `queriedCount` properties being summed in the response. If you set a maximum number of query requests and there is still a `lastKey` on the response that will be returned to you. ```js -Cat.query("name").eq("Will").all(); // Query table and so long as the `lastKey` property exists continuously query the table to retrieve all documents -Cat.query("name").eq("Will").all(100); // Query table and so long as the `lastKey` property exists continuously query the table to retrieve all documents with a 100 ms delay before the next query request -Cat.query("name").eq("Will").all(0, 5); // Query table and so long as the `lastKey` property exists continuously query the table to retrieve all documents with a maximum of 5 requests total +Cat.query("name").eq("Will").all(); // Query table and so long as the `lastKey` property exists continuously query the table to retrieve all items +Cat.query("name").eq("Will").all(100); // Query table and so long as the `lastKey` property exists continuously query the table to retrieve all items with a 100 ms delay before the next query request +Cat.query("name").eq("Will").all(0, 5); // Query table and so long as the `lastKey` property exists continuously query the table to retrieve all items with a maximum of 5 requests total ``` diff --git a/docs/docs/guide/Scan.md b/docs/docs/guide/Scan.md index 624c6759c..79127659f 100644 --- a/docs/docs/guide/Scan.md +++ b/docs/docs/guide/Scan.md @@ -1,15 +1,15 @@ Dynamoose provides the ability to scan a model by using the `Model.scan` function. This function acts as a builder to construct your scan with the appropriate settings before executing it (`scan.exec`). -Scan operations run on every document in your table or index. This means that all filtering is done after the documents are read, and therefore is not the most performant method. Due to that, if possible, it is highly encouraged to use [`Model.query`](Query.md) as opposed to `Model.scan`. +Scan operations run on every item in your table or index. This means that all filtering is done after the items are read, and therefore is not the most performant method. Due to that, if possible, it is highly encouraged to use [`Model.query`](Query.md) as opposed to `Model.scan`. ## Model.scan([filter]) This is the basic entry point to construct a scan request. The filter property is optional and can either be an object or a string representing the key you which to first filter on. In the event you don't pass in any parameters and don't call any other methods on the scan object it will scan with no filters or options. ```js -Cat.scan().exec() // will scan all documents with no filters or options -Cat.scan("breed").contains("Terrier").exec() // will scan all documents and filter all documents where the key `breed` contains `Terrier` -Cat.scan({"breed": {"contains": "Terrier"}}).exec() // will scan all documents and filter all documents where the key `breed` contains `Terrier` +Cat.scan().exec() // will scan all items with no filters or options +Cat.scan("breed").contains("Terrier").exec() // will scan all items and filter all items where the key `breed` contains `Terrier` +Cat.scan({"breed": {"contains": "Terrier"}}).exec() // will scan all items and filter all items where the key `breed` contains `Terrier` ``` If you pass an object into `Model.scan` the object for each key should contain the comparison type. For example, in the last example above, `contains` was our comparison type. This comparison type must match one of the comparison type functions listed on this page. @@ -30,7 +30,7 @@ Cat.scan().exec((error, results) => { console.error(error); } else { console.log(results); - // [ Document { name: 'Will', breed: 'Terrier', id: 1 }, + // [ Item { name: 'Will', breed: 'Terrier', id: 1 }, // lastKey: undefined, // count: 1, // scannedCount: 2, @@ -54,29 +54,29 @@ The extra properties attached to the array are: | Name | Description | |---|---| -| `lastKey` | In the event there are more documents to scan in DynamoDB this property will be equal to an object that you can pass into [`scan.startAt(key)`](#scanstartatkey) to retrieve more documents. Normally DynamoDB returns this property as a DynamoDB object, but Dynamoose returns it and handles it as a standard JS object without the DynamoDB types. | -| `count` | The count property from DynamoDB, which represents how many documents were returned from DynamoDB. This should always equal the number of documents in the array. | -| `scannedCount` | How many documents DynamoDB scanned. This doesn't necessarily represent how many documents were returned from DynamoDB due to filters that might have been applied to the scan request. | +| `lastKey` | In the event there are more items to scan in DynamoDB this property will be equal to an object that you can pass into [`scan.startAt(key)`](#scanstartatkey) to retrieve more items. Normally DynamoDB returns this property as a DynamoDB object, but Dynamoose returns it and handles it as a standard JS object without the DynamoDB types. | +| `count` | The count property from DynamoDB, which represents how many items were returned from DynamoDB. This should always equal the number of items in the array. | +| `scannedCount` | How many items DynamoDB scanned. This doesn't necessarily represent how many items were returned from DynamoDB due to filters that might have been applied to the scan request. | | `timesScanned` | How many times Dynamoose made a scan request to DynamoDB. This will always equal 1, unless you used the `scan.all` or `scan.parallel` method. | -| `populate` | A function that is an alias to [`document.populate`](Document#documentpopulatesettings-callback) and will populate all documents in the array. | +| `populate` | A function that is an alias to [`item.populate`](Item#itempopulatesettings-callback) and will populate all items in the array. | ## scan.limit(count) -This function will limit the number of documents that DynamoDB will scan in this request. Unlike most SQL databases this does not guarantee the response will contain 5 documents. Instead DynamoDB will only scan a maximum of 5 documents to see if they match and should be returned. The `count` parameter passed in should be a number representing how many documents you wish DynamoDB to scan. +This function will limit the number of items that DynamoDB will scan in this request. Unlike most SQL databases this does not guarantee the response will contain 5 items. Instead DynamoDB will only scan a maximum of 5 items to see if they match and should be returned. The `count` parameter passed in should be a number representing how many items you wish DynamoDB to scan. ```js -Cat.scan().limit(5); // Limit scan request to 5 documents +Cat.scan().limit(5); // Limit scan request to 5 items ``` ## scan.startAt(key) -In the event there are more documents to scan in a previous response, Dynamoose will return a key in the `.lastKey` property. You can pass that object into this property to further scan documents in your table. +In the event there are more items to scan in a previous response, Dynamoose will return a key in the `.lastKey` property. You can pass that object into this property to further scan items in your table. Although the `.lastKey` property returns a standard (non DynamoDB) object, you can pass a standard object OR DynamoDB object into this function, and it will handle either case. ```js const response = await Cat.scan().exec(); -const moreDocuments = Cat.scan().startAt(response.lastKey); +const moreItems = Cat.scan().startAt(response.lastKey); ``` ## scan.attributes(attributes) @@ -84,7 +84,7 @@ const moreDocuments = Cat.scan().startAt(response.lastKey); This function will limit which attributes DynamoDB returns for each item in the table. This can limit the size of the DynamoDB response and helps you only retrieve the data you need. The `attributes` property passed into this function should be an array of strings representing the property names you wish DynamoDB to return. ```js -Cat.scan().attributes(["id", "name"]); // Return all documents but only return the `id` & `name` properties for each item +Cat.scan().attributes(["id", "name"]); // Return all items but only return the `id` & `name` properties for each item ``` This function uses the `ProjectionExpression` DynamoDB property to save bandwidth and not send the entire item over the wire. @@ -101,7 +101,7 @@ Cat.scan().parallel(4); // Run 4 parallel scans on the table ## scan.count() -Instead of returning the documents in the array this function will cause the scan operation to return a special object with the count information for the scan. The response you will receive from the scan operation with this setting will be an object with the properties `count` & `scannedCount`, which have the same values as described in [`scan.exec([callback])`](#scanexeccallback). +Instead of returning the items in the array this function will cause the scan operation to return a special object with the count information for the scan. The response you will receive from the scan operation with this setting will be an object with the properties `count` & `scannedCount`, which have the same values as described in [`scan.exec([callback])`](#scanexeccallback). Using this option will save bandwidth by setting the DynamoDB `Select` option to `COUNT`. @@ -128,17 +128,17 @@ Cat.scan().using("name-index"); // Run the scan on the `name-index` index ## scan.all([delay[, max]]) -Unlike most other scan functions that directly change the DynamoDB scan request, this function is purely internal and unique to Dynamoose. If a scan result is more than the AWS scan response limit, DynamoDB paginates the results so you would have to send multiple requests. This function sends continuous scan requests upon receiving the response until all documents have been received (by checking and making new requests with the `lastKey` property from the previous response). This can be useful if you wish to get all the documents from the table and don't want to worry about checking the `lastKey` property and sending a new scan request yourself. +Unlike most other scan functions that directly change the DynamoDB scan request, this function is purely internal and unique to Dynamoose. If a scan result is more than the AWS scan response limit, DynamoDB paginates the results so you would have to send multiple requests. This function sends continuous scan requests upon receiving the response until all items have been received (by checking and making new requests with the `lastKey` property from the previous response). This can be useful if you wish to get all the items from the table and don't want to worry about checking the `lastKey` property and sending a new scan request yourself. Two parameters can be specified on this setting: - `delay` - Number (default: 0) - The number of milliseconds to delay between receiving of the response of one scan request and sending of the request for the next scan request. - `max` - Number (default: 0) - The maximum number of requests that should be made to DynamoDB, regardless of if the `lastKey` property still exists in the response. In the event this is set to 0, an unlimited number of requests will be made to DynamoDB, so long as the `lastKey` property still exists. -The documents for all of the requests will be merged into a single array with the `count` & `scannedCount` properties being summed in the response. If you set a maximum number of scan requests and there is still a `lastKey` on the response that will be returned to you. +The items for all of the requests will be merged into a single array with the `count` & `scannedCount` properties being summed in the response. If you set a maximum number of scan requests and there is still a `lastKey` on the response that will be returned to you. ```js -Cat.scan().all(); // Scan table and so long as the `lastKey` property exists continuously scan the table to retrieve all documents -Cat.scan().all(100); // Scan table and so long as the `lastKey` property exists continuously scan the table to retrieve all documents with a 100 ms delay before the next scan request -Cat.scan().all(0, 5); // Scan table and so long as the `lastKey` property exists continuously scan the table to retrieve all documents with a maximum of 5 requests total +Cat.scan().all(); // Scan table and so long as the `lastKey` property exists continuously scan the table to retrieve all items +Cat.scan().all(100); // Scan table and so long as the `lastKey` property exists continuously scan the table to retrieve all items with a 100 ms delay before the next scan request +Cat.scan().all(0, 5); // Scan table and so long as the `lastKey` property exists continuously scan the table to retrieve all items with a maximum of 5 requests total ``` diff --git a/docs/docs/guide/Schema.md b/docs/docs/guide/Schema.md index 89f8452ed..16b2ffa0c 100644 --- a/docs/docs/guide/Schema.md +++ b/docs/docs/guide/Schema.md @@ -6,8 +6,8 @@ The `options` parameter is an optional object with the following options: | Name | Type | Default | Information |---|---|---|---| -| `saveUnknown` | array \| boolean | false | This setting lets you specify if the schema should allow properties not defined in the schema. If you pass `true` in for this option all unknown properties will be allowed. If you pass in an array of strings, only properties that are included in that array will be allowed. If you pass in an array of strings, you can use `*` to indicate a wildcard nested property one level deep, or `**` to indicate a wildcard nested property infinite levels deep (ex. `["person.*", "friend.**"]` will allow you store a property `person` with 1 level of unknown properties and `friend` with infinitely nested level unknown properties). If you retrieve documents from DynamoDB with `saveUnknown` enabled, all custom Dynamoose types will be returned as the underlying DynamoDB type (ex. Dates will be returned as a Number representing number of milliseconds since Jan 1 1970). -| `timestamps` | boolean \| object | false | This setting lets you indicate to Dynamoose that you would like it to handle storing timestamps in your documents for both creation and most recent update times. If you pass in an object for this setting you must specify two keys `createdAt` & `updatedAt`, each with a value of a string or array of strings being the name of the attribute(s) for each timestamp. If you pass in `null` for either of those keys that specific timestamp won't be added to the schema. If you set this option to `true` it will use the default attribute names of `createdAt` & `updatedAt`. +| `saveUnknown` | array \| boolean | false | This setting lets you specify if the schema should allow properties not defined in the schema. If you pass `true` in for this option all unknown properties will be allowed. If you pass in an array of strings, only properties that are included in that array will be allowed. If you pass in an array of strings, you can use `*` to indicate a wildcard nested property one level deep, or `**` to indicate a wildcard nested property infinite levels deep (ex. `["person.*", "friend.**"]` will allow you store a property `person` with 1 level of unknown properties and `friend` with infinitely nested level unknown properties). If you retrieve items from DynamoDB with `saveUnknown` enabled, all custom Dynamoose types will be returned as the underlying DynamoDB type (ex. Dates will be returned as a Number representing number of milliseconds since Jan 1 1970). +| `timestamps` | boolean \| object | false | This setting lets you indicate to Dynamoose that you would like it to handle storing timestamps in your items for both creation and most recent update times. If you pass in an object for this setting you must specify two keys `createdAt` & `updatedAt`, each with a value of a string or array of strings being the name of the attribute(s) for each timestamp. If you pass in `null` for either of those keys that specific timestamp won't be added to the schema. If you set this option to `true` it will use the default attribute names of `createdAt` & `updatedAt`. ```js const dynamoose = require("dynamoose"); @@ -90,7 +90,7 @@ const schema = new dynamoose.Schema({ | [`dynamoose.NULL`](Dynamoose#dynamoosenull) | False | NULL | False | False | | | | Schema | False | M | True | True | | This will be converted to an Object type. | | Model | Only if no `rangeKey` for model's schema | S \| N \| B \| M | True | If `rangeKey` in model's schema | | Model Types are setup a bit differently. [Read below](#model-types) for more information. | -| Combine | False | S | True | False | **attributes** - [string] - The attributes to store in the combine attribute.\n**seperator** - string (default: `,`) - The string used to seperate the attributes in the combine attribute. | When running `Model.update` you must update all the attributes in the combine attributes array, or none of them. This is to ensure your combine method remains in sync with your overall document. | +| Combine | False | S | True | False | **attributes** - [string] - The attributes to store in the combine attribute.\n**seperator** - string (default: `,`) - The string used to seperate the attributes in the combine attribute. | When running `Model.update` you must update all the attributes in the combine attributes array, or none of them. This is to ensure your combine method remains in sync with your overall item. | | Constant | False | S \| N \| BOOL | True | False | **value** - string \| number \| boolean - The value this attribute should always match. | | Set's are different from Array's since they require each item in the Set be unique. If you use a Set, it will use the underlying JavaScript Set instance as opposed to an Array. If you use a set you will define the type surrounded by brackets in the [`schema`](#schema-object--array) setting. For example to define a string set you would do something like: @@ -106,7 +106,7 @@ Set's are different from Array's since they require each item in the Set be uniq When using `saveUnknown` with a set, the type recognized by Dynamoose will be the underlying JavaScript Set constructor. If you have a set type defined in your schema the underlying type will be an Array. -Custom Dynamoose Types are not supported with the `saveUnknown` property. For example, if you wish you retrieve a document with a Date type, Dynamoose will return it as a number if that property does not exist in the schema and `saveUnknown` is enabled for that given property. +Custom Dynamoose Types are not supported with the `saveUnknown` property. For example, if you wish you retrieve a item with a Date type, Dynamoose will return it as a number if that property does not exist in the schema and `saveUnknown` is enabled for that given property. For types that are `Nested Types`, you must define a [`schema` setting](#schema-object--array) that includes the nested schema for that given attribute. @@ -122,7 +122,7 @@ In the event you have multiple types that match (Date & Number, Set & Array, mul ```js { - "date": [Number, Date] // If you pass in a Date instance, it will use Date, otherwise it will use Number. All retrieved documents from DynamoDB will use Number since there is no difference in the underlying storage of Number vs Date + "date": [Number, Date] // If you pass in a Date instance, it will use Date, otherwise it will use Number. All retrieved items from DynamoDB will use Number since there is no difference in the underlying storage of Number vs Date } ``` @@ -160,7 +160,7 @@ const gameSchema = new dynamoose.Schema({ }); ``` -You can then set documents to be a Document instance of that Model, a value of the `hashKey` (if you don't have a `rangeKey`), or an object representing the `hashKey` & `rangeKey` (if you have a `rangeKey`). +You can then set items to be a Item instance of that Model, a value of the `hashKey` (if you don't have a `rangeKey`), or an object representing the `hashKey` & `rangeKey` (if you have a `rangeKey`). ```js const dad = new User({ @@ -194,7 +194,7 @@ const user = new User({ }); ``` -You can then call [`document.populate`](Document#documentpopulatesettings-callback) to populate the instances with the documents. +You can then call [`item.populate`](Item#itempopulatesettings-callback) to populate the instances with the items. ```js const user = await User.get(2); // {"id": 2, "name": "Bob", "parent": 1} @@ -372,7 +372,7 @@ You can set this property to always use the `default` value, even if a value is ### validate: value | RegExp | function | async function -You can set a validation on an attribute to ensure the value passes a given validation before saving the document. In the event you set this to be a function or async function, Dynamoose will pass in the value for you to validate as the parameter to your function. Validation will only be run if the item exists in the document. If you'd like to force validation to be run every time (even if the attribute doesn't exist in the document) you can enable `required`. +You can set a validation on an attribute to ensure the value passes a given validation before saving the item. In the event you set this to be a function or async function, Dynamoose will pass in the value for you to validate as the parameter to your function. Validation will only be run if the item exists in the item. If you'd like to force validation to be run every time (even if the attribute doesn't exist in the item) you can enable `required`. ```js { @@ -408,14 +408,14 @@ You can set a validation on an attribute to ensure the value passes a given vali "validate": async (val) => { const networkRequest = await axios(`https://emailvalidator.com/${val}`); return networkRequest.data.isValid; - } // Any object that is saved will call this function and run the network request with `val` equal to the value set for the `email` property, and only allow the document to be saved if the `isValid` property in the response is true + } // Any object that is saved will call this function and run the network request with `val` equal to the value set for the `email` property, and only allow the item to be saved if the `isValid` property in the response is true } } ``` ### required: boolean -You can set an attribute to be required when saving documents to DynamoDB. By default this setting is `false`. +You can set an attribute to be required when saving items to DynamoDB. By default this setting is `false`. In the event the parent object is undefined and `required` is set to `false` on that parent attribute, the required check will not be run on child attributes. @@ -460,7 +460,7 @@ This property is not a replacement for `required`. If the value is undefined or ### get: function | async function -You can use a get function on an attribute to be run whenever retrieving a document from DynamoDB. This function will only be run if the item exists in the document. Dynamoose will pass the DynamoDB value into this function and you must return the new value that you want Dynamoose to return to the application. +You can use a get function on an attribute to be run whenever retrieving a item from DynamoDB. This function will only be run if the item exists in the item. Dynamoose will pass the DynamoDB value into this function and you must return the new value that you want Dynamoose to return to the application. ```js { @@ -473,7 +473,7 @@ You can use a get function on an attribute to be run whenever retrieving a docum ### set: function | async function -You can use a set function on an attribute to be run whenever saving a document to DynamoDB. This function will only be run if the attribute exists in the document. Dynamoose will pass the value you provide into this function and you must return the new value that you want Dynamoose to save to DynamoDB. +You can use a set function on an attribute to be run whenever saving a item to DynamoDB. This function will only be run if the attribute exists in the item. Dynamoose will pass the value you provide into this function and you must return the new value that you want Dynamoose to save to DynamoDB. ```js { @@ -484,7 +484,7 @@ You can use a set function on an attribute to be run whenever saving a document } ``` -Unlike `get` this method will additionally pass in the original value as the second parameter (if avaiable). Internally Dynamoose uses the [`document.original()`](Document#documentoriginal) method to access the original value. This means that using [`Model.batchPut`](Model#modelbatchputdocuments-settings-callback), [`Model.update`](Model#modelupdatekey-updateobj-settings-callback) or any other document save method that does not have access to [`document.original()`](Document#documentoriginal) this second parameter will be `undefined`. +Unlike `get` this method will additionally pass in the original value as the second parameter (if avaiable). Internally Dynamoose uses the [`item.original()`](Item#itemoriginal) method to access the original value. This means that using [`Model.batchPut`](Model#modelbatchputitems-settings-callback), [`Model.update`](Model#modelupdatekey-updateobj-settings-callback) or any other item save method that does not have access to [`item.original()`](Item#itemoriginal) this second parameter will be `undefined`. ```js { diff --git a/docs/docs/guide/Transaction.md b/docs/docs/guide/Transaction.md index d6904f5cb..070f4e6a7 100644 --- a/docs/docs/guide/Transaction.md +++ b/docs/docs/guide/Transaction.md @@ -1,4 +1,4 @@ -DynamoDB supports running DynamoDB Transactions in your database. Transactions are all or nothing, meaning the entire transaction will succeed, or the entire transaction will fail. In the event the transaction fails, the state of the database will be the exact same as if the transaction didn't take place at all (ex. no documents will have been modified). You are also able to run these Transactions across multiple tables. +DynamoDB supports running DynamoDB Transactions in your database. Transactions are all or nothing, meaning the entire transaction will succeed, or the entire transaction will fail. In the event the transaction fails, the state of the database will be the exact same as if the transaction didn't take place at all (ex. no items will have been modified). You are also able to run these Transactions across multiple tables. ## dynamoose.transaction(transactions[, settings][, callback]) @@ -6,7 +6,7 @@ You can use `dynamoose.transaction` to run a transaction on your table. This met The `transactions` parameter must be an array of transaction objects that will be passed into the DynamoDB API. The standard way to get these is by using the [`Model.transaction` methods](Model#modeltransaction). You can also pass Promises into this array that will resolve to an object, and Dynamoose will wait for those promises to be resolved before proceeding. -If you pass RAW objects into the `transactions` array (without using `Model.transaction`) you must be sure that the given model has been registered with Dynamoose at some point so we can convert the response to Document instances of that Model. +If you pass RAW objects into the `transactions` array (without using `Model.transaction`) you must be sure that the given model has been registered with Dynamoose at some point so we can convert the response to Item instances of that Model. This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. @@ -14,7 +14,7 @@ You can also pass in an object for the optional `settings` parameter that is an | Name | Description | Type | Default | |------|-------------|------|---------| -| return | What the function should return. Can be `documents`, or `request`. In the event this is set to `request` the request Dynamoose will make to DynamoDB will be returned, and no request to DynamoDB will be made. | String | `documents` | +| return | What the function should return. Can be `items`, or `request`. In the event this is set to `request` the request Dynamoose will make to DynamoDB will be returned, and no request to DynamoDB will be made. | String | `items` | | type | If Dynamoose should use `transactGetItems` or `transactWriteItems` to make the transaction call. | String | By default, if all `transactions` objects are `Get`, `transactGetItems` will be run, otherwise `transactWriteItems` will be used. | ```js diff --git a/docs/docs/other/FAQ.md b/docs/docs/other/FAQ.md index 943855202..48f7463e7 100644 --- a/docs/docs/other/FAQ.md +++ b/docs/docs/other/FAQ.md @@ -14,8 +14,8 @@ The following is a chart of IAM permissions you need in order to run Dynamoose f | Model.update | `updateItem` | | | Model.delete | `deleteItem` | | | Model.batchDelete | `batchWriteItem` | | -| document.save | `putItem` | | -| document.delete | `deleteItem` | | +| item.save | `putItem` | | +| item.delete | `deleteItem` | | | dynamoose.transaction | `transactGetItems`, `transactWriteItems` | | ## Why is it recommended to set `create` & `waitForActive` model options to false for production environments? diff --git a/docs/sidebars.js b/docs/sidebars.js index 2dec171d6..e71a074d9 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -17,7 +17,7 @@ module.exports = { "items": [ "guide/Schema", "guide/Model", - "guide/Document", + "guide/Item", "guide/Condition", "guide/Query", "guide/Scan", diff --git a/lib/Condition.ts b/lib/Condition.ts index 8642e1288..1a5619e1d 100644 --- a/lib/Condition.ts +++ b/lib/Condition.ts @@ -1,4 +1,4 @@ -import {Document} from "./Document"; +import {Item} from "./Item"; import CustomError = require("./Error"); import utils = require("./utils"); const OR = Symbol("OR"); @@ -235,8 +235,8 @@ Condition.prototype.requestObject = function (this: Condition, settings: Conditi return Object.entries((this.settings.raw as ObjectType).ExpressionAttributeValues).reduce((obj, entry) => { const [key, value] = entry; // TODO: we should fix this so that we can do `isDynamoItem(value)` - if (!Document.isDynamoObject({"key": value})) { - obj.ExpressionAttributeValues[key] = Document.objectToDynamo(value, {"type": "value"}); + if (!Item.isDynamoObject({"key": value})) { + obj.ExpressionAttributeValues[key] = Item.objectToDynamo(value, {"type": "value"}); } return obj; }, this.settings.raw as ObjectType); @@ -276,7 +276,7 @@ Condition.prototype.requestObject = function (this: Condition, settings: Conditi }, []).join("."); } const toDynamo = (value: ObjectType): DynamoDB.AttributeValue => { - return Document.objectToDynamo(value, {"type": "value"}); + return Item.objectToDynamo(value, {"type": "value"}); }; object.ExpressionAttributeValues[keys.value] = toDynamo(value); diff --git a/lib/General.ts b/lib/General.ts index f1779c4a3..3c728ea3c 100644 --- a/lib/General.ts +++ b/lib/General.ts @@ -1,4 +1,4 @@ -import {Document} from "./Document"; +import {Item} from "./Item"; import {Model} from "./Model"; // - General @@ -8,15 +8,15 @@ export type FunctionType = (...args: any[]) => any; export type DeepPartial = {[P in keyof T]?: DeepPartial}; // - Dynamoose -interface ModelDocumentConstructor { +interface ModelItemConstructor { new (object: {[key: string]: any}): T; Model: Model; } -export type ModelType = T & Model & ModelDocumentConstructor; +export type ModelType = T & Model & ModelItemConstructor; -// This represents a document array. This is used for the output of functions such as `scan`, `query`, and `batchGet`. These functions can extend this property to add additional properties or functions. However this represents the shared properties/functions for all document arrays. -export interface DocumentArray extends Array { - populate: () => Promise>; +// This represents a item array. This is used for the output of functions such as `scan`, `query`, and `batchGet`. These functions can extend this property to add additional properties or functions. However this represents the shared properties/functions for all item arrays. +export interface ItemArray extends Array { + populate: () => Promise>; toJSON: () => ObjectType; } diff --git a/lib/Document.ts b/lib/Item.ts similarity index 75% rename from lib/Document.ts rename to lib/Item.ts index 5172fc713..712fffd5a 100644 --- a/lib/Document.ts +++ b/lib/Item.ts @@ -13,28 +13,28 @@ import DynamoDB = require("@aws-sdk/client-dynamodb"); import {ValueType} from "./Schema"; import {CallbackType, ObjectType} from "./General"; import {SerializerOptions} from "./Serializer"; -import {PopulateDocument, PopulateSettings} from "./Populate"; +import {PopulateItem, PopulateSettings} from "./Populate"; import {Condition} from "./Condition"; -export interface DocumentSaveSettings { +export interface ItemSaveSettings { overwrite?: boolean; - return?: "request" | "document"; + return?: "request" | "Item"; condition?: Condition; } -export interface DocumentSettings { +export interface ItemSettings { type?: "fromDynamo" | "toDynamo"; } -// Document represents an item in a Model that is either pending (not saved) or saved -export class Document { - constructor (model: Model, object?: AttributeMap | ObjectType, settings?: DocumentSettings) { - const documentObject = Document.isDynamoObject(object) ? aws.converter().unmarshall(object) : object; - Object.keys(documentObject).forEach((key) => this[key] = documentObject[key]); +// Item represents an item in a Model that is either pending (not saved) or saved +export class Item { + constructor (model: Model, object?: AttributeMap | ObjectType, settings?: ItemSettings) { + const itemObject = Item.isDynamoObject(object) ? aws.converter().unmarshall(object) : object; + Object.keys(itemObject).forEach((key) => this[key] = itemObject[key]); Object.defineProperty(this, internalProperties, { "configurable": false, "value": {} }); - this[internalProperties].originalObject = JSON.parse(JSON.stringify(documentObject)); + this[internalProperties].originalObject = JSON.parse(JSON.stringify(itemObject)); this[internalProperties].originalSettings = {...settings}; Object.defineProperty(this, "model", { @@ -48,7 +48,7 @@ export class Document { } // Internal - model?: Model; + model?: Model; static objectToDynamo (object: ObjectType): AttributeMap; static objectToDynamo (object: any, settings: {type: "value"}): DynamoDB.AttributeValue; static objectToDynamo (object: ObjectType, settings: {type: "object"}): AttributeMap; @@ -71,7 +71,7 @@ export class Document { } const keys = Object.keys(value); const key = keys[0]; - const nestedResult = typeof value[key] === "object" && !(value[key] instanceof Buffer) ? Array.isArray(value[key]) ? value[key].every((value) => Document.isDynamoObject(value, true)) : Document.isDynamoObject(value[key]) : true; + const nestedResult = typeof value[key] === "object" && !(value[key] instanceof Buffer) ? Array.isArray(value[key]) ? value[key].every((value) => Item.isDynamoObject(value, true)) : Item.isDynamoObject(value[key]) : true; const {Schema} = require("./Schema"); const attributeType = Schema.attributeTypes.findDynamoDBType(key); return typeof value === "object" && keys.length === 1 && attributeType && (nestedResult || Object.keys(value[key]).length === 0 || attributeType.isSet); @@ -86,14 +86,14 @@ export class Document { } } - static attributesWithSchema: (document: Document, model: Model) => Promise; - static objectFromSchema: (object: any, model: Model, settings?: DocumentObjectFromSchemaSettings) => Promise; - static prepareForObjectFromSchema: (object: any, model: Model, settings: DocumentObjectFromSchemaSettings) => any; - conformToSchema: (this: Document, settings?: DocumentObjectFromSchemaSettings) => Promise; - toDynamo: (this: Document, settings?: Partial) => Promise; + static attributesWithSchema: (item: Item, model: Model) => Promise; + static objectFromSchema: (object: any, model: Model, settings?: ItemObjectFromSchemaSettings) => Promise; + static prepareForObjectFromSchema: (object: any, model: Model, settings: ItemObjectFromSchemaSettings) => any; + conformToSchema: (this: Item, settings?: ItemObjectFromSchemaSettings) => Promise; + toDynamo: (this: Item, settings?: Partial) => Promise; // This function handles actions that should take place before every response (get, scan, query, batchGet, etc.) - async prepareForResponse (): Promise { + async prepareForResponse (): Promise { if (this.model.options.populate) { return this.populate({"properties": this.model.options.populate}); } @@ -103,11 +103,11 @@ export class Document { // Original original (): ObjectType | null { return this[internalProperties].originalSettings.type === "fromDynamo" ? this[internalProperties].originalObject : null; - // toJSON } + // toJSON toJSON (): ObjectType { - return utils.dynamoose.documentToJSON.bind(this)(); + return utils.dynamoose.itemToJSON.bind(this)(); } // Serializer @@ -116,9 +116,9 @@ export class Document { } // Delete - delete (this: Document): Promise; - delete (this: Document, callback: CallbackType): void; - delete (this: Document, callback?: CallbackType): Promise | void { + delete (this: Item): Promise; + delete (this: Item, callback: CallbackType): void; + delete (this: Item, callback?: CallbackType): Promise | void { const hashKey = this.model.getHashKey(); const rangeKey = this.model.getRangeKey(); @@ -131,13 +131,13 @@ export class Document { } // Save - save (this: Document): Promise; - save (this: Document, callback: CallbackType): void; - save (this: Document, settings: DocumentSaveSettings & {return: "request"}): Promise; - save (this: Document, settings: DocumentSaveSettings & {return: "request"}, callback: CallbackType): void; - save (this: Document, settings: DocumentSaveSettings & {return: "document"}): Promise; - save (this: Document, settings: DocumentSaveSettings & {return: "document"}, callback: CallbackType): void; - save (this: Document, settings?: DocumentSaveSettings | CallbackType | CallbackType, callback?: CallbackType | CallbackType): void | Promise { + save (this: Item): Promise; + save (this: Item, callback: CallbackType): void; + save (this: Item, settings: ItemSaveSettings & {return: "request"}): Promise; + save (this: Item, settings: ItemSaveSettings & {return: "request"}, callback: CallbackType): void; + save (this: Item, settings: ItemSaveSettings & {return: "item"}): Promise; + save (this: Item, settings: ItemSaveSettings & {return: "item"}, callback: CallbackType): void; + save (this: Item, settings?: ItemSaveSettings | CallbackType | CallbackType, callback?: CallbackType | CallbackType): void | Promise { if (typeof settings !== "object" && typeof settings !== "undefined") { callback = settings; settings = {}; @@ -148,7 +148,7 @@ export class Document { let savedItem; - const localSettings: DocumentSaveSettings = settings; + const localSettings: ItemSaveSettings = settings; const paramsPromise = this.toDynamo({"defaults": true, "validate": true, "required": true, "enum": true, "forceDefault": true, "combine": true, "saveUnknown": true, "customTypesDynamo": true, "updateTimestamps": true, "modifiers": ["set"]}).then((item) => { savedItem = item; let putItemObj: DynamoDB.PutItemInput = { @@ -189,44 +189,44 @@ export class Document { }); if (callback) { - const localCallback: CallbackType = callback as CallbackType; + const localCallback: CallbackType = callback as CallbackType; promise.then(() => { this[internalProperties].storedInDynamo = true; - const returnDocument = new this.model.Document(savedItem as any); - returnDocument[internalProperties].storedInDynamo = true; + const returnItem = new this.model.Item(savedItem as any); + returnItem[internalProperties].storedInDynamo = true; - localCallback(null, returnDocument); + localCallback(null, returnItem); }).catch((error) => callback(error)); } else { - return (async (): Promise => { + return (async (): Promise => { await promise; this[internalProperties].storedInDynamo = true; - const returnDocument = new this.model.Document(savedItem as any); - returnDocument[internalProperties].storedInDynamo = true; + const returnItem = new this.model.Item(savedItem as any); + returnItem[internalProperties].storedInDynamo = true; - return returnDocument; + return returnItem; })(); } } // Populate - populate (): Promise; - populate (callback: CallbackType): void; - populate (settings: PopulateSettings): Promise; - populate (settings: PopulateSettings, callback: CallbackType): void; - populate (...args): Promise | void { - return PopulateDocument.bind(this)(...args); + populate (): Promise; + populate (callback: CallbackType): void; + populate (settings: PopulateSettings): Promise; + populate (settings: PopulateSettings, callback: CallbackType): void; + populate (...args): Promise | void { + return PopulateItem.bind(this)(...args); } } -export class AnyDocument extends Document { +export class AnyItem extends Item { [key: string]: any; } -// This function will mutate the object passed in to run any actions to conform to the schema that cannot be achieved through non mutating methods in Document.objectFromSchema (setting timestamps, etc.) -Document.prepareForObjectFromSchema = async function(object: T, model: Model, settings: DocumentObjectFromSchemaSettings): Promise { +// This function will mutate the object passed in to run any actions to conform to the schema that cannot be achieved through non mutating methods in Item.objectFromSchema (setting timestamps, etc.) +Item.prepareForObjectFromSchema = async function(object: T, model: Model, settings: ItemObjectFromSchemaSettings): Promise { if (settings.updateTimestamps) { const schema: Schema = await model.schemaForObject(object); if (schema.settings.timestamps && settings.type === "toDynamo") { @@ -248,15 +248,15 @@ Document.prepareForObjectFromSchema = async function(object: T, model: Model< } return object; }; -// This function will return a list of attributes combining both the schema attributes with the document attributes. This also takes into account all attributes that could exist (ex. properties in sets that don't exist in document), adding the indexes for each item in the document set. +// This function will return a list of attributes combining both the schema attributes with the item attributes. This also takes into account all attributes that could exist (ex. properties in sets that don't exist in item), adding the indexes for each item in the item set. // https://stackoverflow.com/a/59928314/894067 const attributesWithSchemaCache: ObjectType = {}; -Document.attributesWithSchema = async function (document: Document, model: Model): Promise { - const schema: Schema = await model.schemaForObject(document); +Item.attributesWithSchema = async function (item: Item, model: Model): Promise { + const schema: Schema = await model.schemaForObject(item); const attributes = schema.attributes(); - const documentID = utils.object.keys(document as any).join(""); - if (attributesWithSchemaCache[documentID] && attributesWithSchemaCache[documentID][attributes.join()]) { - return attributesWithSchemaCache[documentID][attributes.join()]; + const itemID = utils.object.keys(item as any).join(""); + if (attributesWithSchemaCache[itemID] && attributesWithSchemaCache[itemID][attributes.join()]) { + return attributesWithSchemaCache[itemID][attributes.join()]; } // build a tree out of schema attributes const root = {}; @@ -296,12 +296,12 @@ Document.attributesWithSchema = async function (document: Document, model: Model }); } const out = []; - traverse(document, root, [], (val) => out.push(val.join("."))); + traverse(item, root, [], (val) => out.push(val.join("."))); const result = out.slice(1); - attributesWithSchemaCache[documentID] = {[attributes.join()]: result}; + attributesWithSchemaCache[itemID] = {[attributes.join()]: result}; return result; }; -export interface DocumentObjectFromSchemaSettings { +export interface ItemObjectFromSchemaSettings { type: "toDynamo" | "fromDynamo"; schema?: Schema; checkExpiredItem?: boolean; @@ -318,7 +318,7 @@ export interface DocumentObjectFromSchemaSettings { updateTimestamps?: boolean | {updatedAt?: boolean; createdAt?: boolean}; } // This function will return an object that conforms to the schema (removing any properties that don't exist, using default values, etc.) & throws an error if there is a typemismatch. -Document.objectFromSchema = async function (object: any, model: Model, settings: DocumentObjectFromSchemaSettings = {"type": "toDynamo"}): Promise { +Item.objectFromSchema = async function (object: any, model: Model, settings: ItemObjectFromSchemaSettings = {"type": "toDynamo"}): Promise { if (settings.checkExpiredItem && model.options.expires && ((model.options.expires as ModelExpiresSettings).items || {}).returnExpired === false && object[(model.options.expires as ModelExpiresSettings).attribute] && object[(model.options.expires as ModelExpiresSettings).attribute] * 1000 < Date.now()) { return undefined; } @@ -366,7 +366,7 @@ Document.objectFromSchema = async function (object: any, model: Model, keysToDelete.reverse().forEach((key) => utils.object.delete(returnObject, key)); if (settings.defaults || settings.forceDefault) { - await Promise.all((await Document.attributesWithSchema(returnObject, model)).map(async (key) => { + await Promise.all((await Item.attributesWithSchema(returnObject, model)).map(async (key) => { const value = utils.object.get(returnObject, key); if (value === dynamooseUndefined) { utils.object.set(returnObject, key, undefined); @@ -386,7 +386,7 @@ Document.objectFromSchema = async function (object: any, model: Model, } // Custom Types if (settings.customTypesDynamo) { - (await Document.attributesWithSchema(returnObject, model)).map((key) => { + (await Item.attributesWithSchema(returnObject, model)).map((key) => { const value = utils.object.get(returnObject, key); const isValueUndefined = typeof value === "undefined" || value === null; if (!isValueUndefined) { @@ -443,7 +443,7 @@ Document.objectFromSchema = async function (object: any, model: Model, } if (settings.modifiers) { await Promise.all(settings.modifiers.map(async (modifier) => { - return Promise.all((await Document.attributesWithSchema(returnObject, model)).map(async (key) => { + return Promise.all((await Item.attributesWithSchema(returnObject, model)).map(async (key) => { const value = utils.object.get(returnObject, key); const modifierFunction = await schema.getAttributeSettingValue(modifier, key, {"returnFunction": true, typeIndexOptionMap}); const modifierFunctionExists: boolean = Array.isArray(modifierFunction) ? modifierFunction.some((val) => Boolean(val)) : Boolean(modifierFunction); @@ -456,7 +456,7 @@ Document.objectFromSchema = async function (object: any, model: Model, })); } if (settings.validate) { - await Promise.all((await Document.attributesWithSchema(returnObject, model)).map(async (key) => { + await Promise.all((await Item.attributesWithSchema(returnObject, model)).map(async (key) => { const value = utils.object.get(returnObject, key); const isValueUndefined = typeof value === "undefined" || value === null; if (!isValueUndefined) { @@ -471,14 +471,14 @@ Document.objectFromSchema = async function (object: any, model: Model, } if (!result) { - throw new Error.ValidationError(`${key} with a value of ${value} had a validation error when trying to save the document`); + throw new Error.ValidationError(`${key} with a value of ${value} had a validation error when trying to save the item`); } } } })); } if (settings.required) { - let attributesToCheck = await Document.attributesWithSchema(returnObject, model); + let attributesToCheck = await Item.attributesWithSchema(returnObject, model); if (settings.required === "nested") { attributesToCheck = attributesToCheck.filter((attribute) => utils.object.keys(returnObject).find((key) => attribute.startsWith(key))); } @@ -502,7 +502,7 @@ Document.objectFromSchema = async function (object: any, model: Model, })); } if (settings.enum) { - await Promise.all((await Document.attributesWithSchema(returnObject, model)).map(async (key) => { + await Promise.all((await Item.attributesWithSchema(returnObject, model)).map(async (key) => { const value = utils.object.get(returnObject, key); const isValueUndefined = typeof value === "undefined" || value === null; if (!isValueUndefined) { @@ -516,28 +516,28 @@ Document.objectFromSchema = async function (object: any, model: Model, return returnObject; }; -Document.prototype.toDynamo = async function (this: Document, settings: Partial = {}): Promise { - const newSettings: DocumentObjectFromSchemaSettings = { +Item.prototype.toDynamo = async function (this: Item, settings: Partial = {}): Promise { + const newSettings: ItemObjectFromSchemaSettings = { ...settings, "type": "toDynamo" }; - await Document.prepareForObjectFromSchema(this, this.model, newSettings); - const object = await Document.objectFromSchema(this, this.model, newSettings); - return Document.objectToDynamo(object); + await Item.prepareForObjectFromSchema(this, this.model, newSettings); + const object = await Item.objectFromSchema(this, this.model, newSettings); + return Item.objectToDynamo(object); }; -// This function will modify the document to conform to the Schema -Document.prototype.conformToSchema = async function (this: Document, settings: DocumentObjectFromSchemaSettings = {"type": "fromDynamo"}): Promise { - let document = this; +// This function will modify the item to conform to the Schema +Item.prototype.conformToSchema = async function (this: Item, settings: ItemObjectFromSchemaSettings = {"type": "fromDynamo"}): Promise { + let item = this; if (settings.type === "fromDynamo") { - document = await this.prepareForResponse(); + item = await this.prepareForResponse(); } - await Document.prepareForObjectFromSchema(document, document.model, settings); - const expectedObject = await Document.objectFromSchema(document, document.model, settings); + await Item.prepareForObjectFromSchema(item, item.model, settings); + const expectedObject = await Item.objectFromSchema(item, item.model, settings); if (!expectedObject) { return expectedObject; } const expectedKeys = Object.keys(expectedObject); - Object.keys(document).forEach((key) => { + Object.keys(item).forEach((key) => { if (!expectedKeys.includes(key)) { delete this[key]; } else if (this[key] !== expectedObject[key]) { diff --git a/lib/DocumentRetriever.ts b/lib/ItemRetriever.ts similarity index 78% rename from lib/DocumentRetriever.ts rename to lib/ItemRetriever.ts index 9bc71a3d8..a99bfe12b 100644 --- a/lib/DocumentRetriever.ts +++ b/lib/ItemRetriever.ts @@ -3,25 +3,25 @@ import CustomError = require("./Error"); import utils = require("./utils"); import {Condition, ConditionInitalizer, BasicOperators, ConditionStorageTypeNested} from "./Condition"; import {Model} from "./Model"; -import {Document} from "./Document"; -import {CallbackType, ObjectType, DocumentArray, SortOrder} from "./General"; -import {PopulateDocuments} from "./Populate"; +import {Item} from "./Item"; +import {CallbackType, ObjectType, ItemArray, SortOrder} from "./General"; +import {PopulateItems} from "./Populate"; -enum DocumentRetrieverTypes { +enum ItemRetrieverTypes { scan = "scan", query = "query" } -interface DocumentRetrieverTypeInformation { - type: DocumentRetrieverTypes; +interface ItemRetrieverTypeInformation { + type: ItemRetrieverTypes; pastTense: string; } -// DocumentRetriever is used for both Scan and Query since a lot of the code is shared between the two -// type DocumentRetriever = BasicOperators; -abstract class DocumentRetriever { +// ItemRetriever is used for both Scan and Query since a lot of the code is shared between the two +// type ItemRetriever = BasicOperators; +abstract class ItemRetriever { internalSettings?: { - model: Model; - typeInformation: DocumentRetrieverTypeInformation; + model: Model; + typeInformation: ItemRetrieverTypeInformation; }; settings: { condition: Condition; @@ -35,15 +35,15 @@ abstract class DocumentRetriever { parallel?: number; sort?: SortOrder; }; - getRequest: (this: DocumentRetriever) => Promise; - all: (this: DocumentRetriever, delay?: number, max?: number) => DocumentRetriever; - limit: (this: DocumentRetriever, value: number) => DocumentRetriever; - startAt: (this: DocumentRetriever, value: ObjectType) => DocumentRetriever; - attributes: (this: DocumentRetriever, value: string[]) => DocumentRetriever; - count: (this: DocumentRetriever) => DocumentRetriever; - consistent: (this: DocumentRetriever) => DocumentRetriever; - using: (this: DocumentRetriever, value: string) => DocumentRetriever; - exec (this: DocumentRetriever, callback?: any): any { + getRequest: (this: ItemRetriever) => Promise; + all: (this: ItemRetriever, delay?: number, max?: number) => ItemRetriever; + limit: (this: ItemRetriever, value: number) => ItemRetriever; + startAt: (this: ItemRetriever, value: ObjectType) => ItemRetriever; + attributes: (this: ItemRetriever, value: string[]) => ItemRetriever; + count: (this: ItemRetriever) => ItemRetriever; + consistent: (this: ItemRetriever) => ItemRetriever; + using: (this: ItemRetriever, value: string) => ItemRetriever; + exec (this: ItemRetriever, callback?: any): any { let timesRequested = 0; const prepareForReturn = async (result): Promise => { if (Array.isArray(result)) { @@ -55,13 +55,13 @@ abstract class DocumentRetriever { [`${this.internalSettings.typeInformation.pastTense}Count`]: result[`${utils.capitalize_first_letter(this.internalSettings.typeInformation.pastTense)}Count`] }; } - const array: any = (await Promise.all(result.Items.map(async (item) => await new this.internalSettings.model.Document(item, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "modifiers": ["get"], "type": "fromDynamo"})))).filter((a) => Boolean(a)); - array.lastKey = result.LastEvaluatedKey ? Array.isArray(result.LastEvaluatedKey) ? result.LastEvaluatedKey.map((key) => this.internalSettings.model.Document.fromDynamo(key)) : this.internalSettings.model.Document.fromDynamo(result.LastEvaluatedKey) : undefined; + const array: any = (await Promise.all(result.Items.map(async (item) => await new this.internalSettings.model.Item(item, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "modifiers": ["get"], "type": "fromDynamo"})))).filter((a) => Boolean(a)); + array.lastKey = result.LastEvaluatedKey ? Array.isArray(result.LastEvaluatedKey) ? result.LastEvaluatedKey.map((key) => this.internalSettings.model.Item.fromDynamo(key)) : this.internalSettings.model.Item.fromDynamo(result.LastEvaluatedKey) : undefined; array.count = result.Count; array[`${this.internalSettings.typeInformation.pastTense}Count`] = result[`${utils.capitalize_first_letter(this.internalSettings.typeInformation.pastTense)}Count`]; array[`times${utils.capitalize_first_letter(this.internalSettings.typeInformation.pastTense)}`] = timesRequested; - array["populate"] = PopulateDocuments; - array["toJSON"] = utils.dynamoose.documentToJSON; + array["populate"] = PopulateItems; + array["toJSON"] = utils.dynamoose.itemToJSON; return array; }; const promise = this.internalSettings.model.pendingTaskPromise().then(() => this.getRequest()).then((request) => { @@ -117,7 +117,7 @@ abstract class DocumentRetriever { } } - constructor (model: Model, typeInformation: DocumentRetrieverTypeInformation, object?: ConditionInitalizer) { + constructor (model: Model, typeInformation: ItemRetrieverTypeInformation, object?: ConditionInitalizer) { this.internalSettings = {model, typeInformation}; let condition: Condition; @@ -136,14 +136,14 @@ abstract class DocumentRetriever { Object.entries(Condition.prototype).forEach((prototype) => { const [key, func] = prototype; if (key !== "requestObject") { - DocumentRetriever.prototype[key] = function (this: DocumentRetriever, ...args): DocumentRetriever { + ItemRetriever.prototype[key] = function (this: ItemRetriever, ...args): ItemRetriever { func.bind(this.settings.condition)(...args); return this; }; } }); -DocumentRetriever.prototype.getRequest = async function (this: DocumentRetriever): Promise { +ItemRetriever.prototype.getRequest = async function (this: ItemRetriever): Promise { const object: any = { ...this.settings.condition.requestObject({"conditionString": "FilterExpression", "conditionStringType": "array"}), "TableName": this.internalSettings.model.name @@ -153,7 +153,7 @@ DocumentRetriever.prototype.getRequest = async function (this: DocumentRetriever object.Limit = this.settings.limit; } if (this.settings.startAt) { - object.ExclusiveStartKey = Document.isDynamoObject(this.settings.startAt) ? this.settings.startAt : this.internalSettings.model.Document.objectToDynamo(this.settings.startAt); + object.ExclusiveStartKey = Item.isDynamoObject(this.settings.startAt) ? this.settings.startAt : this.internalSettings.model.Item.objectToDynamo(this.settings.startAt); } const indexes = await this.internalSettings.model.getIndexes(); function canUseIndexOfTable (hashKeyOfTable, rangeKeyOfTable, chart: ConditionStorageTypeNested): boolean { @@ -289,15 +289,15 @@ DocumentRetriever.prototype.getRequest = async function (this: DocumentRetriever return object; }; -interface DocumentRetrieverResponse extends DocumentArray { +interface ItemRetrieverResponse extends ItemArray { lastKey?: ObjectType; count: number; } -export interface ScanResponse extends DocumentRetrieverResponse { +export interface ScanResponse extends ItemRetrieverResponse { scannedCount: number; timesScanned: number; } -export interface QueryResponse extends DocumentRetrieverResponse { +export interface QueryResponse extends ItemRetrieverResponse { queriedCount: number; timesQueried: number; } @@ -316,23 +316,23 @@ const settings: (SettingDefinition | string)[] = [ {"name": "using", "settingsName": "index"} ]; settings.forEach((item) => { - DocumentRetriever.prototype[(item as SettingDefinition).name || (item as string)] = function (value): DocumentRetriever { + ItemRetriever.prototype[(item as SettingDefinition).name || (item as string)] = function (value): ItemRetriever { const key: string = (item as SettingDefinition).settingsName || (item as SettingDefinition).name || (item as string); this.settings[key] = (item as SettingDefinition).boolean ? !this.settings[key] : value; return this; }; }); -DocumentRetriever.prototype.all = function (this: DocumentRetriever, delay = 0, max = 0): DocumentRetriever { +ItemRetriever.prototype.all = function (this: ItemRetriever, delay = 0, max = 0): ItemRetriever { this.settings.all = {delay, max}; return this; }; -export interface Scan extends DocumentRetriever, BasicOperators> { +export interface Scan extends ItemRetriever, BasicOperators> { exec(): Promise>; exec(callback: CallbackType, any>): void; } -export class Scan extends DocumentRetriever { +export class Scan extends ItemRetriever { exec (callback?: CallbackType, any>): Promise> | void { return super.exec(callback); } @@ -342,17 +342,17 @@ export class Scan extends DocumentRetriever { return this; } - constructor (model: Model, object?: ConditionInitalizer) { - super(model, {"type": DocumentRetrieverTypes.scan, "pastTense": "scanned"}, object); + constructor (model: Model, object?: ConditionInitalizer) { + super(model, {"type": ItemRetrieverTypes.scan, "pastTense": "scanned"}, object); } } -export interface Query extends DocumentRetriever, BasicOperators> { +export interface Query extends ItemRetriever, BasicOperators> { exec(): Promise>; exec(callback: CallbackType, any>): void; } -export class Query extends DocumentRetriever { +export class Query extends ItemRetriever { exec (callback?: CallbackType, any>): Promise> | void { return super.exec(callback); } @@ -362,7 +362,7 @@ export class Query extends DocumentRetriever { return this; } - constructor (model: Model, object?: ConditionInitalizer) { - super(model, {"type": DocumentRetrieverTypes.query, "pastTense": "queried"}, object); + constructor (model: Model, object?: ConditionInitalizer) { + super(model, {"type": ItemRetrieverTypes.query, "pastTense": "queried"}, object); } } diff --git a/lib/Model/index.ts b/lib/Model/index.ts index 221264c22..81b6eb902 100644 --- a/lib/Model/index.ts +++ b/lib/Model/index.ts @@ -1,16 +1,16 @@ import CustomError = require("../Error"); import {Schema, SchemaDefinition, DynamoDBSetTypeResult, ValueType, IndexItem} from "../Schema"; -import {Document as DocumentCarrier, DocumentSaveSettings, DocumentSettings, DocumentObjectFromSchemaSettings, AnyDocument} from "../Document"; +import {Item as ItemCarrier, ItemSaveSettings, ItemSettings, ItemObjectFromSchemaSettings, AnyItem} from "../Item"; import utils = require("../utils"); import ddb = require("../aws/ddb/internal"); import Internal = require("../Internal"); import {Serializer, SerializerOptions} from "../Serializer"; import {Condition, ConditionInitalizer} from "../Condition"; -import {Scan, Query} from "../DocumentRetriever"; -import {CallbackType, ObjectType, FunctionType, DocumentArray, ModelType, DeepPartial} from "../General"; +import {Scan, Query} from "../ItemRetriever"; +import {CallbackType, ObjectType, FunctionType, ItemArray, ModelType, DeepPartial} from "../General"; import {custom as customDefaults, original as originalDefaults} from "./defaults"; import {ModelIndexChangeType} from "../utils/dynamoose/index_changes"; -import {PopulateDocuments} from "../Populate"; +import {PopulateItems} from "../Populate"; import {AttributeMap} from "../Types"; import DynamoDB = require("@aws-sdk/client-dynamodb"); import {GetTransactionInput, CreateTransactionInput, DeleteTransactionInput, UpdateTransactionInput, ConditionTransactionInput} from "../Transaction"; @@ -58,14 +58,14 @@ type ConditionTransactionResult = Promise; export interface GetTransaction { (key: InputKey): GetTransactionResult; (key: InputKey, settings?: ModelGetSettings): GetTransactionResult; - (key: InputKey, settings: ModelGetSettings & {return: "document"}): GetTransactionResult; + (key: InputKey, settings: ModelGetSettings & {return: "item"}): GetTransactionResult; (key: InputKey, settings: ModelGetSettings & {return: "request"}): GetTransactionResult; } export interface CreateTransaction { - (document: ObjectType): CreateTransactionResult; - (document: ObjectType, settings: DocumentSaveSettings & {return: "request"}): CreateTransactionResult; - (document: ObjectType, settings: DocumentSaveSettings & {return: "document"}): CreateTransactionResult; - (document: ObjectType, settings?: DocumentSaveSettings): CreateTransactionResult; + (item: ObjectType): CreateTransactionResult; + (item: ObjectType, settings: ItemSaveSettings & {return: "request"}): CreateTransactionResult; + (item: ObjectType, settings: ItemSaveSettings & {return: "item"}): CreateTransactionResult; + (item: ObjectType, settings?: ItemSaveSettings): CreateTransactionResult; } export interface DeleteTransaction { (key: InputKey): DeleteTransactionResult; @@ -76,7 +76,7 @@ export interface DeleteTransaction { export interface UpdateTransaction { (obj: ObjectType): CreateTransactionResult; (keyObj: ObjectType, updateObj: ObjectType): UpdateTransactionResult; - (keyObj: ObjectType, updateObj: ObjectType, settings: ModelUpdateSettings & {"return": "document"}): UpdateTransactionResult; + (keyObj: ObjectType, updateObj: ObjectType, settings: ModelUpdateSettings & {"return": "item"}): UpdateTransactionResult; (keyObj: ObjectType, updateObj: ObjectType, settings: ModelUpdateSettings & {"return": "request"}): UpdateTransactionResult; (keyObj: ObjectType, updateObj?: ObjectType, settings?: ModelUpdateSettings): UpdateTransactionResult; } @@ -93,7 +93,7 @@ type TransactionType = { }; // Utility functions -async function getTableDetails (model: Model, settings: {allowError?: boolean; forceRefresh?: boolean} = {}): Promise { +async function getTableDetails (model: Model, settings: {allowError?: boolean; forceRefresh?: boolean} = {}): Promise { const func = async (): Promise => { const tableDetails: DynamoDB.DescribeTableOutput = await ddb("describeTable", {"TableName": model.name}); model.latestTableDetails = tableDetails; // eslint-disable-line require-atomic-updates @@ -110,14 +110,14 @@ async function getTableDetails (model: Model, settings: {allowE return model.latestTableDetails; } -async function createTableRequest (model: Model): Promise { +async function createTableRequest (model: Model): Promise { return { "TableName": model.name, ...utils.dynamoose.get_provisioned_throughput(model.options), ...await model.getCreateTableAttributeParams() }; } -async function createTable (model: Model): Promise Promise)> { +async function createTable (model: Model): Promise Promise)> { if (((await getTableDetails(model, {"allowError": true}) || {}).Table || {}).TableStatus === "ACTIVE") { model.alreadyCreated = true; return (): Promise => Promise.resolve.bind(Promise)(); @@ -125,7 +125,7 @@ async function createTable (model: Model): Promise): Promise { +async function updateTimeToLive (model: Model): Promise { let ttlDetails; async function updateDetails (): Promise { @@ -159,7 +159,7 @@ async function updateTimeToLive (model: Model): Promise { break; } } -function waitForActive (model: Model, forceRefreshOnFirstAttempt = true) { +function waitForActive (model: Model, forceRefreshOnFirstAttempt = true) { return (): Promise => new Promise((resolve, reject) => { const start = Date.now(); async function check (count: number): Promise { @@ -185,7 +185,7 @@ function waitForActive (model: Model, forceRefreshOnFirstAttemp check(0); }); } -async function updateTable (model: Model): Promise { +async function updateTable (model: Model): Promise { const updateAll = typeof model.options.update === "boolean" && model.options.update; // Throughput if (updateAll || (model.options.update as ModelUpdateOptions[]).includes(ModelUpdateOptions.throughput)) { @@ -225,7 +225,7 @@ async function updateTable (model: Model): Promise { } interface ModelGetSettings { - return?: "document" | "request"; + return?: "item" | "request"; attributes?: string[]; consistent?: boolean; } @@ -237,14 +237,14 @@ interface ModelBatchPutSettings { return?: "response" | "request"; } interface ModelUpdateSettings { - return?: "document" | "request"; + return?: "item" | "request"; condition?: Condition; } -interface ModelBatchGetDocumentsResponse extends DocumentArray { +interface ModelBatchGetItemsResponse extends ItemArray { unprocessedKeys: ObjectType[]; } interface ModelBatchGetSettings { - return?: "documents" | "request"; + return?: "items" | "request"; attributes?: string[]; } interface ModelBatchDeleteSettings { @@ -252,7 +252,7 @@ interface ModelBatchDeleteSettings { } // Model represents one DynamoDB table -export class Model { +export class Model { constructor (name: string, schema: Schema | SchemaDefinition | (Schema | SchemaDefinition)[], options: ModelOptionsOptional) { this.options = utils.combine_objects(options, customDefaults.get(), originalDefaults) as ModelOptions; this.name = `${this.options.prefix}${name}${this.options.suffix}`; @@ -304,7 +304,7 @@ export class Model { this.alreadyCreated = false; // Represents if the table in DynamoDB was created prior to initalization. This will only be updated if `create` is true. this.pendingTasks = []; // Represents an array of promise resolver functions to be called when Model.ready gets set to true (at the end of the setup flow) this.latestTableDetails = null; // Stores the latest result from `describeTable` for the given table - this.pendingTaskPromise = (): Promise => { // Returns a promise that will be resolved after the Model is ready. This is used in all Model operations (Model.get, Document.save) to `await` at the beginning before running the AWS SDK method to ensure the Model is setup before running actions on it. + this.pendingTaskPromise = (): Promise => { // Returns a promise that will be resolved after the Model is ready. This is used in all Model operations (Model.get, Item.save) to `await` at the beginning before running the AWS SDK method to ensure the Model is setup before running actions on it. return this.ready ? Promise.resolve() : new Promise((resolve) => { this.pendingTasks.push(resolve); }); @@ -337,23 +337,23 @@ export class Model { this.pendingTasks.forEach((task) => task()); this.pendingTasks = []; }); - const self: Model = this; - class Document extends DocumentCarrier { - static Model: Model; - constructor (object: AttributeMap | ObjectType = {}, settings: DocumentSettings = {}) { + const self: Model = this; + class Item extends ItemCarrier { + static Model: Model; + constructor (object: AttributeMap | ObjectType = {}, settings: ItemSettings = {}) { super(self, object, settings); } } - Document.Model = self; + Item.Model = self; this.serializer = new Serializer(); - this.Document = Document; - (this.Document as any).table = { + this.Item = Item; + (this.Item as any).table = { "create": { "request": (): Promise => createTableRequest(this) } }; - (this.Document as any).transaction = [ + (this.Item as any).transaction = [ // `function` Default: `this[key]` // `settingsIndex` Default: 1 // `dynamoKey` Default: utils.capitalize_first_letter(key) @@ -365,7 +365,7 @@ export class Model { return response; }}, {"key": "condition", "settingsIndex": -1, "dynamoKey": "ConditionCheck", "function": (key: string, condition: Condition): DynamoDB.ConditionCheck => ({ - "Key": this.Document.objectToDynamo(this.convertObjectToKey(key)), + "Key": this.Item.objectToDynamo(this.convertObjectToKey(key)), "TableName": this.name, ...condition ? condition.requestObject() : {} } as any)} @@ -409,10 +409,10 @@ export class Model { latestTableDetails: DynamoDB.DescribeTableOutput; pendingTaskPromise: () => Promise; static defaults: ModelOptions; - Document: typeof DocumentCarrier; + Item: typeof ItemCarrier; scan: (object?: ConditionInitalizer) => Scan; query: (object?: ConditionInitalizer) => Query; - methods: { document: { set: (name: string, fn: FunctionType) => void; delete: (name: string) => void }; set: (name: string, fn: FunctionType) => void; delete: (name: string) => void }; + methods: { item: { set: (name: string, fn: FunctionType) => void; delete: (name: string) => void }; set: (name: string, fn: FunctionType) => void; delete: (name: string) => void }; transaction: TransactionType; // This function returns the best matched schema for the given object input @@ -463,34 +463,34 @@ export class Model { } // Batch Get - batchGet (keys: InputKey[]): Promise>; - batchGet (keys: InputKey[], callback: CallbackType, any>): void; + batchGet (keys: InputKey[]): Promise>; + batchGet (keys: InputKey[], callback: CallbackType, any>): void; batchGet (keys: InputKey[], settings: ModelBatchGetSettings & {"return": "request"}): DynamoDB.BatchGetItemInput; batchGet (keys: InputKey[], settings: ModelBatchGetSettings & {"return": "request"}, callback: CallbackType): void; - batchGet (keys: InputKey[], settings: ModelBatchGetSettings): Promise>; - batchGet (keys: InputKey[], settings: ModelBatchGetSettings, callback: CallbackType, any>): void; - batchGet (keys: InputKey[], settings: ModelBatchGetSettings & {"return": "documents"}): Promise>; - batchGet (keys: InputKey[], settings: ModelBatchGetSettings & {"return": "documents"}, callback: CallbackType, any>): void; - batchGet (keys: InputKey[], settings?: ModelBatchGetSettings | CallbackType, any> | CallbackType, callback?: CallbackType, any> | CallbackType): void | DynamoDB.BatchGetItemInput | Promise> { + batchGet (keys: InputKey[], settings: ModelBatchGetSettings): Promise>; + batchGet (keys: InputKey[], settings: ModelBatchGetSettings, callback: CallbackType, any>): void; + batchGet (keys: InputKey[], settings: ModelBatchGetSettings & {"return": "items"}): Promise>; + batchGet (keys: InputKey[], settings: ModelBatchGetSettings & {"return": "items"}, callback: CallbackType, any>): void; + batchGet (keys: InputKey[], settings?: ModelBatchGetSettings | CallbackType, any> | CallbackType, callback?: CallbackType, any> | CallbackType): void | DynamoDB.BatchGetItemInput | Promise> { if (typeof settings === "function") { callback = settings; - settings = {"return": "documents"}; + settings = {"return": "items"}; } if (typeof settings === "undefined") { - settings = {"return": "documents"}; + settings = {"return": "items"}; } const keyObjects = keys.map((key) => this.convertObjectToKey(key)); - const documentify = (document: AttributeMap): Promise => new this.Document(document as any, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "modifiers": ["get"], "type": "fromDynamo"}); - const prepareResponse = async (response: DynamoDB.BatchGetItemOutput): Promise> => { - const tmpResult = await Promise.all(response.Responses[this.name].map((item) => documentify(item))); + const itemify = (item: AttributeMap): Promise => new this.Item(item as any, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "modifiers": ["get"], "type": "fromDynamo"}); + const prepareResponse = async (response: DynamoDB.BatchGetItemOutput): Promise> => { + const tmpResult = await Promise.all(response.Responses[this.name].map((item) => itemify(item))); const unprocessedArray = response.UnprocessedKeys[this.name] ? response.UnprocessedKeys[this.name].Keys : []; - const tmpResultUnprocessed = await Promise.all(unprocessedArray.map((item) => this.Document.fromDynamo(item))); - const startArray: ModelBatchGetDocumentsResponse = Object.assign([], { + const tmpResultUnprocessed = await Promise.all(unprocessedArray.map((item) => this.Item.fromDynamo(item))); + const startArray: ModelBatchGetItemsResponse = Object.assign([], { "unprocessedKeys": [], - "populate": PopulateDocuments, - "toJSON": utils.dynamoose.documentToJSON + "populate": PopulateItems, + "toJSON": utils.dynamoose.itemToJSON }); return keyObjects.reduce((result, key) => { const keyProperties = Object.keys(key); @@ -510,7 +510,7 @@ export class Model { const params: DynamoDB.BatchGetItemInput = { "RequestItems": { [this.name]: { - "Keys": keyObjects.map((key) => this.Document.objectToDynamo(key)) + "Keys": keyObjects.map((key) => this.Item.objectToDynamo(key)) } } }; @@ -529,26 +529,26 @@ export class Model { const promise = this.pendingTaskPromise().then(() => ddb("batchGetItem", params)); if (callback) { - const localCallback: CallbackType = callback as CallbackType; + const localCallback: CallbackType = callback as CallbackType; promise.then((response) => prepareResponse(response)).then((response) => localCallback(null, response)).catch((error) => localCallback(error)); } else { - return (async (): Promise> => { + return (async (): Promise> => { const response = await promise; - return prepareResponse(response) as Promise>; + return prepareResponse(response) as Promise>; })(); } } // Batch Put - batchPut (documents: ObjectType[]): Promise<{"unprocessedItems": ObjectType[]}>; - batchPut (documents: ObjectType[], callback: CallbackType<{"unprocessedItems": ObjectType[]}, any>): void; - batchPut (documents: ObjectType[], settings: ModelBatchPutSettings & {"return": "request"}): Promise; - batchPut (documents: ObjectType[], settings: ModelBatchPutSettings & {"return": "request"}, callback: CallbackType): void; - batchPut (documents: ObjectType[], settings: ModelBatchPutSettings): Promise<{"unprocessedItems": ObjectType[]}>; - batchPut (documents: ObjectType[], settings: ModelBatchPutSettings, callback: CallbackType<{"unprocessedItems": ObjectType[]}, any>): void; - batchPut (documents: ObjectType[], settings: ModelBatchPutSettings & {"return": "response"}): Promise<{"unprocessedItems": ObjectType[]}>; - batchPut (documents: ObjectType[], settings: ModelBatchPutSettings & {"return": "response"}, callback: CallbackType<{"unprocessedItems": ObjectType[]}, any>): void; - batchPut (documents: ObjectType[], settings?: ModelBatchPutSettings | CallbackType<{"unprocessedItems": ObjectType[]}, any> | CallbackType, callback?: CallbackType<{"unprocessedItems": ObjectType[]}, any> | CallbackType): void | Promise { + batchPut (items: ObjectType[]): Promise<{"unprocessedItems": ObjectType[]}>; + batchPut (items: ObjectType[], callback: CallbackType<{"unprocessedItems": ObjectType[]}, any>): void; + batchPut (items: ObjectType[], settings: ModelBatchPutSettings & {"return": "request"}): Promise; + batchPut (items: ObjectType[], settings: ModelBatchPutSettings & {"return": "request"}, callback: CallbackType): void; + batchPut (items: ObjectType[], settings: ModelBatchPutSettings): Promise<{"unprocessedItems": ObjectType[]}>; + batchPut (items: ObjectType[], settings: ModelBatchPutSettings, callback: CallbackType<{"unprocessedItems": ObjectType[]}, any>): void; + batchPut (items: ObjectType[], settings: ModelBatchPutSettings & {"return": "response"}): Promise<{"unprocessedItems": ObjectType[]}>; + batchPut (items: ObjectType[], settings: ModelBatchPutSettings & {"return": "response"}, callback: CallbackType<{"unprocessedItems": ObjectType[]}, any>): void; + batchPut (items: ObjectType[], settings?: ModelBatchPutSettings | CallbackType<{"unprocessedItems": ObjectType[]}, any> | CallbackType, callback?: CallbackType<{"unprocessedItems": ObjectType[]}, any> | CallbackType): void | Promise { if (typeof settings === "function") { callback = settings; settings = {"return": "response"}; @@ -559,11 +559,11 @@ export class Model { const prepareResponse = async (response: DynamoDB.BatchWriteItemOutput): Promise<{unprocessedItems: ObjectType[]}> => { const unprocessedArray = response.UnprocessedItems && response.UnprocessedItems[this.name] ? response.UnprocessedItems[this.name] : []; - const tmpResultUnprocessed = await Promise.all(unprocessedArray.map((item) => this.Document.fromDynamo(item.PutRequest.Item))); - return documents.reduce((result: {unprocessedItems: ObjectType[]}, document) => { - const item = tmpResultUnprocessed.find((item) => Object.keys(document).every((keyProperty) => item[keyProperty] === document[keyProperty])); - if (item) { - result.unprocessedItems.push(item); + const tmpResultUnprocessed = await Promise.all(unprocessedArray.map((item) => this.Item.fromDynamo(item.PutRequest.Item))); + return items.reduce((result: {unprocessedItems: ObjectType[]}, item) => { + const unprocessedItem = tmpResultUnprocessed.find((searchItem) => Object.keys(item).every((keyProperty) => searchItem[keyProperty] === item[keyProperty])); + if (unprocessedItem) { + result.unprocessedItems.push(unprocessedItem); } return result; }, {"unprocessedItems": []}) as {unprocessedItems: ObjectType[]}; @@ -571,9 +571,9 @@ export class Model { const paramsPromise: Promise = (async (): Promise => ({ "RequestItems": { - [this.name]: await Promise.all(documents.map(async (document) => ({ + [this.name]: await Promise.all(items.map(async (item) => ({ "PutRequest": { - "Item": await new this.Document(document as any).toDynamo({"defaults": true, "validate": true, "required": true, "enum": true, "forceDefault": true, "saveUnknown": true, "combine": true, "customTypesDynamo": true, "updateTimestamps": true, "modifiers": ["set"]}) + "Item": await new this.Item(item as any).toDynamo({"defaults": true, "validate": true, "required": true, "enum": true, "forceDefault": true, "saveUnknown": true, "combine": true, "customTypesDynamo": true, "updateTimestamps": true, "modifiers": ["set"]}) } }))) } @@ -622,7 +622,7 @@ export class Model { const prepareResponse = async (response: DynamoDB.BatchWriteItemOutput): Promise<{unprocessedItems: ObjectType[]}> => { const unprocessedArray = response.UnprocessedItems && response.UnprocessedItems[this.name] ? response.UnprocessedItems[this.name] : []; - const tmpResultUnprocessed = await Promise.all(unprocessedArray.map((item) => this.Document.fromDynamo(item.DeleteRequest.Key))); + const tmpResultUnprocessed = await Promise.all(unprocessedArray.map((item) => this.Item.fromDynamo(item.DeleteRequest.Key))); return keyObjects.reduce((result, key) => { const item = tmpResultUnprocessed.find((item) => Object.keys(key).every((keyProperty) => item[keyProperty] === key[keyProperty])); if (item) { @@ -636,7 +636,7 @@ export class Model { "RequestItems": { [this.name]: keyObjects.map((key) => ({ "DeleteRequest": { - "Key": this.Document.objectToDynamo(key) + "Key": this.Item.objectToDynamo(key) } })) } @@ -672,17 +672,17 @@ export class Model { update (keyObj: ObjectType, updateObj: Partial, settings: ModelUpdateSettings & {"return": "request"}, callback: CallbackType): void; update (keyObj: ObjectType, updateObj: Partial, settings: ModelUpdateSettings): Promise; update (keyObj: ObjectType, updateObj: Partial, settings: ModelUpdateSettings, callback: CallbackType): void; - update (keyObj: ObjectType, updateObj: Partial, settings: ModelUpdateSettings & {"return": "document"}): Promise; - update (keyObj: ObjectType, updateObj: Partial, settings: ModelUpdateSettings & {"return": "document"}, callback: CallbackType): void; + update (keyObj: ObjectType, updateObj: Partial, settings: ModelUpdateSettings & {"return": "item"}): Promise; + update (keyObj: ObjectType, updateObj: Partial, settings: ModelUpdateSettings & {"return": "item"}, callback: CallbackType): void; update (keyObj: ObjectType, updateObj?: Partial | CallbackType | CallbackType, settings?: ModelUpdateSettings | CallbackType | CallbackType, callback?: CallbackType | CallbackType): void | Promise | Promise { if (typeof updateObj === "function") { - callback = updateObj as CallbackType; // TODO: fix this, for some reason `updateObj` has a type of Function which is forcing us to type cast it + callback = updateObj as CallbackType; // TODO: fix this, for some reason `updateObj` has a type of Function which is forcing us to type cast it updateObj = null; - settings = {"return": "document"}; + settings = {"return": "item"}; } if (typeof settings === "function") { callback = settings; - settings = {"return": "document"}; + settings = {"return": "item"}; } if (!updateObj) { const hashKeyName = this.getHashKey(); @@ -699,7 +699,7 @@ export class Model { } } if (typeof settings === "undefined") { - settings = {"return": "document"}; + settings = {"return": "item"}; } const schema: Schema = this.schemas[0]; // TODO: fix this to get correct schema @@ -737,7 +737,7 @@ export class Model { const attributeExists = schema.attributes().includes(subKey); const dynamooseUndefined = require("../index").UNDEFINED; if (!updateType.attributeOnly && subValue !== dynamooseUndefined) { - subValue = (await this.Document.objectFromSchema({[subKey]: dynamoType === "L" && !Array.isArray(subValue) ? [subValue] : subValue}, this, {"type": "toDynamo", "customTypesDynamo": true, "saveUnknown": true, ...updateType.objectFromSchemaSettings} as any))[subKey]; + subValue = (await this.Item.objectFromSchema({[subKey]: dynamoType === "L" && !Array.isArray(subValue) ? [subValue] : subValue}, this, {"type": "toDynamo", "customTypesDynamo": true, "saveUnknown": true, ...updateType.objectFromSchemaSettings} as any))[subKey]; } if (subValue === dynamooseUndefined || subValue === undefined) { @@ -789,8 +789,8 @@ export class Model { }, {}) }; - const documentFunctionSettings: DocumentObjectFromSchemaSettings = {"updateTimestamps": {"updatedAt": true}, "customTypesDynamo": true, "type": "toDynamo"}; - const defaultObjectFromSchema = await this.Document.objectFromSchema(await this.Document.prepareForObjectFromSchema({}, this, documentFunctionSettings), this, documentFunctionSettings); + const itemFunctionSettings: ItemObjectFromSchemaSettings = {"updateTimestamps": {"updatedAt": true}, "customTypesDynamo": true, "type": "toDynamo"}; + const defaultObjectFromSchema = await this.Item.objectFromSchema(await this.Item.prepareForObjectFromSchema({}, this, itemFunctionSettings), this, itemFunctionSettings); Object.keys(defaultObjectFromSchema).forEach((key) => { const value = defaultObjectFromSchema[key]; const updateType = updateTypes.find((a) => a.name === "$SET"); @@ -868,7 +868,7 @@ export class Model { } }); - returnObject.ExpressionAttributeValues = this.Document.objectToDynamo(returnObject.ExpressionAttributeValues); + returnObject.ExpressionAttributeValues = this.Item.objectToDynamo(returnObject.ExpressionAttributeValues); if (Object.keys(returnObject.ExpressionAttributeValues).length === 0) { delete returnObject.ExpressionAttributeValues; } @@ -887,10 +887,10 @@ export class Model { }; }; - const documentify = (document): Promise => new this.Document(document, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "type": "fromDynamo"}); + const itemify = (item): Promise => new this.Item(item, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "type": "fromDynamo"}); const localSettings: ModelUpdateSettings = settings; const updateItemParamsPromise: Promise = this.pendingTaskPromise().then(async () => ({ - "Key": this.Document.objectToDynamo(keyObj), + "Key": this.Item.objectToDynamo(keyObj), "ReturnValues": "ALL_NEW", ...utils.merge_objects.main({"combineMethod": "object_combine"})(localSettings.condition ? localSettings.condition.requestObject({"index": {"start": index, "set": (i): void => { index = i; @@ -909,31 +909,31 @@ export class Model { const promise = updateItemParamsPromise.then((params) => ddb("updateItem", params)); if (callback) { - promise.then((response) => response.Attributes ? documentify(response.Attributes) : undefined).then((response) => callback(null, response)).catch((error) => callback(error)); + promise.then((response) => response.Attributes ? itemify(response.Attributes) : undefined).then((response) => callback(null, response)).catch((error) => callback(error)); } else { return (async (): Promise => { const response = await promise; - return response.Attributes ? await documentify(response.Attributes) : undefined; + return response.Attributes ? await itemify(response.Attributes) : undefined; })(); } } // Create - create (document: Partial): Promise; - create (document: Partial, callback: CallbackType): void; - create (document: Partial, settings: DocumentSaveSettings & {return: "request"}): Promise; - create (document: Partial, settings: DocumentSaveSettings & {return: "request"}, callback: CallbackType): void; - create (document: Partial, settings: DocumentSaveSettings): Promise; - create (document: Partial, settings: DocumentSaveSettings, callback: CallbackType): void; - create (document: Partial, settings: DocumentSaveSettings & {return: "document"}): Promise; - create (document: Partial, settings: DocumentSaveSettings & {return: "document"}, callback: CallbackType): void; - create (document: Partial, settings?: DocumentSaveSettings | CallbackType | CallbackType, callback?: CallbackType | CallbackType): void | Promise | Promise { + create (item: Partial): Promise; + create (item: Partial, callback: CallbackType): void; + create (item: Partial, settings: ItemSaveSettings & {return: "request"}): Promise; + create (item: Partial, settings: ItemSaveSettings & {return: "request"}, callback: CallbackType): void; + create (item: Partial, settings: ItemSaveSettings): Promise; + create (item: Partial, settings: ItemSaveSettings, callback: CallbackType): void; + create (item: Partial, settings: ItemSaveSettings & {return: "item"}): Promise; + create (item: Partial, settings: ItemSaveSettings & {return: "item"}, callback: CallbackType): void; + create (item: Partial, settings?: ItemSaveSettings | CallbackType | CallbackType, callback?: CallbackType | CallbackType): void | Promise | Promise { if (typeof settings === "function" && !callback) { callback = settings; settings = {}; } - return new this.Document(document as any).save({"overwrite": false, ...settings} as any, callback as any); + return new this.Item(item as any).save({"overwrite": false, ...settings} as any, callback as any); } // Delete @@ -958,7 +958,7 @@ export class Model { } let deleteItemParams: DynamoDB.DeleteItemInput = { - "Key": this.Document.objectToDynamo(this.convertObjectToKey(key)), + "Key": this.Item.objectToDynamo(this.convertObjectToKey(key)), "TableName": this.name }; @@ -996,22 +996,22 @@ export class Model { get (key: InputKey, settings: ModelGetSettings & {return: "request"}, callback: CallbackType): void; get (key: InputKey, settings: ModelGetSettings): Promise; get (key: InputKey, settings: ModelGetSettings, callback: CallbackType): void; - get (key: InputKey, settings: ModelGetSettings & {return: "document"}): Promise; - get (key: InputKey, settings: ModelGetSettings & {return: "document"}, callback: CallbackType): void; + get (key: InputKey, settings: ModelGetSettings & {return: "item"}): Promise; + get (key: InputKey, settings: ModelGetSettings & {return: "item"}, callback: CallbackType): void; get (key: InputKey, settings?: ModelGetSettings | CallbackType | CallbackType, callback?: CallbackType | CallbackType): void | DynamoDB.GetItemInput | Promise { if (typeof settings === "function") { callback = settings; - settings = {"return": "document"}; + settings = {"return": "item"}; } if (typeof settings === "undefined") { - settings = {"return": "document"}; + settings = {"return": "item"}; } - const conformToSchemaSettings: DocumentObjectFromSchemaSettings = {"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "modifiers": ["get"], "type": "fromDynamo"}; - const documentify = (document: AttributeMap): Promise => new this.Document(document as any, {"type": "fromDynamo"}).conformToSchema(conformToSchemaSettings); + const conformToSchemaSettings: ItemObjectFromSchemaSettings = {"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "modifiers": ["get"], "type": "fromDynamo"}; + const itemify = (item: AttributeMap): Promise => new this.Item(item as any, {"type": "fromDynamo"}).conformToSchema(conformToSchemaSettings); const getItemParams: DynamoDB.GetItemInput = { - "Key": this.Document.objectToDynamo(this.convertObjectToKey(key)), + "Key": this.Item.objectToDynamo(this.convertObjectToKey(key)), "TableName": this.name }; if (settings.consistent !== undefined && settings.consistent !== null) { @@ -1033,41 +1033,41 @@ export class Model { const promise = this.pendingTaskPromise().then(() => ddb("getItem", getItemParams)); if (callback) { - const localCallback: CallbackType = callback as CallbackType; - promise.then((response) => response.Item ? documentify(response.Item) : undefined).then((response) => localCallback(null, response)).catch((error) => callback(error)); + const localCallback: CallbackType = callback as CallbackType; + promise.then((response) => response.Item ? itemify(response.Item) : undefined).then((response) => localCallback(null, response)).catch((error) => callback(error)); } else { return (async (): Promise => { const response = await promise; - return response.Item ? await documentify(response.Item) : undefined; + return response.Item ? await itemify(response.Item) : undefined; })(); } } // Serialize Many - serializeMany (documentsArray: ModelType[] = [], nameOrOptions: SerializerOptions | string): any { - return this.serializer._serializeMany(documentsArray, nameOrOptions); + serializeMany (itemsArray: ModelType[] = [], nameOrOptions: SerializerOptions | string): any { + return this.serializer._serializeMany(itemsArray, nameOrOptions); } } Model.defaults = originalDefaults; -Model.prototype.scan = function (object?: ConditionInitalizer): Scan { +Model.prototype.scan = function (object?: ConditionInitalizer): Scan { return new Scan(this, object); }; -Model.prototype.query = function (object?: ConditionInitalizer): Query { +Model.prototype.query = function (object?: ConditionInitalizer): Query { return new Query(this, object); }; // Methods -const customMethodFunctions = (type: "model" | "document"): {set: (name: string, fn: FunctionType) => void; delete: (name: string) => void} => { - const entryPoint = (self: Model): DocumentCarrier | typeof DocumentCarrier => type === "document" ? self.Document.prototype : self.Document; +const customMethodFunctions = (type: "model" | "item"): {set: (name: string, fn: FunctionType) => void; delete: (name: string) => void} => { + const entryPoint = (self: Model): ItemCarrier | typeof ItemCarrier => type === "item" ? self.Item.prototype : self.Item; return { "set": function (name: string, fn): void { - const self: Model = this as any; + const self: Model = this as any; if (!entryPoint(self)[name] || entryPoint(self)[name][Internal.General.internalProperties] && entryPoint(self)[name][Internal.General.internalProperties].type === "customMethod") { entryPoint(self)[name] = function (...args): Promise { - const bindObject = type === "document" ? this : self.Document; + const bindObject = type === "item" ? this : self.Item; const cb = typeof args[args.length - 1] === "function" ? args[args.length - 1] : undefined; if (cb) { const result = fn.bind(bindObject)(...args); @@ -1093,7 +1093,7 @@ const customMethodFunctions = (type: "model" | "document"): {set: (name: string, } }, "delete": function (name: string): void { - const self: Model = this as any; + const self: Model = this as any; if (entryPoint(self)[name] && entryPoint(self)[name][Internal.General.internalProperties] && entryPoint(self)[name][Internal.General.internalProperties].type === "customMethod") { entryPoint(self)[name] = undefined; } @@ -1102,5 +1102,5 @@ const customMethodFunctions = (type: "model" | "document"): {set: (name: string, }; Model.prototype.methods = { ...customMethodFunctions("model"), - "document": customMethodFunctions("document") + "item": customMethodFunctions("item") }; diff --git a/lib/ModelStore.ts b/lib/ModelStore.ts index 96ea6a438..a9bbec080 100644 --- a/lib/ModelStore.ts +++ b/lib/ModelStore.ts @@ -1,11 +1,11 @@ import CustomError = require("./Error"); import {Model} from "./Model"; -import {Document} from "./Document"; +import {Item} from "./Item"; let aliases: {[name: string]: string} = {}; -let models: {[name: string]: Model} = {}; +let models: {[name: string]: Model} = {}; -const returnObject = (input: Model | string): Model | never => { +const returnObject = (input: Model | string): Model | never => { if (input instanceof Model) { models[input.originalName] = input; aliases[input.name] = input.originalName; diff --git a/lib/Populate.ts b/lib/Populate.ts index 23ddebab6..89df63a4d 100644 --- a/lib/Populate.ts +++ b/lib/Populate.ts @@ -1,5 +1,5 @@ -import {Document} from "./Document"; -import {DocumentArray, CallbackType} from "./General"; +import {Item} from "./Item"; +import {ItemArray, CallbackType} from "./General"; import utils = require("./utils"); import {DynamoDBTypeResult, DynamoDBSetTypeResult, Schema} from "./Schema"; @@ -11,12 +11,12 @@ interface PopulateInternalSettings { parentKey?: string; } -export function PopulateDocument (this: Document): Promise; -export function PopulateDocument (this: Document, callback: CallbackType): void; -export function PopulateDocument (this: Document, settings: PopulateSettings): Promise; -export function PopulateDocument (this: Document, settings: PopulateSettings, callback: CallbackType): void; -export function PopulateDocument (this: Document, settings: PopulateSettings, callback: CallbackType | null, internalSettings?: PopulateInternalSettings): void; -export function PopulateDocument (this: Document, settings?: PopulateSettings | CallbackType, callback?: CallbackType | null, internalSettings?: PopulateInternalSettings): Promise | void { +export function PopulateItem (this: Item): Promise; +export function PopulateItem (this: Item, callback: CallbackType): void; +export function PopulateItem (this: Item, settings: PopulateSettings): Promise; +export function PopulateItem (this: Item, settings: PopulateSettings, callback: CallbackType): void; +export function PopulateItem (this: Item, settings: PopulateSettings, callback: CallbackType | null, internalSettings?: PopulateInternalSettings): void; +export function PopulateItem (this: Item, settings?: PopulateSettings | CallbackType, callback?: CallbackType | null, internalSettings?: PopulateInternalSettings): Promise | void { if (typeof settings === "function") { callback = settings; settings = {}; @@ -40,13 +40,13 @@ export function PopulateDocument (this: Document, settings?: PopulateSettings | const typeDetail: DynamoDBTypeResult | DynamoDBSetTypeResult = Array.isArray(typeDetails) ? (typeDetails as any).find((detail) => detail.name === "Model") : typeDetails; const {typeSettings} = typeDetail; // TODO: `subModel` is currently any, we should fix that - const subModel = typeof typeSettings.model === "object" ? model.Document as any : typeSettings.model; + const subModel = typeof typeSettings.model === "object" ? model.Item as any : typeSettings.model; prop = prop.endsWith(".0") ? prop.substring(0, prop.length - 2) : prop; - const documentPropValue = utils.object.get(this as any, prop); - const doesPopulatePropertyExist = !(typeof documentPropValue === "undefined" || documentPropValue === null); - if (!doesPopulatePropertyExist || documentPropValue instanceof subModel) { + const itemPropValue = utils.object.get(this as any, prop); + const doesPopulatePropertyExist = !(typeof itemPropValue === "undefined" || itemPropValue === null); + if (!doesPopulatePropertyExist || itemPropValue instanceof subModel) { return; } const key: string = [internalSettings.parentKey, prop].filter((a) => Boolean(a)).join("."); @@ -57,16 +57,16 @@ export function PopulateDocument (this: Document, settings?: PopulateSettings | return; } - const isArray = Array.isArray(documentPropValue); - const isSet = documentPropValue instanceof Set; + const isArray = Array.isArray(itemPropValue); + const isSet = itemPropValue instanceof Set; if (isArray || isSet) { - const subDocuments = await Promise.all([...documentPropValue as any].map((val) => subModel.get(val))); - const saveDocuments = await Promise.all(subDocuments.map((doc) => PopulateDocument.bind(doc)(localSettings, null, {"parentKey": key}))); - utils.object.set(this as any, prop, saveDocuments); + const subItems = await Promise.all([...itemPropValue as any].map((val) => subModel.get(val))); + const saveItems = await Promise.all(subItems.map((doc) => PopulateItem.bind(doc)(localSettings, null, {"parentKey": key}))); + utils.object.set(this as any, prop, saveItems); } else { - const subDocument = await subModel.get(documentPropValue); - const saveDocument: Document = await PopulateDocument.bind(subDocument)(localSettings, null, {"parentKey": key}); - utils.object.set(this as any, prop, saveDocument); + const subItem = await subModel.get(itemPropValue); + const saveItem: Item = await PopulateItem.bind(subItem)(localSettings, null, {"parentKey": key}); + utils.object.set(this as any, prop, saveItem); } })); }); @@ -74,31 +74,31 @@ export function PopulateDocument (this: Document, settings?: PopulateSettings | if (callback) { promise.then(() => callback(null, this)).catch((err) => callback(err)); } else { - return (async (): Promise => { + return (async (): Promise => { await promise; return this; })(); } } -export function PopulateDocuments (this: DocumentArray): Promise>; -export function PopulateDocuments (this: DocumentArray, callback: CallbackType, any>): void; -export function PopulateDocuments (this: DocumentArray, settings: PopulateSettings): Promise>; -export function PopulateDocuments (this: DocumentArray, settings: PopulateSettings, callback: CallbackType, any>): void; -export function PopulateDocuments (this: DocumentArray, settings?: PopulateSettings | CallbackType, any>, callback?: CallbackType, any>): Promise> | void { +export function PopulateItems (this: ItemArray): Promise>; +export function PopulateItems (this: ItemArray, callback: CallbackType, any>): void; +export function PopulateItems (this: ItemArray, settings: PopulateSettings): Promise>; +export function PopulateItems (this: ItemArray, settings: PopulateSettings, callback: CallbackType, any>): void; +export function PopulateItems (this: ItemArray, settings?: PopulateSettings | CallbackType, any>, callback?: CallbackType, any>): Promise> | void { if (typeof settings === "function") { callback = settings; settings = {}; } - const promise = Promise.all(this.map(async (document, index) => { - this[index] = await PopulateDocument.bind(document)(settings); + const promise = Promise.all(this.map(async (item, index) => { + this[index] = await PopulateItem.bind(item)(settings); })); if (callback) { promise.then(() => callback(null, this)).catch((err) => callback(err)); } else { - return (async (): Promise> => { + return (async (): Promise> => { await promise; return this; })(); diff --git a/lib/Schema.ts b/lib/Schema.ts index e9fa2d090..83696cc90 100644 --- a/lib/Schema.ts +++ b/lib/Schema.ts @@ -1,7 +1,7 @@ import CustomError = require("./Error"); import utils = require("./utils"); import Internal = require("./Internal"); -import {Document, DocumentObjectFromSchemaSettings} from "./Document"; +import {Item, ItemObjectFromSchemaSettings} from "./Item"; import {Model} from "./Model"; import DynamoDB = require("@aws-sdk/client-dynamodb"); import {ModelType, ObjectType} from "./General"; @@ -11,7 +11,7 @@ export interface DynamoDBSetTypeResult { name: string; dynamicName?: (() => string); dynamodbType: string; // TODO: This should probably be an enum - isOfType: (value: ValueType, type?: "toDynamo" | "fromDynamo", settings?: Partial) => boolean; + isOfType: (value: ValueType, type?: "toDynamo" | "fromDynamo", settings?: Partial) => boolean; isSet: true; customType?: any; typeSettings?: AttributeDefinitionTypeSettings; @@ -100,7 +100,7 @@ class DynamoDBType implements DynamoDBTypeCreationObject { "name": `${this.name} Set`, "isSet": true, "dynamodbType": `${dynamodbType}S`, - "isOfType": (val: ValueType, type: "toDynamo" | "fromDynamo", settings: Partial = {}): boolean => { + "isOfType": (val: ValueType, type: "toDynamo" | "fromDynamo", settings: Partial = {}): boolean => { if (type === "toDynamo") { return !settings.saveUnknown && Array.isArray(val) && val.every((subValue) => result.isOfType(subValue)) || val instanceof Set && [...val].every((subValue) => result.isOfType(subValue)); } else { @@ -192,7 +192,7 @@ const attributeTypesMain: DynamoDBType[] = ((): DynamoDBType[] => { return rangeKey ? "M" : model.schemas[0].getAttributeType(hashKey); }, "set": (typeSettings?: AttributeDefinitionTypeSettings): boolean => { return !typeSettings.model.Model.getRangeKey(); - }, "jsType": {"func": (val): boolean => val.prototype instanceof Document}, "customType": { + }, "jsType": {"func": (val): boolean => val.prototype instanceof Item}, "customType": { "functions": (typeSettings?: AttributeDefinitionTypeSettings): {toDynamo: (val: any) => any; fromDynamo: (val: any) => any; isOfType: (val: any, type: "toDynamo" | "fromDynamo") => boolean} => ({ "toDynamo": (val: any): any => { const model = typeSettings.model.Model; @@ -227,7 +227,7 @@ const attributeTypes: (DynamoDBTypeResult | DynamoDBSetTypeResult)[] = utils.arr type SetValueType = {wrapperName: "Set"; values: ValueType[]; type: string /* TODO: should probably make this an enum */}; type GeneralValueType = string | boolean | number | Buffer | Date; export type ValueType = GeneralValueType | {[key: string]: ValueType} | ValueType[] | SetValueType; -type AttributeType = string | StringConstructor | BooleanConstructor | NumberConstructor | typeof Buffer | DateConstructor | ObjectConstructor | ArrayConstructor | SetConstructor | symbol | Schema | ModelType; +type AttributeType = string | StringConstructor | BooleanConstructor | NumberConstructor | typeof Buffer | DateConstructor | ObjectConstructor | ArrayConstructor | SetConstructor | symbol | Schema | ModelType; export interface TimestampObject { createdAt?: string | string[]; @@ -246,7 +246,7 @@ interface IndexDefinition { } interface AttributeDefinitionTypeSettings { storage?: "miliseconds" | "seconds"; - model?: ModelType; + model?: ModelType; attributes?: string[]; seperator?: string; value?: string | boolean | number; @@ -280,7 +280,7 @@ export class Schema { settings: SchemaSettings; schemaObject: SchemaDefinition; attributes: (object?: ObjectType) => string[]; - async getCreateTableAttributeParams (model: Model): Promise> { + async getCreateTableAttributeParams (model: Model): Promise> { const hashKey = this.getHashKey(); const AttributeDefinitions = [ { @@ -341,7 +341,7 @@ export class Schema { return Array.isArray(typeDetails) ? (typeDetails as any).map((detail) => detail.dynamodbType) : typeDetails.dynamodbType; } catch (e) { if (settings?.unknownAttributeAllowed && e.message === `Invalid Attribute: ${key}` && value) { - return Object.keys((Document as any).objectToDynamo(value, {"type": "value"}))[0]; + return Object.keys((Item as any).objectToDynamo(value, {"type": "value"}))[0]; } else { throw e; } @@ -461,7 +461,7 @@ export class Schema { getSettingValue: (setting: string) => any; getAttributeTypeDetails: (key: string, settings?: { standardKey?: boolean; typeIndexOptionMap?: {} }) => DynamoDBTypeResult | DynamoDBSetTypeResult | DynamoDBTypeResult[] | DynamoDBSetTypeResult[]; getAttributeValue: (key: string, settings?: { standardKey?: boolean; typeIndexOptionMap?: {} }) => AttributeDefinition; - getIndexes: (model: Model) => Promise<{ GlobalSecondaryIndexes?: IndexItem[]; LocalSecondaryIndexes?: IndexItem[] }>; + getIndexes: (model: Model) => Promise<{ GlobalSecondaryIndexes?: IndexItem[]; LocalSecondaryIndexes?: IndexItem[] }>; getIndexRangeKeyAttributes: () => Promise<{ attribute: string }[]>; constructor (object: SchemaDefinition, settings: SchemaSettings = {}) { @@ -626,7 +626,7 @@ Schema.prototype.getRangeKey = function (this: Schema): string | void { Schema.prototype.requiredCheck = async function (this: Schema, key: string, value: ValueType): Promise { const isRequired = await this.getAttributeSettingValue("required", key); if ((typeof value === "undefined" || value === null) && (Array.isArray(isRequired) ? isRequired.some((val) => Boolean(val)) : isRequired)) { - throw new CustomError.ValidationError(`${key} is a required property but has no value when trying to save document`); + throw new CustomError.ValidationError(`${key} is a required property but has no value when trying to save item`); } }; @@ -662,7 +662,7 @@ export interface IndexItem { Projection: {ProjectionType: "KEYS_ONLY" | "INCLUDE" | "ALL"; NonKeyAttributes?: string[]}; ProvisionedThroughput?: {"ReadCapacityUnits": number; "WriteCapacityUnits": number}; // TODO: this was copied from get_provisioned_throughput. We should change this to be an actual interface } -Schema.prototype.getIndexes = async function (this: Schema, model: Model): Promise<{GlobalSecondaryIndexes?: IndexItem[]; LocalSecondaryIndexes?: IndexItem[]}> { +Schema.prototype.getIndexes = async function (this: Schema, model: Model): Promise<{GlobalSecondaryIndexes?: IndexItem[]; LocalSecondaryIndexes?: IndexItem[]}> { return (await this.getIndexAttributes()).reduce((accumulator, currentValue) => { const indexValue = currentValue.index; const attributeValue = currentValue.attribute; @@ -798,7 +798,7 @@ Schema.prototype.getAttributeTypeDetails = function (this: Schema, key: string, const isThisType = typeVal as any === Internal.Public.this; const isNullType = typeVal as any === Internal.Public.null; if (typeof typeVal === "function" || isThisType) { - if ((typeVal as any).prototype instanceof Document || isThisType) { + if ((typeVal as any).prototype instanceof Item || isThisType) { type = "model"; if (isThisType) { diff --git a/lib/Serializer.ts b/lib/Serializer.ts index 93e5c8235..49130875d 100644 --- a/lib/Serializer.ts +++ b/lib/Serializer.ts @@ -1,5 +1,5 @@ import {ObjectType, ModelType} from "./General"; -import {Document} from "./Document"; +import {Item} from "./Item"; import CustomError = require("./Error"); import utils = require("./utils"); @@ -70,21 +70,21 @@ export class Serializer { } } - _serializeMany (documentsArray: ModelType[], nameOrOptions: SerializerOptions | string): ObjectType[] { - if (!documentsArray || !Array.isArray(documentsArray)) { - throw new CustomError.InvalidParameter("documentsArray must be an array of document objects"); + _serializeMany (itemsArray: ModelType[], nameOrOptions: SerializerOptions | string): ObjectType[] { + if (!itemsArray || !Array.isArray(itemsArray)) { + throw new CustomError.InvalidParameter("itemsArray must be an array of item objects"); } - return documentsArray.map((document) => { + return itemsArray.map((item) => { try { - return document.serialize(nameOrOptions); + return item.serialize(nameOrOptions); } catch (e) { - return this._serialize(document, nameOrOptions); + return this._serialize(item, nameOrOptions); } }); } - _serialize (document: ObjectType, nameOrOptions: SerializerOptions | string = this.#defaultSerializer): ObjectType { + _serialize (item: ObjectType, nameOrOptions: SerializerOptions | string = this.#defaultSerializer): ObjectType { let options: SerializerOptions; if (typeof nameOrOptions === "string") { @@ -98,13 +98,13 @@ export class Serializer { } if (Array.isArray(options)) { - return utils.object.pick(document, options); + return utils.object.pick(item, options); } return [ { "if": Boolean(options.include), - "function": (): ObjectType => utils.object.pick(document, options.include) + "function": (): ObjectType => utils.object.pick(item, options.include) }, { "if": Boolean(options.exclude), @@ -112,8 +112,8 @@ export class Serializer { }, { "if": Boolean(options.modify), - "function": (serialized: ObjectType): ObjectType => options.modify(serialized, document) + "function": (serialized: ObjectType): ObjectType => options.modify(serialized, item) } - ].filter((item) => item.if).reduce((serialized: ObjectType, item) => item.function(serialized), {...document}); + ].filter((item) => item.if).reduce((serialized: ObjectType, item) => item.function(serialized), {...item}); } } diff --git a/lib/Transaction.ts b/lib/Transaction.ts index 2b5aef227..d214a1463 100644 --- a/lib/Transaction.ts +++ b/lib/Transaction.ts @@ -5,11 +5,11 @@ import Error = require("./Error"); import {Model} from "./Model"; import * as ModelStore from "./ModelStore"; import {CallbackType} from "./General"; -import {Document} from "./Document"; +import {Item} from "./Item"; export enum TransactionReturnOptions { request = "request", - documents = "documents" + items = "items" } enum TransactionType { get = "get", @@ -43,11 +43,11 @@ function Transaction (transactions: Transactions, settings: TransactionSettings) function Transaction (transactions: Transactions, callback: TransactionCallback): TransactionReturnType; function Transaction (transaction: Transactions, settings: TransactionSettings, callback: TransactionCallback): TransactionReturnType; function Transaction (transactions: Transactions, settings?: TransactionSettings | TransactionCallback, callback?: TransactionCallback): TransactionReturnType { - settings = settings ?? {"return": TransactionReturnOptions.documents}; + settings = settings ?? {"return": TransactionReturnOptions.items}; if (typeof settings === "function") { callback = settings; - settings = {"return": TransactionReturnOptions.documents}; + settings = {"return": TransactionReturnOptions.items}; } if (typeof transactions === "function") { callback = transactions; @@ -87,7 +87,7 @@ function Transaction (transactions: Transactions, settings?: TransactionSettings const modelNames: string[] = transactionObjects.map((a) => (Object.values(a)[0] as any).TableName); const uniqueModelNames = utils.unique_array_elements(modelNames); - const models: Model[] = uniqueModelNames.map((name) => ModelStore(name)); + const models: Model[] = uniqueModelNames.map((name) => ModelStore(name)); models.forEach((model, index) => { if (!model) { throw new Error.InvalidParameter(`Model "${uniqueModelNames[index]}" not found. Please register the model with dynamoose before using it in transactions.`); @@ -99,8 +99,8 @@ function Transaction (transactions: Transactions, settings?: TransactionSettings const result: any = await ddb(transactionType as any, transactionParams as any); return result.Responses ? await Promise.all(result.Responses.map((item, index: number) => { const modelName: string = modelNames[index]; - const model: Model = models.find((model) => model.name === modelName); - return new model.Document(item.Item, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "type": "fromDynamo"}); + const model: Model = models.find((model) => model.name === modelName); + return new model.Item(item.Item, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "type": "fromDynamo"}); })) : null; })(); diff --git a/lib/index.ts b/lib/index.ts index c419b676b..e4a0a5421 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -8,11 +8,11 @@ import aws = require("./aws"); import Internal = require("./Internal"); import utils = require("./utils"); import logger = require("./logger"); -import {Document, AnyDocument} from "./Document"; +import {Item, AnyItem} from "./Item"; import ModelStore = require("./ModelStore"); import {ModelType} from "./General"; -const model = (name: string, schema?: Schema | SchemaDefinition | (Schema | SchemaDefinition)[], options: ModelOptionsOptional = {}): ModelType => { +const model = (name: string, schema?: Schema | SchemaDefinition | (Schema | SchemaDefinition)[], options: ModelOptionsOptional = {}): ModelType => { let model: Model; let storedSchema: Model; if (name) { @@ -27,7 +27,7 @@ const model = (name: string, schema?: Schema | } else { model = new Model(name, schema, options); } - const returnObject: any = model.Document; + const returnObject: any = model.Item; const keys = utils.array_flatten([ Object.keys(model), Object.keys(Object.getPrototypeOf(model)), diff --git a/lib/utils/dynamoose/index.ts b/lib/utils/dynamoose/index.ts index efacc6f32..13487d629 100644 --- a/lib/utils/dynamoose/index.ts +++ b/lib/utils/dynamoose/index.ts @@ -3,7 +3,7 @@ import wildcard_allowed_check = require("./wildcard_allowed_check"); import index_changes from "./index_changes"; import * as convertConditionArrayRequestObjectToString from "./convertConditionArrayRequestObjectToString"; import getValueTypeCheckResult = require("./getValueTypeCheckResult"); -import {documentToJSON} from "./documentToJSON"; +import {itemToJSON} from "./itemToJSON"; export = { get_provisioned_throughput, @@ -11,5 +11,5 @@ export = { index_changes, convertConditionArrayRequestObjectToString, getValueTypeCheckResult, - documentToJSON + itemToJSON }; diff --git a/lib/utils/dynamoose/index_changes.ts b/lib/utils/dynamoose/index_changes.ts index 76a6346fb..2f7e3181c 100644 --- a/lib/utils/dynamoose/index_changes.ts +++ b/lib/utils/dynamoose/index_changes.ts @@ -1,6 +1,6 @@ import obj = require("../object"); import {Model} from "../../Model"; -import {Document} from "../../Document"; +import {Item} from "../../Item"; import {IndexItem} from "../../Schema"; export enum ModelIndexChangeType { @@ -17,7 +17,7 @@ export interface ModelIndexDeleteChange { name: string; } -const index_changes = async (model: Model, existingIndexes = []): Promise<(ModelIndexAddChange | ModelIndexDeleteChange)[]> => { +const index_changes = async (model: Model, existingIndexes = []): Promise<(ModelIndexAddChange | ModelIndexDeleteChange)[]> => { const output: (ModelIndexAddChange | ModelIndexDeleteChange)[] = []; const expectedIndexes = await model.getIndexes(); diff --git a/lib/utils/dynamoose/documentToJSON.ts b/lib/utils/dynamoose/itemToJSON.ts similarity index 56% rename from lib/utils/dynamoose/documentToJSON.ts rename to lib/utils/dynamoose/itemToJSON.ts index 9b21f9f1c..838443f0c 100644 --- a/lib/utils/dynamoose/documentToJSON.ts +++ b/lib/utils/dynamoose/itemToJSON.ts @@ -1,8 +1,8 @@ -import {DocumentArray, ObjectType} from "../../General"; -import {Document} from "../../Document"; +import {ItemArray, ObjectType} from "../../General"; +import {Item} from "../../Item"; // import object from "../object"; // TODO optimize this in the future after we add performance tests. Doing `JSON.parse(JSON.stringify()) can be kinda slow. -export function documentToJSON (this: Document | DocumentArray): ObjectType { +export function itemToJSON (this: Item | ItemArray): ObjectType { return JSON.parse(JSON.stringify(Array.isArray(this) ? [...this] : {...this})); } diff --git a/package-lock.json b/package-lock.json index 95c4fc69f..a8af9887b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,7 @@ "requires": true, "packages": { "": { - "version": "2.7.1", + "version": "3.0.0-alpha.1", "funding": [ { "type": "github-sponsors", @@ -37,7 +37,7 @@ "typescript": "^4.0.5" }, "engines": { - "node": ">=8.0.0" + "node": ">=10.0.0" } }, "node_modules/@aws-crypto/ie11-detection": { diff --git a/test/types/Model.ts b/test/types/Model.ts index 4afb1bae6..b96627b2a 100644 --- a/test/types/Model.ts +++ b/test/types/Model.ts @@ -1,7 +1,7 @@ /* eslint @typescript-eslint/no-unused-vars: 0 */ import * as dynamoose from "../../dist"; -import {Document} from "../../dist/Document"; +import {Item} from "../../dist/Item"; // @ts-expect-error const shouldFailWithNumberAsName = dynamoose.model(1); @@ -52,7 +52,7 @@ const shouldFailWithInvalidUpdateTransaction = model.transaction.update(0); const shouldFailWithInvalidConditionTransaction = model.transaction.condition(0, []); // Typed Models -export class User extends Document { +export class User extends Item { id: string; name: string; age: number; diff --git a/test/types/Transaction.ts b/test/types/Transaction.ts index 551a3a07f..ae1417d8f 100644 --- a/test/types/Transaction.ts +++ b/test/types/Transaction.ts @@ -9,13 +9,13 @@ const shouldPassWithArrayOfTransactions = dynamoose.transaction([model.transacti // @ts-expect-error const shouldFailWithNoArray = dynamoose.transaction(model.transaction.get("key")); -const shouldPassWithTransactionSettings = dynamoose.transaction([model.transaction.get("key")], {"return": TransactionReturnOptions.documents}); +const shouldPassWithTransactionSettings = dynamoose.transaction([model.transaction.get("key")], {"return": TransactionReturnOptions.items}); // @ts-expect-error const shouldFailWithInvalidTransactionSettings = dynamoose.transaction([model.transaction.get("key")], {"return": "bad"}); const shouldPassWithCallback = dynamoose.transaction( [model.transaction.get("key")], - {"return": TransactionReturnOptions.documents}, + {"return": TransactionReturnOptions.items}, (a, b) => { return; } @@ -23,7 +23,7 @@ const shouldPassWithCallback = dynamoose.transaction( const shouldFailWithInvalidCallback = dynamoose.transaction( [model.transaction.get("key")], - {"return": TransactionReturnOptions.documents}, + {"return": TransactionReturnOptions.items}, // @ts-expect-error (a, b, c) => { return; diff --git a/test/types/model/Query.ts b/test/types/model/Query.ts index 4937e756c..a281cad95 100644 --- a/test/types/model/Query.ts +++ b/test/types/model/Query.ts @@ -3,18 +3,18 @@ import {UserTypedModel, UserModel, User} from "../Model"; import {SortOrder} from "../../../dist/General"; import {Condition} from "../../../dist"; -import {AnyDocument} from "../../../dist/Document"; -import {QueryResponse} from "../../../dist/DocumentRetriever"; +import {AnyItem} from "../../../dist/Item"; +import {QueryResponse} from "../../../dist/ItemRetriever"; // query.exec([callback]) async function queryExec (): Promise { return await UserTypedModel.query().exec(); } -async function queryExecUnTyped (): Promise { +async function queryExecUnTyped (): Promise { return await UserModel.query().exec(); } -const queryExecUnTypedQueryResponse: Promise> = UserModel.query().exec(); +const queryExecUnTypedQueryResponse: Promise> = UserModel.query().exec(); const queryExecTyped: Promise> = UserTypedModel.query("name").eq("Will").exec(); // query.limit(count) diff --git a/test/types/model/Scan.ts b/test/types/model/Scan.ts index 16e012e90..e7bf03fac 100644 --- a/test/types/model/Scan.ts +++ b/test/types/model/Scan.ts @@ -2,18 +2,18 @@ import {UserTypedModel, User, UserModel} from "../Model"; import {Condition} from "../../../dist"; -import {AnyDocument} from "../../../dist/Document"; -import {ScanResponse} from "../../../dist/DocumentRetriever"; +import {AnyItem} from "../../../dist/Item"; +import {ScanResponse} from "../../../dist/ItemRetriever"; // scan.exec([callback]) async function scanExec (): Promise { return await UserTypedModel.scan().exec(); } -async function scanExecUnTyped (): Promise { +async function scanExecUnTyped (): Promise { return await UserModel.scan().exec(); } -const scanExecUnTypedWithScanResponse: Promise> = UserModel.scan().exec(); +const scanExecUnTypedWithScanResponse: Promise> = UserModel.scan().exec(); const scanExecTyped: Promise> = UserTypedModel.scan("name").eq("Will").exec(); UserTypedModel.scan().exec(); @@ -24,7 +24,7 @@ UserTypedModel.scan().limit(5); // scan.startAt(key) async function scanStartAt (): Promise { const response = await UserTypedModel.scan().exec(); - const moreDocuments = UserTypedModel.scan().startAt(response.lastKey); + const moreItems = UserTypedModel.scan().startAt(response.lastKey); } // scan.attributes(attributes) diff --git a/test/unit/Document.js b/test/unit/Document.js index 9b07a46ba..1c08adcb0 100644 --- a/test/unit/Document.js +++ b/test/unit/Document.js @@ -4,15 +4,15 @@ chai.use(chaiAsPromised); const {expect} = chai; const dynamoose = require("../../dist"); const {Schema, aws} = dynamoose; -const {Document} = require("../../dist/Document"); +const {Item} = require("../../dist/Item"); const util = require("util"); const Error = require("../../dist/Error"); const utils = require("../../dist/utils"); const Internal = require("../../dist/Internal"); -describe("Document", () => { +describe("Item", () => { it("Should be a function", () => { - expect(Document).to.be.a("function"); + expect(Item).to.be.a("function"); }); it("Should not have internalProperties if use spread operator on object", () => { @@ -69,7 +69,7 @@ describe("Document", () => { }); }); - describe("Document.prototype.toDynamo", () => { + describe("Item.prototype.toDynamo", () => { const tests = [ { "input": {}, @@ -89,7 +89,7 @@ describe("Document", () => { }); }); - describe("document.save", () => { + describe("item.save", () => { let User, user, putParams = [], putItemFunction; beforeEach(() => { dynamoose.model.defaults.set({ @@ -119,8 +119,8 @@ describe("Document", () => { }); const functionCallTypes = [ - {"name": "Promise", "func": (document) => document.save}, - {"name": "Callback", "func": (document) => util.promisify(document.save)} + {"name": "Promise", "func": (item) => item.save}, + {"name": "Callback", "func": (item) => util.promisify(item.save)} ]; functionCallTypes.forEach((callType) => { describe(callType.name, () => { @@ -414,7 +414,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "address": {"type": Object, "schema": {"street": String, "country": {"type": String, "required": true}}}}, {"create": false, "waitForActive": false}); user = new User({"id": 1, "address": {"street": "hello"}}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("address.country is a required property but has no value when trying to save document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("address.country is a required property but has no value when trying to save item"); }); it("Should throw type mismatch error if passing in wrong type with custom type for object", () => { @@ -567,7 +567,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "friends": {"type": Array, "schema": [{"type": Object, "schema": {"id": {"type": Number, "required": true}, "name": String}}]}}, {"create": false, "waitForActive": false}); user = new User({"id": 1, "friends": [{"name": "Bob"}]}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("friends.0.id is a required property but has no value when trying to save document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("friends.0.id is a required property but has no value when trying to save item"); }); it("Should throw error if not passing in required property in array for second item", () => { @@ -575,7 +575,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "friends": {"type": Array, "schema": [{"type": Object, "schema": {"id": {"type": Number, "required": true}, "name": String}}]}}, {"create": false, "waitForActive": false}); user = new User({"id": 1, "friends": [{"name": "Bob", "id": 1}, {"name": "Tim"}]}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("friends.1.id is a required property but has no value when trying to save document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("friends.1.id is a required property but has no value when trying to save item"); }); it("Should throw error if not passing in required property in array for second item with multi nested objects", () => { @@ -583,7 +583,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "friends": {"type": Array, "schema": [{"type": Object, "schema": {"name": String, "addresses": {"type": Array, "schema": [{"type": Object, "schema": {"country": {"type": String, "required": true}}}]}}}]}}, {"create": false, "waitForActive": false}); user = new User({"id": 1, "friends": [{"name": "Bob", "addresses": [{"country": "world"}]}, {"name": "Tim", "addresses": [{"country": "moon"}, {"zip": 12345}]}]}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("friends.1.addresses.1.country is a required property but has no value when trying to save document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("friends.1.addresses.1.country is a required property but has no value when trying to save item"); }); it("Should save with correct object with expires set to a number", async () => { @@ -1019,7 +1019,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "age": {"type": Number, "validate": 5}}, {"create": false, "waitForActive": false}); user = new User({"id": 1, "age": 4}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("age with a value of 4 had a validation error when trying to save the document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("age with a value of 4 had a validation error when trying to save the item"); }); // This test is here since if you want to enforce that the property exists, you must use both `required` & `validate`, not just `validate` @@ -1061,7 +1061,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "age": {"type": Number, "validate": (val) => val > 5}}, {"create": false, "waitForActive": false}); user = new User({"id": 1, "age": 4}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("age with a value of 4 had a validation error when trying to save the document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("age with a value of 4 had a validation error when trying to save the item"); }); it("Should save with correct object with validation async function", async () => { @@ -1080,7 +1080,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "age": {"type": Number, "validate": async (val) => val > 5}}, {"create": false, "waitForActive": false}); user = new User({"id": 1, "age": 4}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("age with a value of 4 had a validation error when trying to save the document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("age with a value of 4 had a validation error when trying to save the item"); }); it("Should save with correct object with validation RegExp", async () => { @@ -1099,7 +1099,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "name": {"type": String, "validate": /.../gu}}, {"create": false, "waitForActive": false}); user = new User({"id": 1, "name": "a"}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("name with a value of a had a validation error when trying to save the document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("name with a value of a had a validation error when trying to save the item"); }); it("Should save with correct object with required property", async () => { @@ -1118,7 +1118,7 @@ describe("Document", () => { User = dynamoose.model("User", {"id": Number, "name": {"type": String, "required": true}}, {"create": false, "waitForActive": false}); user = new User({"id": 1}); - return expect(callType.func(user).bind(user)()).to.be.rejectedWith("name is a required property but has no value when trying to save document"); + return expect(callType.func(user).bind(user)()).to.be.rejectedWith("name is a required property but has no value when trying to save item"); }); it("Should save with correct object with enum property", async () => { @@ -1235,7 +1235,7 @@ describe("Document", () => { }]); }); - it("Should work correctly if attributes added to document after initalization", async () => { + it("Should work correctly if attributes added to item after initalization", async () => { putItemFunction = () => Promise.resolve(); User = dynamoose.model("User", {"id": Number, "name": String}, {"create": false, "waitForActive": false}); user = new User(); @@ -1259,7 +1259,7 @@ describe("Document", () => { game = null; }); - it("Should save with correct object with document instance passed in", async () => { + it("Should save with correct object with item instance passed in", async () => { putItemFunction = () => Promise.resolve(); await callType.func(game).bind(game)(); expect(putParams).to.eql([{ @@ -1284,7 +1284,7 @@ describe("Document", () => { game = new Game({"id": 2, "name": "Game 2", "user": [user]}); }); - it("Should save with correct object with document instance as set passed in", async () => { + it("Should save with correct object with item instance as set passed in", async () => { putItemFunction = () => Promise.resolve(); await callType.func(game).bind(game)(); expect(putParams).to.eql([{ @@ -1312,7 +1312,7 @@ describe("Document", () => { game = new Game({"id": 2, "name": "Game 2", user}); }); - it("Should save with correct object with document instance passed in", async () => { + it("Should save with correct object with item instance passed in", async () => { putItemFunction = () => Promise.resolve(); await callType.func(game).bind(game)(); expect(putParams).to.eql([{ @@ -1343,7 +1343,7 @@ describe("Document", () => { return expect(callType.func(game).bind(game)()).to.be.rejectedWith("Expected user to be of type User, instead found type string."); }); - it("Should throw error if trying to create document with property type as set model", () => { + it("Should throw error if trying to create item with property type as set model", () => { const Game = dynamoose.model("Game", {"id": Number, "name": String, "user": {"type": Set, "schema": [User]}}); return expect(Game.create({"id": 2, "name": "Game 2", "user": [1]})).to.be.rejectedWith("user with type: model is not allowed to be a set"); }); @@ -1447,11 +1447,11 @@ describe("Document", () => { } }); const model = dynamoose.model("User2", {"id": Number, "name": String}, {"waitForActive": {"enabled": true, "check": {"frequency": 0, "timeout": 100}}}); - const document = new model({"id": 1, "name": "Charlie"}); + const item = new model({"id": 1, "name": "Charlie"}); await utils.set_immediate_promise(); let finishedSavingUser = false; - callType.func(document).bind(document)().then(() => finishedSavingUser = true); + callType.func(item).bind(item)().then(() => finishedSavingUser = true); await utils.set_immediate_promise(); expect(putParams).to.eql([]); @@ -1476,7 +1476,7 @@ describe("Document", () => { }); }); - describe("document.original", () => { + describe("item.original", () => { let model; beforeEach(() => { model = dynamoose.model("User", {"id": Number}, {"create": false, "waitForActive": false}); @@ -1497,40 +1497,40 @@ describe("Document", () => { expect(new model({"id": 1}, {"type": "fromDynamo"}).original()).to.eql({"id": 1}); }); - it("Should return original object if retrieving from database even after modifying document", () => { - const document = new model({"id": 1}, {"type": "fromDynamo"}); - document.id = 2; - expect(document.original()).to.eql({"id": 1}); - expect({...document}).to.eql({"id": 2}); + it("Should return original object if retrieving from database even after modifying item", () => { + const item = new model({"id": 1}, {"type": "fromDynamo"}); + item.id = 2; + expect(item.original()).to.eql({"id": 1}); + expect({...item}).to.eql({"id": 2}); }); it("Shouldn't return DynamoDB object if retrieving from database", () => { expect(new model({"id": {"N": "1"}}, {"type": "fromDynamo"}).original()).to.eql({"id": 1}); }); - it("Shouldn't return DynamoDB object if retrieving from database even after modifying document", () => { - const document = new model({"id": {"N": "1"}}, {"type": "fromDynamo"}); - document.id = 2; - expect(document.original()).to.eql({"id": 1}); - expect({...document}).to.eql({"id": 2}); + it("Shouldn't return DynamoDB object if retrieving from database even after modifying item", () => { + const item = new model({"id": {"N": "1"}}, {"type": "fromDynamo"}); + item.id = 2; + expect(item.original()).to.eql({"id": 1}); + expect({...item}).to.eql({"id": 2}); }); - it("Shouldn't modify inner array after modifying document", () => { - const document = new model({"id": {"N": "1"}, "array": {"L": [{"S": "1"}]}}, {"type": "fromDynamo"}); - document.array.push("2"); - expect(document.original()).to.eql({"id": 1, "array": ["1"]}); - expect({...document}).to.eql({"id": 1, "array": ["1", "2"]}); + it("Shouldn't modify inner array after modifying item", () => { + const item = new model({"id": {"N": "1"}, "array": {"L": [{"S": "1"}]}}, {"type": "fromDynamo"}); + item.array.push("2"); + expect(item.original()).to.eql({"id": 1, "array": ["1"]}); + expect({...item}).to.eql({"id": 1, "array": ["1", "2"]}); }); - it("Shouldn't modify inner object after modifying document", () => { - const document = new model({"id": {"N": "1"}, "object": {"M": {"hello": {"S": "world"}}}}, {"type": "fromDynamo"}); - document.object.test = "item"; - expect(document.original()).to.eql({"id": 1, "object": {"hello": "world"}}); - expect({...document}).to.eql({"id": 1, "object": {"hello": "world", "test": "item"}}); + it("Shouldn't modify inner object after modifying item", () => { + const item = new model({"id": {"N": "1"}, "object": {"M": {"hello": {"S": "world"}}}}, {"type": "fromDynamo"}); + item.object.test = "item"; + expect(item.original()).to.eql({"id": 1, "object": {"hello": "world"}}); + expect({...item}).to.eql({"id": 1, "object": {"hello": "world", "test": "item"}}); }); }); - describe("document.toJSON", () => { + describe("item.toJSON", () => { let model; beforeEach(() => { model = dynamoose.model("User", {"id": Number}, {"create": false, "waitForActive": false}); @@ -1548,7 +1548,7 @@ describe("Document", () => { expect(new model({}).constructor).to.not.eql(Object); }); - it("Should return empty object if no properties in document", () => { + it("Should return empty object if no properties in item", () => { expect(new model({}).toJSON()).to.eql({}); }); @@ -1556,19 +1556,19 @@ describe("Document", () => { expect(new model({"id": 1}).toJSON()).to.eql({"id": 1}); }); - it("Should not return object that equals document", () => { - const document = new model({"id": 1}); - expect(document.toJSON()).to.not.eql(document); + it("Should not return object that equals item", () => { + const item = new model({"id": 1}); + expect(item.toJSON()).to.not.eql(item); }); it("Should return JSON object even after modifying", () => { - const document = new model({"id": 1}); - document.id = 2; - expect(document.toJSON()).to.eql({"id": 2}); + const item = new model({"id": 1}); + item.id = 2; + expect(item.toJSON()).to.eql({"id": 2}); }); }); - describe("document.delete", () => { + describe("item.delete", () => { let User, user, deleteParams, deleteItemFunction; beforeEach(() => { dynamoose.model.defaults.set({ @@ -1598,8 +1598,8 @@ describe("Document", () => { }); const functionCallTypes = [ - {"name": "Promise", "func": (document) => document.delete}, - {"name": "Callback", "func": (document) => util.promisify(document.delete)} + {"name": "Promise", "func": (item) => item.delete}, + {"name": "Callback", "func": (item) => util.promisify(item.delete)} ]; functionCallTypes.forEach((callType) => { describe(callType.name, () => { @@ -1617,7 +1617,7 @@ describe("Document", () => { user = new User({"id": 1, "name": "Charlie", "type": "admin"}); deleteItemFunction = () => Promise.resolve(); - const func = (document) => util.promisify(document.delete); + const func = (item) => util.promisify(item.delete); await func(user).bind(user)(); expect(deleteParams).to.eql({ "Key": {"id": {"N": "1"}, "name": {"S": "Charlie"}}, @@ -1633,7 +1633,7 @@ describe("Document", () => { }); }); - describe("document.populate", () => { + describe("item.populate", () => { let User, user, Game, game, getItemParams = [], getItemFunction; beforeEach(() => { dynamoose.model.defaults.set({ @@ -1667,8 +1667,8 @@ describe("Document", () => { }); const functionCallTypes = [ - {"name": "Promise", "func": (document) => document.populate}, - {"name": "Callback", "func": (document) => util.promisify(document.populate)} + {"name": "Promise", "func": (item) => item.populate}, + {"name": "Callback", "func": (item) => util.promisify(item.populate)} ]; functionCallTypes.forEach((callType) => { describe(callType.name, () => { @@ -1689,10 +1689,10 @@ describe("Document", () => { "name": "Charlie" } }); - expect(res).to.be.a.instanceOf(Document); + expect(res).to.be.a.instanceOf(Item); }); - it("Should not call getItem if sub document already exists", async () => { + it("Should not call getItem if sub item already exists", async () => { getItemFunction = () => Promise.resolve({ "Item": {...user} }); @@ -1740,7 +1740,7 @@ describe("Document", () => { }); }); - it("Should not call getItem if sub document already exists", async () => { + it("Should not call getItem if sub item already exists", async () => { getItemFunction = () => Promise.resolve({ "Item": {...parent} }); @@ -1809,7 +1809,7 @@ describe("Document", () => { }); }); - describe("Document.isDynamoObject", () => { + describe("Item.isDynamoObject", () => { let User; beforeEach(() => { User = dynamoose.model("User", {"id": Number, "name": String}, {"create": false, "waitForActive": false}); @@ -1924,7 +1924,7 @@ describe("Document", () => { }); }); - describe("Document.attributesWithSchema", () => { + describe("Item.attributesWithSchema", () => { it("Should be a function", () => { expect(dynamoose.model("User", {"id": Number}, {"create": false, "waitForActive": false}).attributesWithSchema).to.be.a("function"); }); @@ -1990,7 +1990,7 @@ describe("Document", () => { }); }); - describe("Document.objectFromSchema", () => { + describe("Item.objectFromSchema", () => { it("Should be a function", () => { expect(dynamoose.model("User", {"id": Number}, {"create": false, "waitForActive": false}).objectFromSchema).to.be.a("function"); }); @@ -2108,7 +2108,7 @@ describe("Document", () => { }, { "input": [{"id": "test"}, {"validate": true}], - "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the document"), + "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the item"), "schema": {"id": {"type": String, "validate": (val) => val.length > 5}} }, // Validations @@ -2124,7 +2124,7 @@ describe("Document", () => { }, { "input": [{"id": "test"}, {"validate": true}], - "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the document"), + "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the item"), "schema": {"id": {"type": String, "validate": async (val) => val.length > 5}} }, { @@ -2139,7 +2139,7 @@ describe("Document", () => { }, { "input": [{"id": "test"}, {"validate": true}], - "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the document"), + "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the item"), "schema": {"id": {"type": String, "validate": (val) => val.length > 5}} }, { @@ -2154,7 +2154,7 @@ describe("Document", () => { }, { "input": [{"id": "test"}, {"validate": true}], - "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the document"), + "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the item"), "schema": {"id": {"type": String, "validate": /ID_.+/gu}} }, { @@ -2169,7 +2169,7 @@ describe("Document", () => { }, { "input": [{"id": "test"}, {"validate": true}], - "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the document"), + "error": new Error.ValidationError("id with a value of test had a validation error when trying to save the item"), "schema": {"id": {"type": String, "validate": "ID_test"}} }, { @@ -2184,7 +2184,7 @@ describe("Document", () => { }, { "input": [{"id": "test"}, {"enum": true, "required": true}], - "error": new Error.ValidationError("age is a required property but has no value when trying to save document"), + "error": new Error.ValidationError("age is a required property but has no value when trying to save item"), "schema": {"id": {"type": String}, "age": {"type": Number, "enum": [10, 20], "required": true}} }, { @@ -2199,7 +2199,7 @@ describe("Document", () => { }, { "input": [{"id": "test"}, {"required": true}], - "error": new Error.ValidationError("data is a required property but has no value when trying to save document"), + "error": new Error.ValidationError("data is a required property but has no value when trying to save item"), "schema": {"id": {"type": String}, "data": {"type": Object, "schema": {"name": {"type": String, "required": false}}, "required": true}} }, { @@ -2209,12 +2209,12 @@ describe("Document", () => { }, { "input": [{"id": "test", "data": {"email": "test@test.com"}}, {"required": true}], - "error": new Error.ValidationError("data.name is a required property but has no value when trying to save document"), + "error": new Error.ValidationError("data.name is a required property but has no value when trying to save item"), "schema": {"id": {"type": String}, "data": {"type": Object, "schema": {"email": String, "name": {"type": String, "required": true}}}} }, { "input": [{"id": "test"}, {"required": true}], - "error": new Error.ValidationError("data is a required property but has no value when trying to save document"), + "error": new Error.ValidationError("data is a required property but has no value when trying to save item"), "schema": {"id": {"type": String}, "data": {"type": Object, "schema": {"name": {"type": String, "required": true}}, "required": true}} }, { @@ -2224,7 +2224,7 @@ describe("Document", () => { }, { "input": [{"id": "test"}, {"required": true}], - "error": new Error.ValidationError("hash is a required property but has no value when trying to save document"), + "error": new Error.ValidationError("hash is a required property but has no value when trying to save item"), "schema": {"id": {"type": String}, "hash": {"type": String, "required": true}, "data": {"type": Object, "schema": {"email": String, "name": {"type": String, "required": true}}}} }, { @@ -2363,7 +2363,7 @@ describe("Document", () => { { "schema": {"id": Number, "name": {"type": String, "required": true, "set": (val) => val === "" ? undefined : val}}, "input": [{"id": 1, "name": ""}, {"type": "toDynamo", "modifiers": ["set"], "required": true}], - "error": new Error.ValidationError("name is a required property but has no value when trying to save document") + "error": new Error.ValidationError("name is a required property but has no value when trying to save item") }, { "schema": {"id": Number, "friends": {"type": Array}}, @@ -2788,7 +2788,7 @@ describe("Document", () => { }); }); - describe("Document.prepareForObjectFromSchema", () => { + describe("Item.prepareForObjectFromSchema", () => { it("Should be a function", () => { expect(dynamoose.model("User", {"id": Number}, {"create": false, "waitForActive": false}).prepareForObjectFromSchema).to.be.a("function"); }); diff --git a/test/unit/DocumentRetriever.js b/test/unit/DocumentRetriever.js index a4039dc90..aed53779c 100644 --- a/test/unit/DocumentRetriever.js +++ b/test/unit/DocumentRetriever.js @@ -1,16 +1,16 @@ const {expect} = require("chai"); -const DocumentRetriever = require("../../dist/DocumentRetriever"); +const ItemRetriever = require("../../dist/ItemRetriever"); -describe("DocumentRetriever", () => { +describe("ItemRetriever", () => { it("Should return an object", () => { - expect(DocumentRetriever).to.be.an("object"); + expect(ItemRetriever).to.be.an("object"); }); it("Should return an object with Scan property", () => { - expect(DocumentRetriever.Scan).to.exist; + expect(ItemRetriever.Scan).to.exist; }); it("Should return an object with Query property", () => { - expect(DocumentRetriever.Query).to.exist; + expect(ItemRetriever.Query).to.exist; }); }); diff --git a/test/unit/Model.js b/test/unit/Model.js index d2a595e98..ecbfc5c2e 100644 --- a/test/unit/Model.js +++ b/test/unit/Model.js @@ -1235,7 +1235,7 @@ describe("Model", () => { expect(user.name).to.eql("Charlie"); }); - it("Should return object that is an instance of Document", async () => { + it("Should return object that is an instance of Item", async () => { getItemFunction = () => Promise.resolve({"Item": {"id": {"N": "1"}, "name": {"S": "Charlie"}}}); const user = await callType.func(User).bind(User)(1); expect(user).to.be.an.instanceof(User); @@ -1492,7 +1492,7 @@ describe("Model", () => { }); describe("Populate", () => { - it("Should not populate document automatically", async () => { + it("Should not populate item automatically", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": dynamoose.model("Parent", {"id": Number, "data": String})}); @@ -1511,7 +1511,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically if schema property is object", async () => { + it("Should not populate item automatically if schema property is object", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": dynamoose.model("Parent", {"id": Number, "data": String})}}); @@ -1530,7 +1530,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when schema property is dynamoose.THIS", async () => { + it("Should not populate item automatically when schema property is dynamoose.THIS", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": dynamoose.THIS}); @@ -1549,7 +1549,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when schema property is dynamoose.THIS if schema property is object", async () => { + it("Should not populate item automatically when schema property is dynamoose.THIS if schema property is object", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": dynamoose.THIS}}); @@ -1568,7 +1568,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when using set", async () => { + it("Should not populate item automatically when using set", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": Set, "schema": [dynamoose.model("Parent", {"id": Number, "data": String})]}}); @@ -1586,7 +1586,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when using set if schema property is object", async () => { + it("Should not populate item automatically when using set if schema property is object", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": Set, "schema": [{"type": dynamoose.model("Parent", {"id": Number, "data": String})}]}}); @@ -1604,7 +1604,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when using set when schema property is dynamoose.THIS", async () => { + it("Should not populate item automatically when using set when schema property is dynamoose.THIS", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": Set, "schema": [dynamoose.THIS]}}); @@ -1622,7 +1622,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when using set when schema property is dynamoose.THIS if schema property is object", async () => { + it("Should not populate item automatically when using set when schema property is dynamoose.THIS if schema property is object", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": Set, "schema": [{"type": dynamoose.THIS}]}}); @@ -1640,7 +1640,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when using array", async () => { + it("Should not populate item automatically when using array", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": Array, "schema": [dynamoose.model("Parent", {"id": Number, "data": String})]}}); @@ -1659,7 +1659,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when using array if schema property is object", async () => { + it("Should not populate item automatically when using array if schema property is object", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": Array, "schema": [{"type": dynamoose.model("Parent", {"id": Number, "data": String})}]}}); @@ -1678,7 +1678,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when using array when schema property is dynamoose.THIS", async () => { + it("Should not populate item automatically when using array when schema property is dynamoose.THIS", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": Array, "schema": [dynamoose.THIS]}}); @@ -1697,7 +1697,7 @@ describe("Model", () => { expect(getItemTimesCalled).to.eql(1); }); - it("Should not populate document automatically when using array when schema property is dynamoose.THIS if schema property is object", async () => { + it("Should not populate item automatically when using array when schema property is dynamoose.THIS if schema property is object", async () => { let getItemTimesCalled = 0; User = dynamoose.model("User", {"id": Number, "name": String, "parent": {"type": Array, "schema": [{"type": dynamoose.THIS}]}}); @@ -3410,10 +3410,10 @@ describe("Model", () => { }); }); - it("Should return updated document upon success", async () => { + it("Should return updated item upon success", async () => { updateItemFunction = () => Promise.resolve({"Attributes": {"id": {"N": "1"}, "name": {"S": "Charlie"}}}); const result = await callType.func(User).bind(User)({"id": 1, "name": "Charlie"}); - expect(result.constructor.name).to.eql("Document"); + expect(result.constructor.name).to.eql("Item"); expect({...result}).to.eql({ "id": 1, "name": "Charlie" @@ -3438,7 +3438,7 @@ describe("Model", () => { updateItemFunction = () => Promise.reject({"error": "ERROR"}); User = dynamoose.model("User", {"id": Number, "name": {"type": String, "validate": (val) => val.length > 10}}); - return expect(callType.func(User).bind(User)({"id": 1}, {"name": "Bob"})).to.be.rejectedWith("name with a value of Bob had a validation error when trying to save the document"); + return expect(callType.func(User).bind(User)({"id": 1}, {"name": "Bob"})).to.be.rejectedWith("name with a value of Bob had a validation error when trying to save the item"); }); it("Should throw error if value not in enum", () => { @@ -3486,7 +3486,7 @@ describe("Model", () => { updateItemFunction = () => Promise.reject({"error": "ERROR"}); User = dynamoose.model("User", {"id": Number, "name": {"type": String, "required": true}}); - return expect(callType.func(User).bind(User)({"id": 1}, {"$REMOVE": ["name"]})).to.be.rejectedWith("name is a required property but has no value when trying to save document"); + return expect(callType.func(User).bind(User)({"id": 1}, {"$REMOVE": ["name"]})).to.be.rejectedWith("name is a required property but has no value when trying to save item"); }); it("Should not throw error if trying to modify required property", () => { @@ -3507,14 +3507,14 @@ describe("Model", () => { updateItemFunction = () => Promise.resolve({}); User = dynamoose.model("User", {"id": Number, "data": {"type": Object, "schema": {"name": String, "age": {"type": Number, "required": true}}}}); - return expect(callType.func(User).bind(User)({"id": 1}, {"data": {"name": "Charlie"}})).to.be.rejectedWith("data.age is a required property but has no value when trying to save document"); + return expect(callType.func(User).bind(User)({"id": 1}, {"data": {"name": "Charlie"}})).to.be.rejectedWith("data.age is a required property but has no value when trying to save item"); }); it("Should throw error if trying to replace object with $SET without nested required property", () => { updateItemFunction = () => Promise.resolve({}); User = dynamoose.model("User", {"id": Number, "data": {"type": Object, "schema": {"name": String, "age": {"type": Number, "required": true}}}}); - return expect(callType.func(User).bind(User)({"id": 1}, {"$SET": {"data": {"name": "Charlie"}}})).to.be.rejectedWith("data.age is a required property but has no value when trying to save document"); + return expect(callType.func(User).bind(User)({"id": 1}, {"$SET": {"data": {"name": "Charlie"}}})).to.be.rejectedWith("data.age is a required property but has no value when trying to save item"); }); it("Should use default value if deleting property", async () => { @@ -4806,7 +4806,7 @@ describe("Model", () => { return [[{"id": 1, "status": "active", "name": "Bob"}, {"id": 2, "status": "not_active", "name": "Tim"}], "isActive"]; }, "output": [{"id": 1, "isActive": true}, {"id": 2, "isActive": false}]}, {"input": [[{"id": 1, "name": "Bob"}, {"id": 2, "name": "Tim"}], "random"], "error": "Field options is required and should be an object or array"}, - {"input": [{"id": 1, "name": "Bob"}], "error": "documentsArray must be an array of document objects"} + {"input": [{"id": 1, "name": "Bob"}], "error": "itemsArray must be an array of item objects"} ]; describe("Model.serializeMany", () => { it("Should be a function", () => { @@ -4823,7 +4823,7 @@ describe("Model", () => { } }); - it(`Should return ${JSON.stringify(test.output)} for ${JSON.stringify(test.input)} when using document instance`, () => { + it(`Should return ${JSON.stringify(test.output)} for ${JSON.stringify(test.input)} when using item instance`, () => { const input = typeof test.input === "function" ? test.input() : test.input; if (Array.isArray(input[0])) { input[0] = input[0].map((obj) => new User(obj)); @@ -4849,26 +4849,26 @@ describe("Model", () => { if (Array.isArray(input[0])) { input[0].forEach((object, index) => { - const document = new User(object); + const item = new User(object); if (test.error) { - expect(() => document.serialize(input[1])).to.throw(test.error); + expect(() => item.serialize(input[1])).to.throw(test.error); } else { - expect(document.serialize(input[1])).to.eql(test.output[index]); + expect(item.serialize(input[1])).to.eql(test.output[index]); } }); } }); if (!test.error) { - it(`Should return same output as document.toJSON() for ${JSON.stringify(test.input)}`, () => { + it(`Should return same output as item.toJSON() for ${JSON.stringify(test.input)}`, () => { const input = typeof test.input === "function" ? test.input() : test.input; if (Array.isArray(input[0])) { input[0].forEach((object) => { - const document = new User(object); + const item = new User(object); User.serializer.default.set(); - expect(document.serialize()).to.eql(document.toJSON()); + expect(item.serialize()).to.eql(item.toJSON()); }); } }); @@ -5038,8 +5038,8 @@ describe("Model", () => { } customMethodTests({"prefixName": "Model.methods", "methodEntryPoint": () => User.methods, "testObject": () => User, "existingMethod": "get"}); - describe("Model.methods.document", () => { - customMethodTests({"prefixName": "Model.methods.document", "methodEntryPoint": () => User.methods.document, "testObject": () => user, "existingMethod": "save"}); + describe("Model.methods.item", () => { + customMethodTests({"prefixName": "Model.methods.item", "methodEntryPoint": () => User.methods.item, "testObject": () => user, "existingMethod": "save"}); }); }); }); diff --git a/test/unit/Populate.js b/test/unit/Populate.js index ad94f9a16..83f419766 100644 --- a/test/unit/Populate.js +++ b/test/unit/Populate.js @@ -26,26 +26,26 @@ describe("Populate", () => { describe(responseType.name, () => { const populateTypes = [ { - "name": "PopulateDocument", - "func": Populate.PopulateDocument, + "name": "PopulateItem", + "func": Populate.PopulateItem, "tests": [ - {"input": {"id": 2, "name": "Tim"}, "output": {"id": 2, "name": "Tim"}, "documents": [{"id": 1, "name": "Bob"}]}, - {"input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob"}}, "documents": [{"id": 1, "name": "Bob"}]}, - {"input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": {"id": 3, "name": "Evan"}}}, "documents": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}]}, - {"input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}, "documents": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": "*"}}, - {"input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}, "documents": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": ["*"]}}, - {"schema": {"id": Number, "name": String, "parent": [dynamoose.THIS, String]}, "input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}, "documents": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": ["*"]}} + {"input": {"id": 2, "name": "Tim"}, "output": {"id": 2, "name": "Tim"}, "items": [{"id": 1, "name": "Bob"}]}, + {"input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob"}}, "items": [{"id": 1, "name": "Bob"}]}, + {"input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": {"id": 3, "name": "Evan"}}}, "items": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}]}, + {"input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}, "items": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": "*"}}, + {"input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}, "items": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": ["*"]}}, + {"schema": {"id": Number, "name": String, "parent": [dynamoose.THIS, String]}, "input": {"id": 2, "name": "Tim", "parent": 1}, "output": {"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}, "items": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": ["*"]}} ] }, { - "name": "PopulateDocuments", - "func": Populate.PopulateDocuments, + "name": "PopulateItems", + "func": Populate.PopulateItems, "tests": [ - {"input": [{"id": 2, "name": "Tim"}], "output": [{"id": 2, "name": "Tim"}], "documents": [{"id": 1, "name": "Bob"}]}, - {"input": [{"id": 2, "name": "Tim", "parent": 1}], "output": [{"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob"}}], "documents": [{"id": 1, "name": "Bob"}]}, - {"input": [{"id": 2, "name": "Tim", "parent": 1}], "output": [{"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": {"id": 3, "name": "Evan"}}}], "documents": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}]}, - {"input": [{"id": 2, "name": "Tim", "parent": 1}], "output": [{"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}], "documents": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": "*"}}, - {"input": [{"id": 2, "name": "Tim", "parent": 1}], "output": [{"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}], "documents": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": ["*"]}} + {"input": [{"id": 2, "name": "Tim"}], "output": [{"id": 2, "name": "Tim"}], "items": [{"id": 1, "name": "Bob"}]}, + {"input": [{"id": 2, "name": "Tim", "parent": 1}], "output": [{"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob"}}], "items": [{"id": 1, "name": "Bob"}]}, + {"input": [{"id": 2, "name": "Tim", "parent": 1}], "output": [{"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": {"id": 3, "name": "Evan"}}}], "items": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}]}, + {"input": [{"id": 2, "name": "Tim", "parent": 1}], "output": [{"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}], "items": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": "*"}}, + {"input": [{"id": 2, "name": "Tim", "parent": 1}], "output": [{"id": 2, "name": "Tim", "parent": {"id": 1, "name": "Bob", "parent": 3}}], "items": [{"id": 1, "name": "Bob", "parent": 3}, {"id": 3, "name": "Evan"}], "settings": {"properties": ["*"]}} ] } ]; @@ -74,9 +74,9 @@ describe("Populate", () => { User = dynamoose.model("User", test.schema, {"create": false, "waitForActive": false}); } - promiseFunction = (param) => ({"Item": aws.converter().marshall(test.documents.find((doc) => doc.id === parseInt(param.Key.id.N)))}); + promiseFunction = (param) => ({"Item": aws.converter().marshall(test.items.find((doc) => doc.id === parseInt(param.Key.id.N)))}); - const input = Array.isArray(test.input) ? Object.assign(test.input.map((item) => new User(item)), {"populate": Populate.PopulateDocuments, "toJSON": utils.dynamoose.documentToJSON}) : new User(test.input); + const input = Array.isArray(test.input) ? Object.assign(test.input.map((item) => new User(item)), {"populate": Populate.PopulateItems, "toJSON": utils.dynamoose.itemToJSON}) : new User(test.input); const res = await responseType.func(input).bind(input)(test.settings || {}); expect(res.toJSON()).to.eql(test.output); }); @@ -88,7 +88,7 @@ describe("Populate", () => { }; const obj = new User({"id": 2, "name": "Tim", "parent": 1}); - const input = populateType.name === "PopulateDocuments" ? Object.assign([obj], {"populate": Populate.PopulateDocuments}) : obj; + const input = populateType.name === "PopulateItems" ? Object.assign([obj], {"populate": Populate.PopulateItems}) : obj; const res = responseType.func(input).bind(input)(); return expect(res).to.be.rejectedWith("ERROR"); }); diff --git a/test/unit/Query.js b/test/unit/Query.js index 837330980..9d7a23693 100644 --- a/test/unit/Query.js +++ b/test/unit/Query.js @@ -4,7 +4,7 @@ chai.use(chaiAsPromised); const {expect} = chai; const dynamoose = require("../../dist"); const util = require("util"); -const {Query} = require("../../dist/DocumentRetriever"); +const {Query} = require("../../dist/ItemRetriever"); describe("Query", () => { beforeEach(() => { diff --git a/test/unit/Scan.js b/test/unit/Scan.js index 54afc55ac..ee2dc95cf 100644 --- a/test/unit/Scan.js +++ b/test/unit/Scan.js @@ -4,7 +4,7 @@ chai.use(chaiAsPromised); const {expect} = chai; const dynamoose = require("../../dist"); const util = require("util"); -const {Scan} = require("../../dist/DocumentRetriever"); +const {Scan} = require("../../dist/ItemRetriever"); describe("Scan", () => { beforeEach(() => {