Giter Club home page Giter Club logo

dynamodb-onetable's People

Contributors

alexander-dermicus avatar alexstansfield avatar busticated avatar bytekast avatar calebwilson706 avatar dev-embedthis avatar erik-dreamteam avatar hibanka avatar hicksy avatar iraycd avatar krisb avatar kujtimiihoxha avatar loetjvr avatar markandrus avatar melissarh57 avatar mikkel-arturo avatar mkovel avatar mobsense avatar onhate avatar radekl avatar rdelcampog avatar rjmackay avatar sdemjanenko avatar shishkin avatar simonireilly avatar skrud-dt avatar smacker avatar sparkboxx avatar spearmootz avatar yauhenpylaurea avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dynamodb-onetable's Issues

[BUG]: Unique type fields are not removed once a Model Item is removed

Describe the bug
Unique type fields are not removed once a Model Item having unique attrbiute is removed.

To Reproduce

    models: {

        Tenant: {
            pk: { type: String, value: 'tenant#${id}' },
            sk: { type: String, value: 'tenant#' },
            id: { type: String, uuid: true, validate: Match.ulid },
            name: { type: String, required: true, unique: true, validate: Match.name },
            balance: { type: Number, default: 0 },

            //  Search by tenant name or by type
            gs1pk: { type: String, value: 'tenant#' },
            gs1sk: { type: String, value: 'tenant#${name}#${id}' },
        },
}

The attribute 'name' is marked as unique.

// API to remove
 await this.Tenant.remove({ id: id });

Expected behavior
Unique type fields should be removed alongwith the Model Item.

batchWrite fails

I have a batch write with one deleteItem and two create operations.

It fails, but if I change condition on this line in Expression.js, it starts to work.

            } else if (op == 'delete') {
                args = { Key: key }
-            } else if (op == 'update') {
+            } else if (op == 'put') {
                args = { Item: values }
            }

Hybrid build distribution is broken

The current build creates

  • dist/mjs/index.mjs
  • dist/cjs/index.cjs

But the other files under mjs and cjs use a .js extension. This breaks loading of other files. For example: loading Expression.js from Model.js does not work.

Solution is here:

https://www.sensedeep.com/blog/posts/2021/how-to-create-single-source-npm-module.html

Don't use .mjs and .cjs in package.json exports, and don't use type in top level package.json and instead have per-cjs/mjs package.json files with their own type set to commonjs or module.

Example from README throws errors in TypeScript

Code from the README:

import Dynamo from 'dynamodb-onetable/Dynamo';
import {Entity, Model, Table} from 'dynamodb-onetable';
import {DynamoDBClient} from '@aws-sdk/client-dynamodb';

const client = new Dynamo({client: new DynamoDBClient({})});

const MySchema = {
    indexes: {
        primary: { hash: 'pk', sort: 'sk' },
        gs1:     { hash: 'gs1pk', sort: 'gs1sk', follow: true },
    },
    models: {
        Account: {
            pk:          { value: 'account:${name}' },
            sk:          { value: 'account:' },
            id:          { type: String, uuid: true, validate: /^[0-9A-F]{32}$/i },
            name:        { type: String, required: true },
            status:      { type: String, default: 'active' },
            zip:         { type: String },
        },
        User: {
            pk:          { type: String, value: 'account:${accountName}' },
            sk:          { value: 'user:${email}' },
            id:          { type: String, required: true },
            accountName: { type: String, required: true },
            email:       { type: String, required: true },
            firstName:   { type: String, required: true },
            lastName:    { type: String, required: true },
            username:    { type: String, required: true },
            role:        { type: String, enum: ['user', 'admin'], required: true, default: 'user' },
            balance:     { type: Number, default: 0 },

            gs1pk:       { value: 'user-email:${email}' },
            gs1sk:       { value: 'user:' },
        },
    },
};

const table = new Table({
    client: client,
    name: 'MyTable',
    schema: MySchema,
});

throws TypeScript errors because of:

  • pk and sk fields do not have type defined - if String is default, types do not respect that
  • User.balance field type Number is incompatible:
TS2322: Type '{ indexes: { primary: { hash: string; sort: string; }; gs1: { hash: string; sort: string; follow: boolean; }; }; models: { Account: { pk: { type: StringConstructor; value: string; }; sk: { type: StringConstructor; value: string; }; id: { ...; }; name: { ...; }; status: { ...; }; zip: { ...; }; }; User: { ...; }; }; }' is not assignable to type 'OneSchema'.   Types of property 'models' are incompatible.     Type '{ Account: { pk: { type: StringConstructor; value: string; }; sk: { type: StringConstructor; value: string; }; id: { type: StringConstructor; uuid: boolean; validate: RegExp; }; name: { ...; }; status: { ...; }; zip: { ...; }; }; User: { ...; }; }' is not assignable to type '{ [key: string]: OneModelSchema; }'.       Property 'User' is incompatible with index signature.         Type '{ pk: { type: StringConstructor; value: string; }; sk: { type: StringConstructor; value: string; }; id: { type: StringConstructor; required: boolean; }; ... 8 more ...; gs1sk: { ...; }; }' is not assignable to type 'OneModelSchema'.           Property 'balance' is incompatible with index signature.             Type '{ type: NumberConstructor; default: number; }' is not assignable to type 'OneFieldSchema'.               Types of property 'default' are incompatible.                 Type 'number' is not assignable to type 'string | (() => any) | undefined'.

On top of that, there are missing commas in the example code.

[BUG]: Table.createTable fails for definitions using local secondary indexes

Table.createTable fails when creating a table as follows:

const schema = {
    indexes: {
        primary: { hash: 'pk', sort: 'sk' },
        ls1: { hash: 'pk', sort: 'ls1sk', project: 'all' },
        ls2: { hash: 'pk', sort: 'ls2sk', project: 'all' },
    },
    models: {
        User: {
            //  Yes, this is a bad PK and puts all users in the same partition
            pk:         { type: String, value: 'user#' },
            sk:         { type: String, value: 'user#${id}' },
            id:         { type: String, uuid: true },
            name:       { type: String },
            email:      { type: String },

            ls1sk:      { type: String, value: 'user#${name}' },
            ls2sk:      { type: String, value: 'user#${_type}' },
        }
    }
}


const table = new Table({
    name: 'LocalTestTable',
    client: Client,
    schema,
})

let result: any = await table.createTable()

The create fails with duplicate pk attributes.

Is backward pagination supported?

Hello!

First of all... this library is just awesome!! It simplifies a lot working with dynamo when it comes to one table design.

I'm new to dynamodb-onetable and I'm evaluating its use in my developments. So far, everything is almost covered. However I haven't found in the documentation how to retrieve the previous page while paginating (it might be there though). I saw find results include a start property to help with next page management. After digging a bit into the code, I saw it maps to LastEvaluatedKey.

There are use cases in which backward navigation is quite useful (for instance when displaying live feed). Is there a straight API to do so within dynamodb-onetable? I guess I can get the first item of a collection and use it as ExclusiveStartKey; and then perform a query by negating the reverse flag (based on ScanIndexForward, this might require to reverse results). However, since the library hides key attributes. This add some extra logic.

It would be nice if the library could handle this scenario in the same fashion it handles forward pagination. Maybe find results could include a first property with the key attributes of the first item. That way is would be easy to paginate backwards:

let items: any = await User.find({accountId}, {limit: 10, start});

// Then, to get the previous page we could do:
await User.find({accountId}, {limit: 10, start: items.first, reverse: true}));

Would this make sense?

[BUG]: Can't perform multiple updates in a single update expression

Copied from Discussion #55

The issue is when doing an update that combines updated attributes and removed attributes, the updates get lost. The remove takes precedence. Should be able to do both update and remove in one expression.

I am trying to handle a scenario where we have to update a table item with new value as well as remove the secondary index (gsi). Is there a way we can handle that?

Please find the example below.

schema = {
    indexes: {
      primary: { hash: 'pk', sort: 'sk' },
      gsi1: { hash: 'gsi1pk', sort: 'gsi1sk', project: 'all', follow: true },
      gsi2: { hash: 'gsi2pk', sort: 'gsi2sk', follow: true },
      gsi3: { hash: 'gsi3pk', sort: 'gsi3sk', follow: true },
    },
    models: {
      Mailbox: {
        pk: { type: String, value: 'mail#${id}' },
        sk: { type: String, value: 'mail#${id}' },
        read: { type: Boolean },
        subject: { type: String },
        desc: { type: String },
        body: { type: String },
        userId: { type: String, required: true },
        id: { type: String, required: true, uuid: 'ulid' },
        gsi1pk: {
          type: String,
          value: 'user#${userId}',
        },
        gsi1sk: {
          type: String,
          value: 'mail#${id}',
        },
        gsi2pk: {
          type: String,
          value: 'user#${userId}#unread',
        },
        gsi2sk: {
          type: String,
          value: 'mail#${id}',
        },
        _type: { type: String, filter: false, value: 'Mailbox' },
      },
    },
  };
table = new Table({
    client: client,
    name: 'table-name',
    delimiter: '#',
    schema: schema,
  });
  mailboxModel = this.table.getModel('Mailbox');

Here I need the GSI 2 to only include the mails that are unread.

When i try the following, it's just removing GSI2 but not updating the read status in main table.

return this.mailBoxModel.update(data, {
      log: true,
      updateIndexes: true,
      remove: data.read ? ['gsi2pk', 'gsi2sk'] : [],
    });

Can you please check and let me know if there is a better way to handle this scenario?

Appreciate your help. Thanks!

[BUG]: createTable() fails with "TypeError: Cannot read property 'createTable' of undefined"

Describe the bug

I'm trying to create a DynamoDB Table using the createTable method from the Table class but it fails with "TypeError: Cannot read property 'createTable' of undefined". See how to reproduce it and full error message below.

Node version: v14.6.0
Project deps:

  "dependencies": {
    "@aws-sdk/client-dynamodb": "^3.17.0",
    "@aws-sdk/util-dynamodb": "^3.17.0",
    "@babel/polyfill": "^7.12.1",
    "core-js": "^3.13.0",
    "dynamodb-onetable": "^1.4.2"
  },
  "devDependencies": {
    "@babel/cli": "^7.14.3",
    "@babel/core": "^7.14.3",
    "@babel/preset-env": "^7.14.2"
  }

To Reproduce

import Dynamo from 'dynamodb-onetable/Dynamo'
import { Table } from 'dynamodb-onetable'
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'

const client = new Dynamo({ client: new DynamoDBClient({ region: 'dev', endpoint: 'http://localhost:8000' }) })

const table = new Table({
    client: client,
    name: 'TestLocal2',
    uuid: 'ulid',
    delimiter: '#',
    schema: {
        indexes: {
            primary: { hash: 'pk', sort: 'sk' },
            gs1:     { hash: 'gs1pk', sort: 'gs1sk', follow: true },
        },
        models: {
            User: {
                pk:          { type: String, value: 'USR#${id}' },
                sk:          { type: String, value: 'USR#${id}' },
                id:          { type: String, uuid: true },
                name:        { type: String, required: true },
                status:      { type: String, default: 'active' },
                zip:         { type: String },
            },
            Event: {
                pk:          { type: String, value: 'USR#${userId}' },
                sk:          { type: String, value: 'EVT#${id}' },
                id:          { type: String, uuid: true },
                userId:      { type: String, required: true },
                name:        { type: String, required: true },
                gs1pk:       { type: String, value: 'EVT#${id}' },
                gs1sk:       { type: String, value: 'EVT#${id}' },
            }
        }
    },
    logger: (type, message, context) => {
        if (type == 'trace' || type == 'data') return
        console.log(type, message, JSON.stringify(context, null, 4))
    }
})

const User = table.getModel('User')
const Event = table.getModel('Event')

