-
Notifications
You must be signed in to change notification settings - Fork 99
nodejs: implement 130/311 benchmarks #281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2b8b171
16e0868
8778e13
ac877c4
43c6944
3a3e9b3
4d81473
ec75a13
9adde7d
7b5480e
913413c
74e745e
45603be
115b43a
4623ef8
af86479
e6093e4
0f8a3f0
ac207c7
7edfff8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,7 @@ exports.handler = async function(event) { | |
| fs.readFile(file, "utf-8", | ||
| function(err, data) { | ||
| if(err) reject(err); | ||
| resolve(Mustache.render(data, input)); | ||
| resolve({result: Mustache.render(data, input)}); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid nesting Line 26 returns 🐛 Proposed fix- resolve({result: Mustache.render(data, input)});
+ resolve(Mustache.render(data, input));🤖 Prompt for AI Agents |
||
| } | ||
| ); | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| const nosql = require('./nosql'); | ||
|
|
||
| const nosqlClient = nosql.nosql.get_instance(); | ||
| const nosqlTableName = "shopping_cart"; | ||
|
mcopik marked this conversation as resolved.
|
||
|
|
||
| async function addProduct(cartId, productId, productName, price, quantity) { | ||
| await nosqlClient.insert( | ||
| nosqlTableName, | ||
| ["cart_id", cartId], | ||
| ["product_id", productId], | ||
| { price: price, quantity: quantity, name: productName } | ||
| ); | ||
| } | ||
|
|
||
| async function getProducts(cartId, productId) { | ||
| return await nosqlClient.get( | ||
| nosqlTableName, | ||
| ["cart_id", cartId], | ||
| ["product_id", productId] | ||
| ); | ||
| } | ||
|
|
||
| async function queryProducts(cartId) { | ||
| const res = await nosqlClient.query( | ||
| nosqlTableName, | ||
| ["cart_id", cartId], | ||
| "product_id" | ||
| ); | ||
|
|
||
| const products = []; | ||
| let priceSum = 0; | ||
| let quantitySum = 0; | ||
|
|
||
| for (const product of res) { | ||
| products.push(product.name); | ||
| priceSum += product.price * product.quantity; | ||
| quantitySum += product.quantity; | ||
| } | ||
|
|
||
| const avgPrice = quantitySum > 0 ? priceSum / quantitySum : 0.0; | ||
|
|
||
| return { | ||
| products: products, | ||
| total_cost: priceSum, | ||
| avg_price: avgPrice | ||
| }; | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| exports.handler = async function(event) { | ||
| const results = []; | ||
|
|
||
| for (const request of event.requests) { | ||
| const route = request.route; | ||
| const body = request.body; | ||
| let res; | ||
|
|
||
| if (route === "PUT /cart") { | ||
| await addProduct( | ||
| body.cart, | ||
| body.product_id, | ||
| body.name, | ||
| body.price, | ||
| body.quantity | ||
| ); | ||
| res = {}; | ||
| } else if (route === "GET /cart/{id}") { | ||
| res = await getProducts(body.cart, request.path.id); | ||
| } else if (route === "GET /cart") { | ||
| res = await queryProducts(body.cart); | ||
| } else { | ||
| throw new Error(`Unknown request route: ${route}`); | ||
| } | ||
|
|
||
| results.push(res); | ||
| } | ||
|
|
||
| return results; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "name": "crud-api", | ||
| "version": "1.0.0", | ||
| "description": "CRUD API benchmark", | ||
| "author": "", | ||
| "license": "", | ||
| "dependencies": { | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -25,5 +25,5 @@ exports.handler = async function(event) { | |||||
| } | ||||||
| ); | ||||||
| await promise; | ||||||
| return {bucket: output_prefix, key: uploadName} | ||||||
| return {result: {bucket: output_prefix, key: uploadName}} | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep the thumbnail result flat for the provider wrappers. Line 28 causes wrapper output to become 🐛 Proposed fix- return {result: {bucket: output_prefix, key: uploadName}}
+ return {bucket: output_prefix, key: uploadName};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| }; | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "name": "", | ||
| "version": "1.0.0", | ||
| "description": "", | ||
| "author": "", | ||
| "license": "", | ||
| "dependencies": { | ||
| "sharp": "^0.33" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "name": "", | ||
| "version": "1.0.0", | ||
| "description": "", | ||
| "author": "", | ||
| "license": "", | ||
| "dependencies": { | ||
| "sharp": "^0.33" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const archiver = require('archiver'); | ||
| const { v4: uuidv4 } = require('uuid'); | ||
| const storage = require('./storage'); | ||
|
|
||
| let storage_handler = new storage.storage(); | ||
|
|
||
| /** | ||
| * Calculate total size of a directory recursively | ||
| * @param {string} directory - Path to directory | ||
| * @returns {number} Total size in bytes | ||
| */ | ||
| function parseDirectory(directory) { | ||
| let size = 0; | ||
|
|
||
| function walkDir(dir) { | ||
| const files = fs.readdirSync(dir); | ||
| for (const file of files) { | ||
| const filepath = path.join(dir, file); | ||
| const stat = fs.statSync(filepath); | ||
| if (stat.isDirectory()) { | ||
| walkDir(filepath); | ||
| } else { | ||
| size += stat.size; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| walkDir(directory); | ||
| return size; | ||
| } | ||
|
|
||
| /** | ||
| * Create a zip archive from a directory using archiver | ||
| * @param {string} sourceDir - Directory to compress | ||
| * @param {string} outputPath - Path for the output archive file | ||
| * @returns {Promise<void>} | ||
| */ | ||
| async function createZipArchive(sourceDir, outputPath) { | ||
| return new Promise((resolve, reject) => { | ||
| const output = fs.createWriteStream(outputPath); | ||
| const archive = archiver('zip', { | ||
| zlib: { level: 9 } // Maximum compression | ||
| }); | ||
|
|
||
| output.on('close', () => { | ||
| resolve(); | ||
| }); | ||
|
|
||
| archive.on('error', (err) => { | ||
| reject(err); | ||
| }); | ||
|
|
||
| archive.pipe(output); | ||
|
|
||
| // Add all files from the directory, excluding the archive itself | ||
| archive.glob('**/*', { | ||
| cwd: sourceDir, | ||
| ignore: [path.basename(outputPath)] | ||
| }); | ||
|
|
||
| archive.finalize(); | ||
|
Comment on lines
+41
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reject on output stream errors. Line 42 creates a write stream, but only the archive emits are handled. If the output stream fails, the invocation can crash or hang instead of rejecting the archive promise. 🐛 Proposed fix output.on('close', () => {
resolve();
});
+ output.on('error', (err) => {
+ reject(err);
+ });
+
archive.on('error', (err) => {
reject(err);
});🤖 Prompt for AI Agents |
||
| }); | ||
| } | ||
|
|
||
| exports.handler = async function(event) { | ||
| const bucket = event.bucket.bucket; | ||
| const input_prefix = event.bucket.input; | ||
| const output_prefix = event.bucket.output; | ||
| const key = event.object.key; | ||
|
|
||
| // Create unique download path | ||
| const download_path = path.join('/tmp', `${key}-${uuidv4()}`); | ||
| fs.mkdirSync(download_path, { recursive: true }); | ||
|
|
||
| // Download directory from storage | ||
| const s3_download_begin = Date.now(); | ||
| await storage_handler.downloadDirectory(bucket, path.join(input_prefix, key), download_path); | ||
| const s3_download_stop = Date.now(); | ||
|
Comment on lines
+77
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify whether download_directory is defined in any Node.js storage wrapper
fd -e js storage.js benchmarks/wrappers | xargs -I{} sh -c 'echo "=== {} ==="; grep -nE "download_directory|downloadDirectory" "{}" || echo "NOT FOUND"'Repository: spcl/serverless-benchmarks Length of output: 379 🏁 Script executed: # Check what methods are actually defined in one storage wrapper (AWS as representative)
echo "=== AWS storage.js exports ===" && grep -nE "^(exports\.|module\.exports|async function|function )" benchmarks/wrappers/aws/nodejs/storage.js | head -20
echo -e "\n=== Check function.js around lines 100-103 ===" && sed -n '95,115p' benchmarks/300.utilities/311.compression/nodejs/function.js
echo -e "\n=== Search for download_directory usage in entire codebase ===" && rg "download_directory|downloadDirectory" --type jsRepository: spcl/serverless-benchmarks Length of output: 1139 🏁 Script executed: # Get the full AWS storage.js to see what methods are defined
echo "=== AWS storage.js full content ===" && cat benchmarks/wrappers/aws/nodejs/storage.js
echo -e "\n=== Verify exact line numbers in function.js ===" && cat -n benchmarks/300.utilities/311.compression/nodejs/function.js | sed -n '95,120p'Repository: spcl/serverless-benchmarks Length of output: 3243
Either add 🤖 Prompt for AI Agents |
||
|
|
||
| // Calculate size of downloaded files | ||
| const size = parseDirectory(download_path); | ||
|
|
||
| // Compress directory | ||
| const compress_begin = Date.now(); | ||
| const archive_name = `${key}.zip`; | ||
| const archive_path = path.join(download_path, archive_name); | ||
| await createZipArchive(download_path, archive_path); | ||
|
Comment on lines
+73
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not use the storage key as a local filesystem path. Lines 74 and 87 use 🐛 Proposed fix // Create unique download path
- const download_path = path.join('/tmp', `${key}-${uuidv4()}`);
+ const run_id = uuidv4();
+ const download_path = path.join('/tmp', `compression-${run_id}`);
fs.mkdirSync(download_path, { recursive: true });
@@
// Compress directory
const compress_begin = Date.now();
const archive_name = `${key}.zip`;
- const archive_path = path.join(download_path, archive_name);
+ const local_archive_name = `${path.basename(key) || 'archive'}.${run_id}.zip`;
+ const archive_path = path.join(download_path, local_archive_name);
await createZipArchive(download_path, archive_path);🤖 Prompt for AI Agents |
||
| const compress_end = Date.now(); | ||
|
|
||
| // Get archive size | ||
| const archive_size = fs.statSync(archive_path).size; | ||
|
|
||
| // Upload compressed archive | ||
| const s3_upload_begin = Date.now(); | ||
| const [key_name, uploadPromise] = storage_handler.upload( | ||
| bucket, | ||
| path.join(output_prefix, archive_name), | ||
| archive_path | ||
| ); | ||
| await uploadPromise; | ||
| const s3_upload_stop = Date.now(); | ||
|
|
||
| // Calculate times in microseconds | ||
| const download_time = (s3_download_stop - s3_download_begin) * 1000; | ||
| const upload_time = (s3_upload_stop - s3_upload_begin) * 1000; | ||
| const process_time = (compress_end - compress_begin) * 1000; | ||
|
|
||
| return { | ||
| result: { | ||
| bucket: bucket, | ||
| key: key_name | ||
| }, | ||
| measurement: { | ||
| download_time: download_time, | ||
| download_size: size, | ||
| upload_time: upload_time, | ||
| upload_size: archive_size, | ||
| compute_time: process_time | ||
| } | ||
| }; | ||
| }; | ||
|
mcopik marked this conversation as resolved.
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "name": "compression-benchmark", | ||
| "version": "1.0.0", | ||
| "description": "Compression benchmark for serverless platforms", | ||
| "dependencies": { | ||
| "uuid": "^10.0.0", | ||
| "archiver": "^7.0.0" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,104 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Copyright 2020-2025 ETH Zurich and the SeBS authors. All rights reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This is pretty much a Node.js rewrite of our Python wrapper. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { DynamoDBDocument } = require("@aws-sdk/lib-dynamodb"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { DynamoDB } = require("@aws-sdk/client-dynamodb"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class nosql { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| constructor() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.client = DynamoDBDocument.from(new DynamoDB()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this._tables = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+7
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify whether the AWS SDK v3 packages are declared as deps anywhere in the benchmark tree
rg -nP '"@aws-sdk/(lib-dynamodb|client-dynamodb)"' --type=json
# Confirm no package.json near this wrapper adds them
fd -t f 'package.json' benchmarks/wrappers/aws/nodejs benchmarks/100.webappsRepository: spcl/serverless-benchmarks Length of output: 241 🌐 Web query:
💡 Result: No, Citations:
These AWS SDK v3 packages are not preinstalled in Lambda Node.js 20/22/24 and must be explicitly bundled as dependencies. The code imports
Additionally, 🤖 Prompt for AI Agents
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it works. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
✏️ Learnings added
🧠 Learnings used |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _get_table(table_name) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!(table_name in this._tables)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const env_name = `NOSQL_STORAGE_TABLE_${table_name}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (env_name in process.env) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this._tables[table_name] = process.env[env_name]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Couldn't find an environment variable ${env_name} for table ${table_name}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return this._tables[table_name]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async insert(table_name, primary_key, secondary_key, data) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data[primary_key[0]] = primary_key[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data[secondary_key[0]] = secondary_key[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .put({ TableName: this._get_table(table_name), Item: data }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async get(table_name, primary_key, secondary_key) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const key = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key[primary_key[0]] = primary_key[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key[secondary_key[0]] = secondary_key[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const res = await this.client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .get({ TableName: this._get_table(table_name), Key: key }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.Item; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async update(table_name, primary_key, secondary_key, updates) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const key = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key[primary_key[0]] = primary_key[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key[secondary_key[0]] = secondary_key[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const update_names = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const update_values = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const update_expression = ["SET"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const [key_name, value] of Object.entries(updates)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| update_expression.push(`#${key_name}_name = :${key_name}_value,`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| update_names[`#${key_name}_name`] = key_name; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| update_values[`:${key_name}_value`] = value; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // remove trailing comma from the last assignment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| update_expression[update_expression.length - 1] = update_expression[ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| update_expression.length - 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ].slice(0, -1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .update({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TableName: this._get_table(table_name), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Key: key, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UpdateExpression: update_expression.join(" "), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ExpressionAttributeNames: update_names, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ExpressionAttributeValues: update_values, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+46
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing empty-updates guard — When 🐛 Proposed fix async update(table_name, primary_key, secondary_key, updates) {
+ if (Object.keys(updates).length === 0) {
+ return;
+ }
const key = {};
key[primary_key[0]] = primary_key[1];
key[secondary_key[0]] = secondary_key[1];📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async query(table_name, primary_key, _) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const key_name = primary_key[0]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const res = await this.client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .query({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TableName: this._get_table(table_name), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| KeyConditionExpression: "#key_name = :keyvalue", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ExpressionAttributeNames: { "#key_name": key_name }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ExpressionAttributeValues: { ":keyvalue": primary_key[1] }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.Items; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async delete(table_name, primary_key, secondary_key) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const key = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key[primary_key[0]] = primary_key[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key[secondary_key[0]] = secondary_key[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .delete({ TableName: this._get_table(table_name), Key: key }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static get_instance() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The instance is independent of the storage table, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // as we provide table name for each operation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!nosql.instance) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nosql.instance = new nosql(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nosql.instance; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exports.nosql = nosql; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return the benchmark value directly to avoid
result.result.Line 7 makes the wrapper response contain
result: { result: sleep }. The regression path extracts the wrapper-levelresult, so validation receives an object instead of the numeric sleep value.🐛 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents