dynamodb-onetable
dynamodb-onetable copied to clipboard
Can't remove many elements using "begins" condition
Hey
Trying to understand is it possible to use remove + many + begins_with syntax
Please check my test bellow. It looks like tunnel: { begins: { 'sk': 'user' } }
works for the find but not for the remove operation
Is it correct?
Thanks!
/*
debug.ts - Just for debug
Edit your test case here and invoke via: "jest debug"
Or run VS Code in the top level directory and just run.
*/
import {AWS, Client, Entity, Match, Model, Table, print, dump, delay} from './utils/init'
import { OneSchema } from '../src/index.js'
jest.setTimeout(7200 * 1000)
// Change with your schema
const schema: OneSchema = {
version: '0.0.1',
indexes: {
primary: { hash: 'pk', sort: 'sk' },
gs1: { hash: 'gs1pk', sort: 'gs1sk', project: 'all' },
},
models: {
User: {
pk: { type: String, value: '${_type}#' },
sk: { type: String, value: '${name}#${id}' },
gs1pk: { type: String, value: '${_type}#' },
gs1sk: { type: String, value: '${_type}#${id}' },
name: { type: String },
email: { type: String },
id: { type: String, generate: 'ulid' },
}
}
}
// Change your table params as required
const table = new Table({
name: 'DebugTable',
client: Client,
schema,
logger: true,
})
// This will create a local table
test('Create Table', async() => {
if (!(await table.exists())) {
await table.createTable()
expect(await table.exists()).toBe(true)
}
})
test('Test', async() => {
const User = table.getModel('User')
await User.create({ name: 'user1' })
await User.create({ name: 'user2' })
const created = await User.find({})
expect(created.length).toBe(2)
const found = await User.find({}, { tunnel: { begins: { 'sk': 'user' } } })
expect(found.length).toBe(2)
await User.remove({}, { many: true, tunnel: { begins: { 'sk': 'user' } } }) // Can't be removed
const exist = await User.find({})
expect(exist.length).toBe(0)
})
test('Destroy Table', async() => {
await table.deleteTable('DeleteTableForever')
expect(await table.exists()).toBe(false)
})
FAIL test/debug.ts
✓ Create Table (321 ms)
✕ Test (142 ms)
✓ Destroy Table (12 ms)
● Test
expect(received).toBe(expected) // Object.is equality
Expected: 0
Received: 2
61 |
62 | const exist = await User.find({})
> 63 | expect(exist.length).toBe(0)
| ^
64 | })
65 |
66 | test('Destroy Table', async() => {
at Object.<anonymous> (test/debug.ts:63:26)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 2 passed, 3 total
Turn logging on and we can see the actual request issued.
ie.
await User.remove({}, { log: true, many: true, tunnel: { begins: { 'sk': 'user' } } })
Remove with many operates when you don't provide an SK and internally, OneTable does a find. It will only do this if you do not provide an SK.
In your case, you implicitly provide the PK by providing the type for the PK value template. Similarly, you are providing the type which allows a partial SK. Find can use this.
So the following should do what you want I believe:
await User.remove({}, { log: true, many: true })
Hey!
Logs:
info OneTable result for "delete" "User" {
"cmd": {
"TableName": "DebugTable",
"ReturnValues": "ALL_OLD",
"Key": {
"pk": {
"S": "User#"
},
"sk": {
"S": "[object Object]"
}
}
},
"items": [],
"op": "delete",
"properties": {
"pk": "User#",
"sk": "[object Object]"
},
"params": {
"parse": true,
"exists": null,
"high": true,
"log": true,
"many": true,
"tunnel": {
"begins": {
"sk": "user"
}
},
"checked": true
}
}
await User.remove({}, { log: true, many: true })
will always remove all tems, but I want to remove some subset based on a sk composite key e.g
const found = await User.find({}, { tunnel: { begins: { 'sk': 'user1' } } })
From what I understand, it's not possible right now if Im using SK in begins/contains/...expressions with remove operation but works with find?
Yes. Currently remove many only works if you don't provide an SK like you are doing.
I'll flag this as a bug to be addressed.
Fixed this so that if you provide {many: true} to remove, it will always do a find and then remove those items.