const main = async () => {
    try {
        await table.createTable()
    } catch (e) {
        console.log(e)
    }
}

main()

I compile this script with Babel: babel index.js --out-dir dist

And run it with node dist/index.js

Which results in this error:

TypeError: Cannot read property 'createTable' of undefined
    at Table.<anonymous> (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/dynamodb-onetable/dist/cjs/Table.js:256:46)
    at Generator.next (<anonymous>)
    at /some-path/2021-05-27-dynamodb-onetable-test/node_modules/dynamodb-onetable/dist/cjs/Table.js:11:71
    at new Promise (<anonymous>)
    at __awaiter (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/dynamodb-onetable/dist/cjs/Table.js:7:12)
    at Table.createTable (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/dynamodb-onetable/dist/cjs/Table.js:182:16)
    at _callee$ (/some-path/2021-05-27-dynamodb-onetable-test/dist/index.js:138:26)
    at tryCatch (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/regenerator-runtime/runtime.js:63:40)
    at Generator.invoke [as _invoke] (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/regenerator-runtime/runtime.js:293:22)
    at Generator.next (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/regenerator-runtime/runtime.js:118:21)

Expected behavior
A new Table "TestLocal2" is created.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment (please complete the following information):

  • OS: macOS Big Sur
  • Node Version: 14.6.0

Additional context
I'm using the local version of DynamoDB (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html)

Model.get does not respect fields param

  const user1 = await RoleModel.get(
    {
      name: 'admin1',
    },
    {
      fields: ['name', 'created'],
    },
  );

context is:

{
  "cmd": {
    "TableName": "local-main",
    "Key": {
      "pk": "rbac",
      "sk": "Role:admin1"
    },
    "ConsistentRead": false
  },
  "op": "get",
  "properties": {
    "title": "admin1"
  },
  "params": {
    "parse": true,
    "high": true,
    "hidden": true,
    "fields": [
      "title",
      "created"
    ]
  },
  "elapsed": 0.021
}

ProjectionExpression is empty
problem is here

[BUG]: Unable to create GSI's without sort key

Describe the bug
DynamodB allows GSI's to be created (from Console) without sort key. But when we use this library we are not able to create GSI without SORT key.
To Reproduce
Steps to reproduce the behavior:
I tried to reproduce the issue using the sample provided in you repository - crud. You can take following scrip as reference
and execute it. It will not allow to create table and throw error

Make sure TestCrud table does not exists before running following programs

ERROR

(node:87375) UnhandledPromiseRejectionWarning: ValidationException: Attribute name must be specified.

Script to test.

/*
    Demonstrate simple CRUD with OneTable
 */
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { Table } from "dynamodb-onetable";
//  For AWS V3
import Dynamo from "dynamodb-onetable/Dynamo";

const client = new Dynamo({
  client: new DynamoDBClient({
   // region: "ap-south-1",
    region: "local",
    endpoint:"http://localhost:8000"
  }),
});
/*
    Single-table schema and setup. This is used for general access and by `createTable`
 */
const table = new Table({
  name: "TestCrud",
  client: client,
  uuid: "ulid",
  delimiter: "#",
  logger: true,
  schema: {
    indexes: {
      primary: { hash: "pk", sort: "sk" },
      userName: { hash: "name"},
    },
    models: {
      User: {
        pk: { type: String, value: "user#${id}" },
        sk: { type: String, value: "user#${id}" },
        id: { type: String, uuid: true },
        name: { type: String },
        status: { type: String, default: "active" },
        zip: { type: String }
      },
    },
  },
});
//  Create a model to manage User entities
const User = table.getModel("User");
async function main() {
  if (!(await table.exists())) {
    await table.createTable();
  }
  
}
main();

LOGS

(base) Kunals-MacBook-Air:crud kunaldeshmukh$ node dist/index1.js 
info Dynamo createTable for "TestCrud" {
    "def": {
        "AttributeDefinitions": [
            {
                "AttributeName": "pk",
                "AttributeType": "S"
            },
            {
                "AttributeName": "sk",
                "AttributeType": "S"
            },
            {
                "AttributeName": "name",
                "AttributeType": "S"
            },
            {
                "AttributeType": "S"
            }
        ],
        "KeySchema": [
            {
                "AttributeName": "pk",
                "KeyType": "HASH"
            },
            {
                "AttributeName": "sk",
                "KeyType": "RANGE"
            }
        ],
        "GlobalSecondaryIndexes": [
            {
                "IndexName": "userName",
                "KeySchema": [
                    {
                        "AttributeName": "name",
                        "KeyType": "HASH"
                    },
                    {
                        "KeyType": "RANGE".  ### HERE IS THE ISSUE - WHERE SORT KEY IS GOING EMPTY.  THIS OBJECT SHOULD NOT BE THERE
                    }
                ],
                "Projection": {
                    "ProjectionType": "ALL"
                }
            }
        ],
        "TableName": "TestCrud",
        "BillingMode": "PAY_PER_REQUEST"
    }
}
(node:87839) UnhandledPromiseRejectionWarning: ValidationException: Attribute name must be specified.
    at deserializeAws_json1_0CreateTableCommandError (/Users/kunaldeshmukh/Downloads/test/crud/node_modules/@aws-sdk/client-dynamodb/dist/cjs/protocols/Aws_json1_0.js:972:41)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async /Users/kunaldeshmukh/Downloads/test/crud/node_modules/@aws-sdk/middleware-serde/dist/cjs/deserializerMiddleware.js:6:20
    at async /Users/kunaldeshmukh/Downloads/test/crud/node_modules/@aws-sdk/middleware-signing/dist/cjs/middleware.js:12:24
    at async StandardRetryStrategy.retry (/Users/kunaldeshmukh/Downloads/test/crud/node_modules/@aws-sdk/middleware-retry/dist/cjs/StandardRetryStrategy.js:51:46)
    at async /Users/kunaldeshmukh/Downloads/test/crud/node_modules/@aws-sdk/middleware-logger/dist/cjs/loggerMiddleware.js:6:22
    at async Dynamo.send (file:///Users/kunaldeshmukh/Downloads/test/crud/node_modules/dynamodb-onetable/dist/mjs/Dynamo.js:77:16)
    at async Dynamo.createTable (file:///Users/kunaldeshmukh/Downloads/test/crud/node_modules/dynamodb-onetable/dist/mjs/Dynamo.js:22:16)
    at async Table.createTable (file:///Users/kunaldeshmukh/Downloads/test/crud/node_modules/dynamodb-onetable/dist/mjs/Table.js:248:20)
    at async main (file:///Users/kunaldeshmukh/Downloads/test/crud/dist/index1.js:46:5)
(node:87839) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 15)
(node:87839) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Expected behavior

As per AWS documentation we can create GSI without sort key here is the documentation : https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-6.html

Library should allow to create GSI without SORT key.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment (please complete the following information):

  • MAC
  • 12x

Additional context
Add any other context about the problem here.

[BUG]: Table.queryItems fails due to Model.queryItems defining a generic type

Table.groupByType will iterate over items.start and throw an exception

To reproduce.

    let items = await db.queryItems({pk})
    let results = db.groupByType(items)

Throws exception in queryItems.

The issue is described in pull request:

#47

The solution is for _Generic type objects to set Model.generic and for queryItems, putItems and updateItems in Model to test if this is set and then NOT define the type.

[QUESTION]: Typescript - can we enforce mandatory attributes in entity types?

In the TypeScript section of the docs it says:

"Using TypeScript dynamic typing, OneTable automatically converts your OneTable schema into fully typed generic Model APIs."

It gives this example:

let Account: Model<AccountType> = table.getModel<AccountType>('Account')

let account = await Account.update({ name: 'Acme', // OK unknown: 42, // Error })

Vis-a-vis the field names we do get this type safety, which is great. However because all the fields in the generated types are optional we don't get checking for mandatory attributes.

Due to this we can sometimes lose the benefits of the type safety. E.g. when you resort to casting to avoid spurious transpiler errors about missing mandatory attributes.

const myApiType: ApiType = {... myModelType} as ApiType

Do we think it would it possible to enforce mandatory attributes in the type (as defined in the schema)? Perhaps this isn't possible, in which case I wonder if there's a workaround the library could provide...

Cheers!

[BUG]: exception when field.value is a function

in Model.js line 207 we check if field.value exists then we pass to getValueVars where we use regex on the value

// line 222
v.replace(/\${(.*?)}/g, (match, varName)

when v is not a string but a function that fails

to fix that I changed line 207 to

if (field.value && typeof field.value !== 'function')

but I am not sure if that is the right way

Incomplete typescript instructions and inaccurate type spec

First, I really like the concept of onetable! It makes working with single table designs a lot easier.

I wasn't able to make Model work with instructions in README, but had to add options parameter to the Model constructor

const EmailValidationModel = new Model<EmailValidation>(table, 'EmailValidation', {
    indexes: schema.indexes,
    timestamps: true,
    //@ts-ignore
    fields: schema.models.EmailValidation,
})

Also, typing suggest that options could include models, but constructor expects fields

[BUG]: Model.create reports error for a field of type Date

Describe the bug
I have a schema containing a model with a field of type Date. When I use the create method, the compiler complains that "Type 'Date' is not assignable to type 'undefined'."

To Reproduce
The code below doesn't compile and reports the following error:

src/repo/Error Schema.ts:21:59 - error TS2322: Type 'Date' is not assignable to type 'undefined'.

21 void Foo.create({ pk: 'pk', sk: 'sk', strField: 'field1', dateField: new Date() })
~~~~~~~~~

src/repo/Error Schema.ts:11:13
11 dateField: { type: Date, required: true }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The expected type comes from property 'dateField' which is declared here on type 'Entity<{ pk: { type: StringConstructor; required: boolean; }; sk: { type: StringConstructor; required: boolean; }; strField: { type: StringConstructor; required: boolean; }; dateField: { ...; }; }>'

import { Entity, Model, Table } from 'dynamodb-onetable'

const mySchema = {
    indexes: { primary: { hash: 'pk', sort: 'sk' } },
    models: {
        Model1: {
            pk: { type: String, required: true },
            sk: { type: String, required: true },

            strField: { type: String, required: true },
            dateField: { type: Date, required: true }
        }
    }
}

type MyType = Entity<typeof mySchema.models.Model1>

export const table = new Table({ name: 'MyTable', delimiter: '#', timestamps: true, isoDates: true, schema: mySchema })
export const Foo: Model<MyType> = table.getModel<MyType>('Foo')

void Foo.create({ pk: 'pk', sk: 'sk', strField: 'field1', dateField: new Date() })

Expected behavior
Code to compile without errors

Environment (please complete the following information):

  • OS - windows
  • Node Version - 14
  • Typescript - 4.3.5

Comparsion with DynamoDBToolbox

I've been thinking about the difference between your OneTable and that DynamoDBToolbox. They look pretty similar, but your library has some other extensions like migrations that are appealing. I've heard Rick Houlihan in the podcast talk to Alex DeBrie about these two libraries, and I don't understand why your library has so few watches. It looks great, but can you tell us what are the other benefits of your OneTable?

I would like to ask what it's like to use your library in TypeScript projects. This is something that DynamoDBToolbox has had from the beginning, but it's not very good, or as I would expect from a TS project.

There are currently three libraries that I have noted that are usable: OneTable, DynamoDBToolbox, and TypeDorm (which is ORM). I think a small comparison could help other people choose the right tool to work with DynamoDB.

Thank you very much 🙏

cjs and mjs modules

Hi,

I read up on your module strategy here.
To find out which module gets used when, I created this repo, where I modified the dynamodb-onetable package to log something based on the current module (Hello from cjs vs. Hello from mjs). After that, I tried different build options:

When bundling with esbuild, it outputs Hello from mjs, when building with tsc (default config tsc --init) or running with node directly it outputs Hello from cjs.

My question: Shouldn't it output Hello from mjs when building with tsc.

Please have a look at this PR, to see what I did in detail: https://github.com/hffmnn/module_test/pull/1

[ENHANCEMENT]: Add support for nanoid as well as uuid

nanoid produces a smaller, faster, at least as strong and more compact (21 characters instead of 36) code than uuidv4, and is more customisable - see Comparison with UUID

I would really prefer to use nanoid, and it would be more (slightly) convenient for dynamodb-onetable to automatically generate it.

Certainly not critical, but would be nice to have.

[BUG]: remove in a batch

is it possible to run multiple Model.remove in a batch? I am using version 1.5.4

I have a list of ids I want to remove with the following code

const batch = this.prepareBatch<CorrespondenceLogByEventType>();

for (const logId of logIds) {
  await this.logByEventType.remove(
    { type: CorrespondenceEventType.UNREAD, logId },
    { batch, many: true, log: this.logEnabled }
  );
}

await this.processBatchWrite<CorrespondenceLogByEventType>(batch);

when I execute that code it throws

// Expression.js
throw new Error('Invalid filters with batch operation');

TypeScript error when specifying "fields" in params

The specific error is "error TS2322: Type '{ index: string; parse: true; reverse: true; fields: string[]; }' is not assignable to type 'OneParams'. Object literal may only specify known properties, and 'fields' does not exist in type 'OneParams'". Reproducible on 1.3.6.

Maybe consider the following as a possible fix? (worked for me on 1.3.6)

--- a/src/Model.d.ts
+++ b/src/Model.d.ts
@@ -130,6 +130,7 @@ export type OneParams = {
     delete?: object,
     execute?: boolean,
     exists?: boolean,
+    fields?: string[]
     hidden?: boolean,
     index?: string,
     limit?: number,

dynamodb-onetable/Dynamo is not exported

src/db.ts:3:20 - error TS2307: Cannot find module 'dynamodb-onetable/Dynamo' or its corresponding type declarations.

3 import Dynamo from 'dynamodb-onetable/Dynamo'
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~

TS: 1 error

[BUG]: Table.groupByType fails on items.start

The Table.groupByType fails to iterate using Object.entries when items.start is defined and is set to null/undefined

    let items = await db.queryItems({})
    db.groupByType(items)

groupByType will throw an exception if items.start is set to null/undefined. This happens when the query returns less than a page of results.

The solution is to iterate over the array not over all keys

-        for (let [index, item] of Object.entries(items)) {
+        for (let item of items) {

OnUpdate features in Model schema

Wondering if there's the on update feature: Forces default values to be passed on every update.
as in dynamodb-toolbox its provided with such feature.
Coz I'm recently working on the project using dynamodb-toolbox but it seems not to provide cli for db migration & auto id generation, log emit, validate etc which I found in dynamodb-onetable so Im considering a change of dynamodb library.

TypeScript Errors

This project looks really interesting. However, I am getting several TypeScript compile errors:

node_modules/dynamodb-onetable/dist/cjs/Model.d.ts:44:11 - error TS2304: Cannot find name 'OneType'.

44     type: OneType,
             ~~~~~~~

node_modules/dynamodb-onetable/dist/cjs/Model.d.ts:188:2 - error TS1036: Statements are not allowed in ambient contexts.

188 };
     ~

node_modules/dynamodb-onetable/dist/cjs/Table.d.ts:21:25 - error TS2314: Generic type 'Model<T>' requires 1 type argument(s).

21     intercept?: (model: Model, op: string, rec: {}, params: OneParams, raw?: {}) => void,
                           ~~~~~

node_modules/dynamodb-onetable/dist/cjs/Table.d.ts:57:2 - error TS1036: Statements are not allowed in ambient contexts.

57 };
    ~

Found 4 errors.

Any ideas? Thanks

[Feat]: Make operations non-blocking

Describe the bug
I want to use the library to a lot of parallel IO. But because the calls all to an await it only performs one operation at at time and runs too slowly.

To Reproduce

Suppose I want to create lots of objects, I want to be able to write code like this so the creation runs in parallel.

export async function create(bordereaux: BordereauxEntityType[]): Promise<BordereauxEntityType[]> {
    const promises = bordereaux.map(async b => Bordereaux.create(b))
    return Promise.all(promises)
}

However with the awaits inside the create call this is going to end up blocking. Obviously in this case I could use a batch write but once my logic becomes more complicated I need operations to by asynchronous and running in parallel.

For example I might read a file of 500 lines. For each line I need to read two objects from the database, combine them and write a new object. I want all the IO to be running in parallel as much as possible to minimise the runtime.

Expected behaviour
None of the operations in the library await on a promise, instead they chain promises.

For example the create function is currently implemented as:

    async create(properties, params = {}) {
        ({ params, properties } = this.checkArgs(properties, params, { parse: true, high: true, exists: false }));
        let result;
        if (this.hasUniqueFields) {
            result = await this.createUnique(properties, params);
        }
        else {
            result = await this.putItem(properties, params);
        }
        return result;
    }

but could be written as

    async create(properties, params = {}) {
        ({ params, properties } = this.checkArgs(properties, params, { parse: true, high: true, exists: false }));
        let result;
        if (this.hasUniqueFields) {
            return this.createUnique(properties, params);
        }
        else {
            return this.putItem(properties, params);
        }
    }

This also avoids creating an intermediate promise when you do return result

I could have a go at submitting a pull request for this if it helps.

Environment (please complete the following information):

  • OS - Windows
  • Node Version - 14
  • typescript - 4.3.5

Trouble importing Dynamo

This issue documents some of the issues with importing the Dynamo helper for use with the AWS SDK V3.

The helper imports the AWS SDK V3 and is used like:

import Dynamo from 'dynamodb-onetable/Dynamo'
import {Table} from 'dynamodb-onetable'
import {DynamoDBClient} from '@aws-sdk/client-dynamodb'
const client = new Dynamo({client: new DynamoDBClient(params)})

To import a subdirectory like Dynamo, node used a package.json#exports which configured multiple entry points. Unfortunately TypeScript does not yet support this syntax.

To solve this, 1.3.1 includes a separate ./Dynamo/package.json file.

Previously in 1.3.0 we attempted to export Dynamo from the index.js so it could be imported with Table, however while this worked when using tree shaking, it failed without shaking as the V3 SDK was being universally imported and if the V2 SDK was being used, it would fail at runtime.

When TypeScript supports exports, we can remove the ./Dynamo/package.json.

[BUG]: not able to use ksuid -Value not defined for required field

Describe the bug
When I set use ksuid on model and table definition the value is null or undefined.
To Reproduce
Steps to reproduce the behavior:

Create model with ksuid : true

 pk: { type: String },
            sk: { type: String, value: 'ACT#${actID}' },
            internalActID: { type: String },
            actID: { type: String, ksuid: true, required: true },
           
       .... other code

Update Table Definition / constructor with

import ksuid = require('ksuid');

  this.usersTable = new Table({
            timestamps: true,
            name: TableNameConstants.USERS_TABLE,
            ksuid: () => {
                return ksuid.randomSync().string;
            },

------ other code

Log

{\"model\":\"Accounts\",\"properties\":{\"opnBal\":0,\"opnBalCurrency\":\"string\",\"actDash\":true,\"actDate\":\"string\",\"actDesc\":\"string\",\"actName\":\"string\",\"actNo\":0,\"actType\":\"string\",\"transactionLog\":[\"string\"],\"closingAmt\":0,\"internalActID\":\"0\",\"pk\":\"fbf909a0-a0e1-11eb-9480-979110379335\",\"_type\":\"Accounts\",\"created\":\"2021-07-05T07:59:31.676Z\",\"updated\":\"2021-07-05T07:59:31.676Z\"},\"details\":{\"sk\":\"Value not defined for required field \\\"sk\\\"\",\"actID\":\"Value not defined for required field \\\"actID\\\"\"}}"}

Expected behavior
sk should be updated with provided implementation for ksuid

Screenshots

Environment (please complete the following information):

  • Mac
  • 12.x

Additional context
node library used ksuid

[FEAT]: table.fetch method - supported?

Hi, firstly great job with the onetable api.

I've been struggling a bit to figure out how to get multiple items (with differing types) given a single partition key. It's possible I've missed something along the way (and apols if so) but here's what I found...

The only example of such an operation in the sample code is in the typescript sample. (I am using typescript).

However it uses table.fetch which is not mentioned in the documentation here:

https://github.com/sensedeep/dynamodb-onetable

I tried it, like so:

items = await table.fetch(["User", "UserProfile"], {pk: User:${id}})

The .d.ts file (and thus my IDE) says this returns Promise<AnyEntity[]> however I found it returns an object with keys of (Model type string) and values of (array of the associated Model type):

{
  User: [ { id: '0b4c8d6a-1c52-4784-b5da-ad1bac65a3ec', _type: 'User' } ],
  UserProfile: [
    {
      id: '0b4c8d6a-1c52-4784-b5da-ad1bac65a3ec',
      email: '[email protected]',
      firstName: 'Colten',
      lastName: 'Monahan',
      displayName: 'Colten Monahan',
      _type: 'UserProfile'
    }
  ]
}

(Not real data, don't worry ;-)

So... I did some fiddling around with casting and was able to get hold of the results ok.

So perhaps actions here might be to 1) document the fetch method 2) fix the types def for it?

Request: Example Project

I'm finding the docs a bit difficult to consume - especially since they are dispersed among 3 projects and blog posts. I think a complete working example to download and play with would help a lot.

[FEAT]: Defining structure (properties) of a model attribute of type Object

First of all, thank you for the amazing library, it helped me a lot with enforcing the single table design pattern in DynamoDB! :)

I was wondering if you had any thoughts on adding support for defining a structure of a model attribute that has a type of an Object. Specifically, I have a property in my model defined as follows:

location: { type: Object, required: true }

What (in my case) would be very helpful feature is to be able to define the properties of that location object and then have those properties added to the TypeScript type by the library. For example I would want to add those properties to my location object:

zip: { type: String, required: true }
state: { type: String, required: true },
city: { type: String, required: true },

Would this be something that's useful and possible to implement?

[BUG]: Can't queryItems via GSI for table without model

Taken from discussion #51

This code fails:

/*
    Demonstrate simple CRUD with OneTable
 */
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { Table } from "dynamodb-onetable";
//  For AWS V3
import Dynamo from "dynamodb-onetable/Dynamo";

const client = new Dynamo({
  client: new DynamoDBClient({
    region: "local",
    endpoint: "http://localhost:8000",
  }),
});
/*
    Single-table schema and setup. This is used for general access and by `createTable`
 */
const table = new Table({
  name: "TestCrud",
  client: client,
  uuid: "ulid",
  delimiter: "#",
  logger: true,
  schema: {
    indexes: {
      primary: { hash: "pk", sort: "sk" },
      emailIndex: { hash: "email" },
    },
    models: {
      User: {
        pk: { type: String, value: "user#${email}" },
        sk: { type: String, value: "user#${email}" },
        id: { type: String, uuid: true },
        email: { type: String, required: true },
        name: { type: String },
        status: { type: String, default: "active" },
        zip: { type: String },
      },
    },
  },
});
//  Create a model to manage User entities
const User = table.getModel("User");
async function main() {
  if (!(await table.exists())) {
    await table.createTable();
  }

  let user = await User.create(
    {
      email: "[email protected]",
      name: "Peter Smith",
    },
    { log: true }
  ); //  Emit console trace for the command and result
  console.log("CREATED user", user);


  let users = await table.queryItems(
    { pk: "user#[email protected]" },
    { parse: true }
  );
  console.log("Query on Primary Index", users);


  users = await table.queryItems(
    { email: "[email protected]" },
    { index: "emailIndex", parse: true }
  );
  console.log("Query on GSI Index", users);
}

main();

TypeScript error when assigning to an entity field with schema type "Array"

The specific error when assigning, for example, an array of strings to such a field is "error TS2322: Type 'string' is not assignable to type 'undefined'." Reproducible on 1.3.6.

You may want to consider the following possible fix. It worked for me in 1.3.6.

--- a/src/Model.d.ts
+++ b/src/Model.d.ts
@@ -91,7 +91,7 @@ type EntityField<T extends OneTypedField> =
     : T['type'] extends BooleanConstructor ? boolean
     : T['type'] extends ObjectConstructor ? object
     : T['type'] extends DateConstructor ? Date
-    : T['type'] extends ArrayConstructor ? []
+    : T['type'] extends ArrayConstructor ? any[]
     : never;

Is lack of DocumentClient in aws-sdk v3 a breaking change?

There is much discussion around the decision by the AWS development team to leave DocumentClient capability out of v3 of the Javascript AWS-SDK. See #1223, and the response at #2031.

Does this mean your excellent library will only work with V2? Will there be any plans to support v3?

Modeling

using typescript, how can I model an attribute as Object or Array of Object?
And, Is there a better way to construct an entity with adjacency list pattern?
for example a top level entity called user, and under the user entity there is userProfile, userPayment, etc

TypeScript support

Hey, the library looks really interesting and I would definitely give it a go, if not a lack of TypeScript support.

[BUG]: TypeError: Cannot read property 'ConditionExpression' of null

Describe the bug
I'm evaluating dynamodb-onetable for a project and I can't seem to make it work, even for just a basic "create" operation, please see code sample below.

  • Node version: v14.6.0
  • Project deps:
  "dependencies": {
    "@aws-sdk/client-dynamodb": "^3.17.0",
    "@aws-sdk/util-dynamodb": "^3.17.0",
    "@babel/polyfill": "^7.12.1",
    "core-js": "^3.13.0",
    "dynamodb-onetable": "^1.4.1"
  },
  "devDependencies": {
    "@babel/cli": "^7.14.3",
    "@babel/core": "^7.14.3",
    "@babel/preset-env": "^7.14.2"
  }

To Reproduce

import Dynamo from 'dynamodb-onetable/Dynamo'
import { Table } from 'dynamodb-onetable'
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'

/**
 *  in order to use this layout, you will need to start up DynamoDB local
 *  and provision the table
 *
 *  docker run -p 8000:8000 amazon/dynamodb-local
 *
aws dynamodb create-table \
   --endpoint-url http://localhost:8000 \
   --table-name TestLocal \
   --attribute-definitions AttributeName=pk,AttributeType=S AttributeName=sk,AttributeType=S \
     AttributeName=gs1pk,AttributeType=S AttributeName=gs1sk,AttributeType=S \
     AttributeName=gs2pk,AttributeType=S AttributeName=gs2sk,AttributeType=S \
     AttributeName=gs3pk,AttributeType=S AttributeName=gs3sk,AttributeType=S \
   --key-schema KeyType=HASH,AttributeName=pk KeyType=SORT,AttributeName=sk \
   --billing-mode PAY_PER_REQUEST \
   --global-secondary-indexes 'IndexName=gs1,KeySchema=[{KeyType="HASH",AttributeName="gs1pk"},{KeyType="SORT",AttributeName="gs1sk"}],Projection={ProjectionType="ALL"}' \
     'IndexName=gs2,KeySchema=[{KeyType="HASH",AttributeName="gs2pk"},{KeyType="SORT",AttributeName="gs2sk"}],Projection={ProjectionType="ALL"}' \
     'IndexName=gs3,KeySchema=[{KeyType="HASH",AttributeName="gs3pk"},{KeyType="SORT",AttributeName="gs3sk"}],Projection={ProjectionType="ALL"}'
 */

const client = new Dynamo({ client: new DynamoDBClient({ region: 'us-west-1', endpoint: 'http://localhost:8000' }) })

const table = new Table({
    client: client,
    name: 'TestLocal2',
    uuid: 'ulid',
    delimiter: '#',
    schema: {
        indexes: {
            primary: { hash: 'pk', sort: 'sk' },
            gs1:     { hash: 'gs1pk', sort: 'gs1sk', follow: true },
        },
        models: {
            User: {
                pk:          { type: String, value: 'USR#${id}' },
                sk:          { type: String, value: 'USR#${id}' },
                id:          { type: String, uuid: 'ulid' },
                name:        { type: String, required: true },
                status:      { type: String, default: 'active' },
                zip:         { type: String },
            },
            Event: {
                pk:          { type: String, value: 'USR#${userId}' },
                sk:          { type: String, value: 'EVT#${id}' },
                id:          { type: String, uuid: 'ulid' },
                name:        { type: String, required: true },
                gs1pk:       { type: String, value: 'EVT#${id}' },
                gs1sk:       { type: String, value: '' },
            }
        }
    }
})

const User = table.getModel('User')
const Event = table.getModel('Event')

const main = async () => {
    try {
        let account = await User.create({
            name: 'Eric',
        })

        console.log(account)
    } catch (e) {
        console.log(e)
    }
}

main()

I compile this script with Babel: babel index.js --out-dir dist

And run it with node dist/index.js

Which results in this error:

TypeError: Cannot read property 'ConditionExpression' of null
    at serializeAws_json1_0PutItemInput (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/client-dynamodb/dist/cjs/protocols/Aws_json1_0.js:5483:19)
    at Object.serializeAws_json1_0PutItemCommand (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/client-dynamodb/dist/cjs/protocols/Aws_json1_0.js:344:27)
    at serialize (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/client-dynamodb/dist/cjs/commands/PutItemCommand.js:121:30)
    at /some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/middleware-serde/dist/cjs/serializerMiddleware.js:5:27
    at /some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/middleware-logger/dist/cjs/loggerMiddleware.js:6:28
    at DynamoDBClient.send (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/smithy-client/dist/cjs/client.js:23:20)
    at Dynamo.<anonymous> (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/dynamodb-onetable/dist/cjs/Dynamo.js:95:38)
    at Generator.next (<anonymous>)
    at /some-path/2021-05-27-dynamodb-onetable-test/node_modules/dynamodb-onetable/dist/cjs/Dynamo.js:17:71
    at new Promise (<anonymous>)

I've also tried to set all the attributes of the model:

let account = await User.create({
    id: '01ARZ3NDEKTSV4RRFFQ69G5FAV',
    name: 'Eric',
    status: 'active',
    zip: 'XYZ'
})

and a get another error:

ResourceNotFoundException: ResourceNotFoundException
    at deserializeAws_json1_0PutItemCommandError (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/client-dynamodb/dist/cjs/protocols/Aws_json1_0.js:2904:41)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async /some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/middleware-serde/dist/cjs/deserializerMiddleware.js:6:20
    at async /some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/middleware-signing/dist/cjs/middleware.js:12:24
    at async StandardRetryStrategy.retry (/some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/middleware-retry/dist/cjs/defaultStrategy.js:56:46)
    at async /some-path/2021-05-27-dynamodb-onetable-test/node_modules/@aws-sdk/middleware-logger/dist/cjs/loggerMiddleware.js:6:22

Expected behavior
A User item is created

Screenshots
If applicable, add screenshots to help explain your problem.

Environment (please complete the following information):

  • OS: macOS Big Sur
  • Node Version: 14.6.0

Additional context
I'm using the local version of DynamoDB (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html)

Cannot install npm package in node.js APP.

Command : npm i onetable-cli -g
Error :
npm ERR! code ENOLOCAL
npm ERR! Could not install from "C:\Users\jb\AppData\Roaming\npm\node_modules\onetable-cli\src\paks\js-blend" as it does not contain a package.json file.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\jb\AppData\Roaming\npm-cache_logs\2021-04-29T11_48_31_546Z-debug.log

Can someone help me with this issue?

'dynamodb-onetable/Dynamo' MODULE_NOT_FOUND

Describe the bug
NodeJS projects fails to load complaining of dynamodb-onetable/Dynamo'

Project Imports are as follows:

import Dynamo from 'dynamodb-onetable/Dynamo'
import {Table, Model, } from 'dynamodb-onetable'

import {DynamoDBClient} from '@aws-sdk/client-dynamodb'

const params = {
    /** input parameters */
    credentials: {
        accessKeyId: "", 
        secretAccessKey: "", 
        },
    region : "us-east-1"
  };
// const client = new DynamoDBClient(params);

const client = new Dynamo({client: new DynamoDBClient(params)})

[BUG]: calling .next() throws a ValidationException

Describe the bug
when I fetch some data and got back a LastEvaluatedKey from DynamoDB, then when I call

await results.next();

I got ValidationException: The provided key element does not match the schema

in Model.js line 376 we have

params = Object.assign({}, params, {start: result.LastEvaluatedKey})

when I change that to

params = Object.assign({}, params, { start: items.start });

that works fine

Expected behavior
calling .next() should not throw an exception

Environment (please complete the following information):

  • MacOS
  • Node 14

Issues with Paging find results

result.start => {"pk":{"S":"user#eWR6pYoybfADt4oBM"},"sk":{"S":"message#01F3F63MWN6H104E0698RN1XZ0"}}

start param => {"pk":{"S":"user#eWR6pYoybfADt4oBM"},"sk":{"S":"message#01F3F63MWN6H104E0698RN1XZ0"}}

They are exactly the same, but adding the start param results in this error:

2021-04-18T04:32:49.623Z	9945dda7-db39-4e55-be9a-dc1119352034	ERROR	Invoke Error 	{"errorType":"ValidationException","errorMessage":"The provided key element does not match the schema","__type":"com.amazon.coral.validate#ValidationException","name":"ValidationException","$fault":"client","$metadata":{"httpStatusCode":400,"requestId":"JH9CAULMN2P18723AI80A7GF3RVV4KQNSO5AEMVJF66Q9ASUAAJG","attempts":1,"totalRetryDelay":0},"stack":["ValidationException: The provided key element does not match the schema","    at s9i (/var/node_modules/@aws-sdk/client-dynamodb/protocols/Aws_json1_0.ts:3704:39)","    at processTicksAndRejections (internal/process/task_queues.js:93:5)","    at /var/node_modules/@aws-sdk/middleware-serde/src/deserializerMiddleware.ts:20:18","    at /var/node_modules/@aws-sdk/middleware-signing/src/middleware.ts:26:22","    at ZHe.retry (/var/node_modules/@aws-sdk/middleware-retry/src/defaultStrategy.ts:125:38)","    at /var/node_modules/@aws-sdk/middleware-logger/src/loggerMiddleware.ts:21:20","    at GEe.send (/var/node_modules/dynamodb-onetable/dist/mjs/Dynamo.js:61:16)","    at GEe.find (/var/node_modules/dynamodb-onetable/dist/mjs/Dynamo.js:30:16)","    at V8.run (/var/node_modules/dynamodb-onetable/dist/mjs/Model.js:252:30)","    at V8.queryItems (/var/node_modules/dynamodb-onetable/dist/mjs/Model.js:528:16)"]}

[BUG]: Unable to use `begins` condition with `Model.find` in TypeScript

Describe the bug
It is unclear how to properly use a begins condition when using the Model.find APIs.

This results in a compile error:

export const getEventsByDriverId = async (driverId: string, filter?: Filter): Promise<AWSEvent[]> => {
  const sk = { begins: { sk: buildPrefix(filter) } }
  const results = await EventModel.find({ driverId, sk  }, { tunnel, index: 'gs2' })
  return results as AWSEvent[]
}

This results in .for is not iterable error.

export const getEventsByDriverId = async (driverId: string, filter?: Filter): Promise<AWSEvent[]> => {
  const tunnel = { begins: { sk: buildPrefix(filter) } }
  const results = await EventModel.find({ driverId }, { tunnel, index: 'gs2' })
  return results as AWSEvent[]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.