Skip to content

Implement readStrict option for Table configuration #6

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

Merged
merged 20 commits into from
Jun 18, 2025
Merged

Conversation

jimmyn
Copy link
Collaborator

@jimmyn jimmyn commented Jun 18, 2025

This PR implements the readStrict option for Table configuration to control how strictly items are validated when reading from DynamoDB.

Key Changes:

  • Added readStrict option to TableOptions with default value false
  • Modified ItemObjectFromSchemaSettings to include readStrict parameter
  • Updated Item.conformToSchema to skip expensive validation when readStrict is false
  • Updated ItemRetriever, Model, and Transaction classes to pass readStrict option
  • Added tests for both readStrict: true and readStrict: false behaviors

Behavior:

  • When readStrict: true (maintains backward compatibility): Unknown properties from DynamoDB are filtered out
  • When readStrict: false (new behavior): Unknown properties from DynamoDB are preserved in the item

This allows for better performance when reading from DynamoDB by skipping unnecessary validation while still applying essential transformations like getters and custom type conversions.

Background:
This feature was previously implemented and tested. This PR allows for internal review and testing before potentially submitting to upstream.

Summary by CodeRabbit

  • New Features

    • Introduced a new table configuration option, readStrict, allowing users to control whether unknown properties from DynamoDB responses are included or excluded in query and scan results.
    • Added a detailed README for the Dynamoose package with setup instructions, resources, and branch strategy documentation.
  • Bug Fixes

    • Improved handling of optional stream configuration to prevent runtime errors during table creation.
  • Documentation

    • Added a comprehensive README file for Dynamoose.
    • Updated test assertions to clarify timestamp handling and attribute serialization.
  • Refactor

    • Changed several internal type definitions and interfaces to be publicly exported, improving TypeScript support and extensibility.
    • Enhanced schema conformance methods to support the readStrict option during item retrieval and saving.
  • Tests

    • Added tests to verify the behavior of the readStrict option in query and scan operations.
    • Enhanced tests to check correct serialization of date attributes and timestamp types.
  • Chores

    • Updated package metadata to reflect new package naming and publishing configuration.
    • Adjusted editor settings to disable automatic code actions on save.
    • Improved formatting and whitespace in workflow configuration files.

Copy link


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I dedicate any and all copyright interest in this software to the public domain. I make this dedication for the benefit of the public at large and to the detriment of my heirs and successors. I intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

Copy link

coderabbitai bot commented Jun 18, 2025

Warning

Rate limit exceeded

@jimmyn has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 47 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 86e9756 and 9838659.

📒 Files selected for processing (1)
  • packages/dynamoose/lib/Item.ts (7 hunks)

Walkthrough

The changes introduce a new readStrict option to the Dynamoose library's table configuration, allowing users to control whether unknown properties from DynamoDB are preserved or omitted when reading items. This option is now respected throughout item retrieval, schema conformance, and transaction logic. Type definitions and several interfaces were made public, and tests were added to verify the new behavior.

Changes

File(s) Change Summary
.github/workflows/publish.yml Added blank lines after specific steps for formatting; no logic changes.
.vscode/settings.json Disabled auto code actions on save for ESLint, TypeScript, and import organization.
package.json, packages/dynamoose/package.json Changed package name to @monei-js/dynamoose, added publishConfig, and downgraded version in package subfolder.
packages/dynamoose/README.md Added new README with badges, getting started, resources, and branch strategy documentation.
packages/dynamoose/lib/General.ts Made ModelItemConstructor interface exported.
packages/dynamoose/lib/Item.ts Enhanced Item.save to conform to schema with possible relaxed validation; added readStrict option to schema conformance; improved null safety; updated interface.
packages/dynamoose/lib/ItemRetriever.ts, packages/dynamoose/lib/Transaction.ts Passed readStrict from table options to conformToSchema for item retrieval and transaction processing.
packages/dynamoose/lib/Model/index.ts Made several interfaces exported; changed UpdatePartial<T> to intersection type; added readStrict to schema conformance calls.
packages/dynamoose/lib/Schema.ts Made multiple interfaces and type aliases exported.
packages/dynamoose/lib/Table/defaults.ts, packages/dynamoose/lib/Table/index.ts Added readStrict boolean property to table options and set default to false.
packages/dynamoose/lib/Table/utilities.ts Used optional chaining for safer access to streamOptions.enabled.
packages/dynamoose/test/Item.js Updated tests to include and assert correct handling of a new birthday Date attribute.
packages/dynamoose/test/Model.js Updated timestamp assertions to expect Date objects instead of numbers.
packages/dynamoose/test/Query.js, packages/dynamoose/test/Scan.js Added tests to verify readStrict option: with true, unknown properties are omitted; with false, they are preserved.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Model
    participant Table
    participant Item
    participant DynamoDB

    User->>Model: get/query/scan(...)
    Model->>Table: Retrieve table options (including readStrict)
    Model->>DynamoDB: Fetch item(s)
    DynamoDB-->>Model: Return item(s) (may include unknown properties)
    Model->>Item: conformToSchema({ type: "fromDynamo", readStrict })
    Item-->>Model: Return item(s) with properties filtered (or not) per readStrict
    Model-->>User: Return processed item(s)
Loading
sequenceDiagram
    participant User
    participant Table
    participant Model
    participant Item

    User->>Table: new Table({ readStrict: false })
    User->>Model: query/scan/get(...)
    Model->>Item: conformToSchema({ type: "fromDynamo", readStrict: false })
    Item-->>Model: Return item(s) with all properties (including unknown)
    Model-->>User: Return item(s) with unknown properties preserved
Loading
sequenceDiagram
    participant User
    participant Table
    participant Model
    participant Item

    User->>Table: new Table({ readStrict: true })
    User->>Model: query/scan/get(...)
    Model->>Item: conformToSchema({ type: "fromDynamo", readStrict: true })
    Item-->>Model: Return item(s) with only schema-defined properties
    Model-->>User: Return item(s) with unknown properties omitted
Loading
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch read-strict

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (2)
packages/dynamoose/lib/Model/index.ts (2)

900-902: Same readStrict/itemify duplication as above

See earlier comment — extracting a helper will simplify maintenance.


1030-1032: Same readStrict/conformToSchema pattern repeated

Covered by earlier remarks.

🧹 Nitpick comments (18)
packages/dynamoose/lib/Table/index.ts (1)

564-578: ```shell
#!/bin/bash

Display the JSDoc table and default JSON block above TableOptions

sed -n '1,150p' packages/dynamoose/lib/Table/index.ts


</blockquote></details>
<details>
<summary>.github/workflows/publish.yml (1)</summary><blockquote>

`19-19`: **Strip trailing whitespace to satisfy YAML linters**

`yamllint` flags these blank lines for `trailing-spaces`.  
They are harmless at runtime but can fail CI lint jobs—delete the extra spaces.

```diff
-  
+

Also applies to: 38-38

packages/dynamoose/test/Query.js (3)

125-128: Strip trailing whitespace to satisfy linter

eslint --fix (rule no-trailing-spaces) is currently failing on line 128 – it’s just a blank line that contains spaces.
Remove the padding to unblock CI.

-					
+

133-137: Second trailing-space offender

Line 137 carries the same issue. De-indent the empty line or delete it.

-					
+

124-140: Consider deduplicating identical “readStrict” tests

The two new cases for readStrict: true/false are reproduced verbatim in Scan.js.
Extract a small helper (e.g. expectReadStrictBehaviour(modelFactory, execFn)) in a shared test util to avoid copy-paste and make future tweaks safer.

packages/dynamoose/test/Scan.js (3)

125-128: Lint failure – trailing whitespace

CI flags line 128 for trailing spaces. Drop the padding.

-					
+

133-137: Repeat trailing-space issue

Same on line 137 – clean it up.

-					
+

124-140: Reuse test logic instead of duplicating

The readStrict true/false scenarios here are identical to those in Query.js.
Factor them into a shared helper to reduce noise and ensure consistent assertions across query/scan paths.

packages/dynamoose/README.md (2)

2-39: Replace hard tabs with spaces for consistent Markdown formatting.

The file uses hard tabs for indentation across multiple lines, triggering MD010 errors and reducing readability. Convert these tabs to spaces (e.g., 2 or 4 spaces) throughout the file.

Example diff for the first few lines:

…and apply the same replacement for all indented lines.


74-81: Add trailing pipes to table rows for proper Markdown table style.

The branch strategy table uses leading-only pipes (MD055). Add a trailing pipe at the end of each row to satisfy markdownlint.

-| [`main`](https://github.com/dynamoose/dynamoose/tree/main) | 4.x.x |   | - [Documentation](https://dynamoose.pages.dev) |
+| [`main`](https://github.com/dynamoose/dynamoose/tree/main) | 4.x.x |   | - [Documentation](https://dynamoose.pages.dev) |
...
packages/dynamoose/test/Item.js (2)

124-127: Consider isolating the birthday fixture to avoid repetition

A magic value (new Date(10000)) is repeated in multiple tests. Defining a const BIRTHDAY = new Date(10_000) at the top of the describe("item.save") block (or in a shared helper) would:

  • keep the test data DRY
  • make it obvious that the same value is expected everywhere
  • avoid accidental divergence if one expectation is updated in-place later

151-153: Template literal inside expectation is brittle

The assertions interpolate the timestamp each time with

{"birthday": {"N": `${new Date(10000).getTime()}`}}

This recreates a Date object on every evaluation. While harmless here, it is noisy and slightly obscures intent. Using the same constant suggested above (or simply the literal string "10000") would make the expectation clearer and cheaper to evaluate.

Example:

- "birthday": {"N": `${new Date(10000).getTime()}`}
+ "birthday": {"N": "10000"}

Also applies to: 168-170, 212-214, 1725-1727

packages/dynamoose/lib/Item.ts (4)

443-448: Consider eliminating the extra Item instantiation

Inside save() we create a new Item only to immediately call conformToSchema and then copy its enumerable props back onto this.

const savedItem = await new (this.getInternalProperties(internalProperties).model).Item(item as any)
  .conformToSchema(conformToSchemaSettings);
Object.keys(savedItem).forEach((key) => this[key] = savedItem[key]);

This duplicates work:

  1. A second constructor allocation.
  2. Two separate InternalPropertiesClass objects.

We can avoid both by calling conformToSchema directly on the current instance after the marshal round-trip:

- const savedItem = await new (this.getInternalProperties(internalProperties).model)
-   .Item(item as any).conformToSchema(conformToSchemaSettings);
- Object.keys(savedItem).forEach((key) => this[key] = savedItem[key]);
+ await this.conformToSchema(conformToSchemaSettings);
+ const savedItem = this;

This keeps behaviour identical while shaving some allocations and internal bookkeeping.


592-599: Interface doc missing for readStrict

readStrict? is now part of ItemObjectFromSchemaSettings but there’s no JSDoc comment explaining its semantics. Since this struct is frequently referenced by users, adding a short description will improve discoverability.


722-731: Minor performance tweak & optional chaining

Even when typeCheck has been disabled (e.g. via readStrict:false), we still call
getValueTypeCheckResult for every attribute solely to drive custom-type transforms.
That partially defeats the perf benefit.

You can gate the call:

- const typeDetails = utils.dynamoose.getValueTypeCheckResult(schema, value, key, settings, {typeIndexOptionMap}).matchedTypeDetails as DynamoDBTypeResult;
+ const typeDetails = settings.typeCheck === false
+   ? undefined
+   : utils.dynamoose
+       .getValueTypeCheckResult(schema, value, key, settings, {typeIndexOptionMap})
+       .matchedTypeDetails as DynamoDBTypeResult;

Additionally, the linter hint can be satisfied by optional-chaining:

- const {"type": typeInfo} = typeDetails.isOfType(value as ValueType);
+ const {"type": typeInfo} = typeDetails?.isOfType(value as ValueType) ?? {};

Not critical, but helps fulfil the performance promise of non-strict reads and removes the lint warning.


740-742: Fallback still incurs a second expensive lookup

The try/catch pathway re-computes findTypeForValue when the first lookup fails, which can be costly for large payloads.
Caching the first valueTypeCheckResult (even if undefined) would avoid the duplicate work.

packages/dynamoose/lib/Model/index.ts (2)

74-76: Use PascalCase for interface names

TypeScript convention is to start exported type/interface names with an uppercase letter.
Proposed patch:

-export interface schemaCorrectnessScoresSettings {
-	considerDefaults?: boolean
-}
+export interface SchemaCorrectnessScoresSettings {
+	considerDefaults?: boolean;
+}

474-476: Avoid duplicating readStrict plumbing & double-check saveUnknown interplay

  1. The same 3-line block retrieving readStrict and building itemify is repeated in batchGet, update, and get. Consider a small helper (e.g., this._itemifyFromDynamo(...)) or an internal getter to DRY this up.

  2. With readStrict === true you still pass saveUnknown: true. Please confirm that Item.conformToSchema ignores saveUnknown when readStrict is enabled; otherwise unknown attributes might leak back in and defeat the strict read.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4f5fbf and e383cc7.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (18)
  • .github/workflows/publish.yml (2 hunks)
  • .vscode/settings.json (1 hunks)
  • package.json (2 hunks)
  • packages/dynamoose/README.md (1 hunks)
  • packages/dynamoose/lib/General.ts (1 hunks)
  • packages/dynamoose/lib/Item.ts (6 hunks)
  • packages/dynamoose/lib/ItemRetriever.ts (1 hunks)
  • packages/dynamoose/lib/Model/index.ts (5 hunks)
  • packages/dynamoose/lib/Schema.ts (4 hunks)
  • packages/dynamoose/lib/Table/defaults.ts (1 hunks)
  • packages/dynamoose/lib/Table/index.ts (1 hunks)
  • packages/dynamoose/lib/Table/utilities.ts (1 hunks)
  • packages/dynamoose/lib/Transaction.ts (1 hunks)
  • packages/dynamoose/package.json (2 hunks)
  • packages/dynamoose/test/Item.js (5 hunks)
  • packages/dynamoose/test/Model.js (2 hunks)
  • packages/dynamoose/test/Query.js (1 hunks)
  • packages/dynamoose/test/Scan.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.ts`: - Ensure code is clean, readable, and maintainable. - Adhere to proper naming conventions and consistent formatting. - Split functionality into smaller, reusable modules...

**/*.ts: - Ensure code is clean, readable, and maintainable.

  • Adhere to proper naming conventions and consistent formatting.
  • Split functionality into smaller, reusable modules.
  • Keep files small by extracting related functionalities into separate modules.
  • Use imports to connect modules effectively.
  • Write concise, technical, and type-safe TypeScript code.
  • Import types with import type to avoid importing implementations.
  • Use @ts-expect-error instead of @ts-ignore and add a comment explaining why the error is expected.
  • Use early return patterns to avoid deep nesting.
  • Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
  • Use AWS SDK V3 instead of V2.
  • Use Zod for data validation.
  • Use the full import path for packages when possible to enable tree shaking and reduce bundle size.
  • packages/dynamoose/lib/Transaction.ts
  • packages/dynamoose/lib/ItemRetriever.ts
  • packages/dynamoose/lib/Table/index.ts
  • packages/dynamoose/lib/General.ts
  • packages/dynamoose/lib/Table/utilities.ts
  • packages/dynamoose/lib/Table/defaults.ts
  • packages/dynamoose/lib/Item.ts
  • packages/dynamoose/lib/Schema.ts
  • packages/dynamoose/lib/Model/index.ts
🧬 Code Graph Analysis (2)
packages/dynamoose/lib/General.ts (1)
packages/dynamoose/lib/Item.ts (1)
  • Item (41-503)
packages/dynamoose/lib/Schema.ts (2)
packages/dynamoose/lib/General.ts (1)
  • ModelType (35-35)
packages/dynamoose/lib/Item.ts (1)
  • Item (41-503)
🪛 YAMLlint (1.37.1)
.github/workflows/publish.yml

[error] 19-19: trailing spaces

(trailing-spaces)


[error] 38-38: trailing spaces

(trailing-spaces)

🪛 GitHub Check: lint
packages/dynamoose/test/Query.js

[failure] 137-137:
Trailing spaces not allowed


[failure] 128-128:
Trailing spaces not allowed

packages/dynamoose/test/Scan.js

[failure] 137-137:
Trailing spaces not allowed


[failure] 128-128:
Trailing spaces not allowed

🪛 GitHub Actions: CI
packages/dynamoose/test/Query.js

[error] 128-128: ESLint: Trailing spaces not allowed (no-trailing-spaces)

packages/dynamoose/test/Model.js

[error] 779-783: Test failure: Promise resolved instead of rejected for 'Should throw error if returning Number for ISO Date'. Expected rejection with CustomError.TypeMismatch for type number instead of date.


[error] 781-789: Test failure: Promise resolved instead of rejected for 'Should throw error if returning ISO Date for String'. Expected rejection with CustomError.TypeMismatch for type string instead of date.


[error] 789-797: Test failure: Promise resolved instead of rejected for 'Should throw type mismatch error if passing in wrong type with custom type'. Expected rejection with CustomError.TypeMismatch for type string instead of date.


[error] 817-821: Test failure: Deep equality mismatch in 'Should return object with correct values with object property with elements that don't exist in schema'. Unexpected property 'zip' found in result.


[error] 819-829: Test failure: Promise resolved instead of rejected for 'Should throw type mismatch error if passing in wrong type with custom type for object'. Expected rejection with CustomError.TypeMismatch for 'address' type string instead of object.


[error] 827-837: Test failure: Promise resolved instead of rejected for 'Should throw type mismatch error if passing in wrong type for nested object attribute'. Expected rejection with CustomError.TypeMismatch for 'address.country' type boolean instead of string.


[error] 835-839: Test failure: Deep equality mismatch in 'Should return object with correct values if Dynamo object consists properties that don't exist in schema'. Unexpected property 'hello' found in result.


[error] 1188-1191: Test failure: Promise resolved instead of rejected for 'Should throw error if Dynamo object contains properties that have type mismatch with schema'. Expected rejection with CustomError.TypeMismatch for 'age' type string instead of number.


[error] 1221-1224: Test failure: Promise resolved instead of rejected for 'Should throw error if returning Number for ISO Date' (Callback). Expected rejection with CustomError.TypeMismatch for type number instead of date.


[error] 781-791: Test failure: Promise resolved instead of rejected for 'Should throw error if returning ISO Date for String' (Callback). Expected rejection with CustomError.TypeMismatch for type string instead of date.


[error] 789-799: Test failure: Promise resolved instead of rejected for 'Should throw type mismatch error if passing in wrong type with custom type' (Callback). Expected rejection with CustomError.TypeMismatch for type string instead of date.


[error] 819-829: Test failure: Promise resolved instead of rejected for 'Should throw type mismatch error if passing in wrong type with custom type for object' (Callback). Expected rejection with CustomError.TypeMismatch for 'address' type string instead of object.


[error] 827-837: Test failure: Promise resolved instead of rejected for 'Should throw type mismatch error if passing in wrong type for nested object attribute' (Callback). Expected rejection with CustomError.TypeMismatch for 'address.country' type boolean instead of string.


[error] 835-839: Test failure: Deep equality mismatch in 'Should return object with correct values if Dynamo object consists properties that don't exist in schema' (Callback). Unexpected property 'hello' found in result.


[error] 1188-1191: Test failure: Promise resolved instead of rejected for 'Should throw error if Dynamo object contains properties that have type mismatch with schema' (Callback). Expected rejection with CustomError.TypeMismatch for 'age' type string instead of number.


[warning] Console warning: Dynamoose Warning: Passing callback function into transaction method not allowed. Removing callback function from list of arguments.

packages/dynamoose/lib/Model/index.ts

[warning] 371-371: Dynamoose Warning: Passing callback function into transaction method not allowed. Removing callback function from list of arguments.

🪛 markdownlint-cli2 (0.17.2)
packages/dynamoose/README.md

2-2: Hard tabs
Column: 1

(MD010, no-hard-tabs)


6-6: Hard tabs
Column: 1

(MD010, no-hard-tabs)


7-7: Hard tabs
Column: 1

(MD010, no-hard-tabs)


8-8: Hard tabs
Column: 1

(MD010, no-hard-tabs)


9-9: Hard tabs
Column: 1

(MD010, no-hard-tabs)


10-10: Hard tabs
Column: 1

(MD010, no-hard-tabs)


11-11: Hard tabs
Column: 1

(MD010, no-hard-tabs)


12-12: Hard tabs
Column: 1

(MD010, no-hard-tabs)


13-13: Hard tabs
Column: 1

(MD010, no-hard-tabs)


14-14: Hard tabs
Column: 1

(MD010, no-hard-tabs)


15-15: Hard tabs
Column: 1

(MD010, no-hard-tabs)


16-16: Hard tabs
Column: 1

(MD010, no-hard-tabs)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


18-18: Hard tabs
Column: 1

(MD010, no-hard-tabs)


19-19: Hard tabs
Column: 1

(MD010, no-hard-tabs)


20-20: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Hard tabs
Column: 1

(MD010, no-hard-tabs)


22-22: Hard tabs
Column: 1

(MD010, no-hard-tabs)


23-23: Hard tabs
Column: 1

(MD010, no-hard-tabs)


24-24: Hard tabs
Column: 1

(MD010, no-hard-tabs)


25-25: Hard tabs
Column: 1

(MD010, no-hard-tabs)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


27-27: Hard tabs
Column: 1

(MD010, no-hard-tabs)


28-28: Hard tabs
Column: 1

(MD010, no-hard-tabs)


29-29: Hard tabs
Column: 1

(MD010, no-hard-tabs)


30-30: Hard tabs
Column: 1

(MD010, no-hard-tabs)


31-31: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


33-33: Hard tabs
Column: 1

(MD010, no-hard-tabs)


34-34: Hard tabs
Column: 1

(MD010, no-hard-tabs)


35-35: Hard tabs
Column: 1

(MD010, no-hard-tabs)


36-36: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


38-38: Hard tabs
Column: 1

(MD010, no-hard-tabs)


80-80: Table pipe style
Expected: leading_and_trailing; Actual: leading_only; Missing trailing pipe

(MD055, table-pipe-style)

🪛 Biome (1.9.4)
packages/dynamoose/lib/Item.ts

[error] 727-727: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (13)
.vscode/settings.json (1)

8-12: Disable automatic code actions on save
This new block intentionally turns off ESLint fixes, TypeScript fixes, and import organization on save. It ensures the team’s editor doesn’t auto-modify files during development, preserving the expected workflow.

packages/dynamoose/package.json (2)

49-53: publishConfig looks correct – ensure CI respects it

"access": "public" together with an explicit registry is standard; CI/CD pipelines that already set npm publish --access public will work unchanged.


2-3: ```shell
#!/bin/bash

List all git tags to check for prior published versions

git tag --list


</details>
<details>
<summary>packages/dynamoose/lib/General.ts (1)</summary>

`17-34`: **Exporting `ModelItemConstructor` is safe – no concerns**

Making the constructor interface public improves typing for downstream consumers; there are no breaking-change risks because it only widens visibility.

</details>
<details>
<summary>packages/dynamoose/lib/Table/defaults.ts (1)</summary>

`25-25`: **Defaulting `readStrict` to false may introduce breaking runtime behaviour**

Previous releases always stripped unknown attributes; setting the default to `false` now preserves them for every table that doesn’t explicitly opt-in.  
Confirm that this is an intentional breaking change and that:

1. CHANGELOG/docs call it out clearly.  
2. A major version bump (or a deprecation pathway) is scheduled.  
3. Internal code paths that assumed strict filtering are audited for unintended side-effects.

Consider keeping the default `true` and letting users disable it if backwards compatibility is required.

</details>
<details>
<summary>packages/dynamoose/lib/Table/utilities.ts (1)</summary>

`78-84`: **Optional-chaining guard looks good**

Replacing the nested property check with `streamOptions?.enabled` removes a potential `undefined` access without altering logic.

</details>
<details>
<summary>package.json (1)</summary>

`2-2`: **Verify ecosystem updates after scoped package rename**

Renaming to `@monei-js/dynamoose` and adding a `publishConfig` block affects:

• Import paths in source & documentation.  
• Lerna/workspace publish settings.  
• Consumers depending on the unscoped name.

Ensure all references, badges, and workflow scripts are updated and that the npm token allows publishing under this scope.  



Also applies to: 97-100

</details>
<details>
<summary>packages/dynamoose/test/Model.js (3)</summary>

`2001-2003`: **Approve timestamp constructor assertions**

Confirming that both `createdAt` and `updatedAt` are verified as `Date` instances is correct and improves type clarity in tests.

---

`2013-2013`: **Approve capturing `date3` as upper bound**

Introducing `const date3 = Date.now();` before range assertions on updated timestamps ensures an accurate upper bound for `updatedAt`, making the test deterministic.

---

`2019-2022`: **Approve post-save timestamp range checks**

Validating that `createdAt` and `updatedAt` remain within expected ranges after mutation and save strengthens test coverage of timestamp behavior.

</details>
<details>
<summary>packages/dynamoose/README.md (1)</summary>

`1-4`: **Verify banner image path and inclusion in the package.**

Ensure that `internal/banner/Banner.png` is packaged and that the relative path in the README resolves correctly post-publish. A missing asset will lead to a broken banner on npm.



```shell
#!/bin/bash
# Check for Banner.png in the published package directory
if [ ! -f packages/dynamoose/internal/banner/Banner.png ]; then
  echo "ERROR: Banner.png not found in packages/dynamoose/internal/banner/"
  exit 1
fi
echo "Banner.png is present."
packages/dynamoose/lib/Schema.ts (1)

276-332: Public-export looks good

The new export modifiers surface several formerly-internal types that other packages may now import. Nothing here alters runtime behaviour, and the unions still line up with the values accepted elsewhere in the file, so I have no concerns.

packages/dynamoose/lib/Model/index.ts (1)

23-28: UpdatePartial type change looks good

Intersection with optional $SET/$ADD/$REMOVE/$DELETE props aligns with existing update implementation — especially the array support for $REMOVE. No concerns here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/dynamoose/lib/Item.ts (1)

899-910: readStrict still overrides explicit caller settings
We flagged this in the previous round, but the code still hard-resets
validate, required, enum, defaults, and forceDefault to false,
even when the caller explicitly set them to true.

-settings = {
-  ...settings,
-  "validate": false,
-  "required": false,
-  "enum": false,
-  "defaults": false,
-  "forceDefault": false
-};
+settings = {
+  ...settings,
+  validate: settings.validate ?? false,
+  required: settings.required ?? false,
+  enum: settings.enum ?? false,
+  defaults: settings.defaults ?? false,
+  forceDefault: settings.forceDefault ?? false
+};

This preserves the ergonomic default while respecting deliberate overrides.

🧹 Nitpick comments (4)
packages/dynamoose/lib/Item.ts (4)

443-448: readStrict flag is not forwarded when creating conformToSchemaSettings

conformToSchemaSettings is hard-coded and silently drops any table-level readStrict preference.
If the table was created with readStrict: false, saving an item will still invoke the strict validation path, causing an avoidable performance hit.

-const conformToSchemaSettings : ItemObjectFromSchemaSettings = {"combine": true, "customTypesDynamo": true, "saveUnknown": true, "type": "fromDynamo", "modifiers": ["get"], "mapAttributes": true};
+const conformToSchemaSettings: ItemObjectFromSchemaSettings = {
+  "combine": true,
+  "customTypesDynamo": true,
+  "saveUnknown": true,
+  "type": "fromDynamo",
+  "modifiers": ["get"],
+  "mapAttributes": true,
+  // Preserve table-level option
+  "readStrict": table.getInternalProperties(internalProperties)
+    .options.readStrict
+};

592-595: Interface extended correctly, but lacks JSDoc

readStrict was added to ItemObjectFromSchemaSettings, but no description is given.
Please add a short JSDoc entry so IDEs surface the new option.

-readStrict?: boolean;
+/**
+ * When `false`, skip expensive validation steps during `fromDynamo`
+ * deserialisation, while still applying transformations.
+ * Defaults to `true`.
+ */
+readStrict?: boolean;

743-751: Guard against missing customType functions

customType.functions[settings.type] is accessed without verifying that
customType.functions exists. While most custom types do define the property,
the check is trivial and prevents a run-time TypeError:

- if (customType && customType.functions[settings.type] && !isCorrectTypeAlready) {
+ if (customType?.functions?.[settings.type] && !isCorrectTypeAlready) {

760-762: Optional-chaining simplifies nullish handling
The static-analysis hint is valid – matchedTypeDetails may be undefined. Using optional chaining improves readability and eliminates the try…catch that’s only guarding against that access:

- typeDetails = result ? result.matchedTypeDetails : undefined;
+ typeDetails = result?.matchedTypeDetails;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e383cc7 and 838ae4b.

📒 Files selected for processing (4)
  • packages/dynamoose/lib/Item.ts (7 hunks)
  • packages/dynamoose/test/Model.js (6 hunks)
  • packages/dynamoose/test/Query.js (1 hunks)
  • packages/dynamoose/test/Scan.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/dynamoose/test/Scan.js
  • packages/dynamoose/test/Query.js
  • packages/dynamoose/test/Model.js
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.ts`: - Ensure code is clean, readable, and maintainable. - Adhere to proper naming conventions and consistent formatting. - Split functionality into smaller, reusable modules...

**/*.ts: - Ensure code is clean, readable, and maintainable.

  • Adhere to proper naming conventions and consistent formatting.
  • Split functionality into smaller, reusable modules.
  • Keep files small by extracting related functionalities into separate modules.
  • Use imports to connect modules effectively.
  • Write concise, technical, and type-safe TypeScript code.
  • Import types with import type to avoid importing implementations.
  • Use @ts-expect-error instead of @ts-ignore and add a comment explaining why the error is expected.
  • Use early return patterns to avoid deep nesting.
  • Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
  • Use AWS SDK V3 instead of V2.
  • Use Zod for data validation.
  • Use the full import path for packages when possible to enable tree shaking and reduce bundle size.
  • packages/dynamoose/lib/Item.ts
🪛 Biome (1.9.4)
packages/dynamoose/lib/Item.ts

[error] 747-747: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: test (23.x)
  • GitHub Check: test (21.x)
  • GitHub Check: test (18.x)
  • GitHub Check: test (19.x)
  • GitHub Check: test (16.x)
  • GitHub Check: test (17.x)
  • GitHub Check: test (17.x)
  • GitHub Check: test (21.x)
  • GitHub Check: test (20.x)
  • GitHub Check: test (19.x)
  • GitHub Check: test (16.x)
  • GitHub Check: test (18.x)
🔇 Additional comments (1)
packages/dynamoose/lib/Item.ts (1)

489-492: Good callback / promise harmonisation

The callback now receives the fully conformed savedItem, and the promise path mirrors that behaviour – nice clean-up.

@coveralls
Copy link

coveralls commented Jun 18, 2025

Pull Request Test Coverage Report for Build 15733095012

Details

  • 58 of 62 (93.55%) changed or added relevant lines in 5 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.3%) to 99.691%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/dynamoose/lib/Item.ts 47 51 92.16%
Totals Coverage Status
Change from base Build 15732004020: -0.3%
Covered Lines: 2403
Relevant Lines: 2407

💛 - Coveralls

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/dynamoose/lib/Item.ts (1)

924-935: Unconditional flag override still ignores explicit user settings
Same point raised in the previous review.

The block resets validate, required, enum, defaults, and forceDefault to false whenever readStrict === false.
If a caller explicitly passes validate: true together with readStrict: false, that intent is lost.

Consider only overriding when the property is undefined:

 settings = {
   ...settings,
-  "validate": false,
-  "required": false,
-  "enum": false,
-  "defaults": false,
-  "forceDefault": false
+  "validate": settings.validate ?? false,
+  "required": settings.required ?? false,
+  "enum": settings.enum ?? false,
+  "defaults": settings.defaults ?? false,
+  "forceDefault": settings.forceDefault ?? false
 };

This retains the convenience default while respecting explicit opts.

🧹 Nitpick comments (4)
packages/dynamoose/lib/Item.ts (4)

443-448: Consider forwarding readStrict (and other table options) when normalising the just-marshalled item

conformToSchemaSettings is hard-coded here.
If the parent table was created with readStrict: true, this internal post-save normalisation will silently ignore that preference, potentially leaving unknown attributes on the in-memory item while they would be stripped on a subsequent get().

-const conformToSchemaSettings : ItemObjectFromSchemaSettings = {"combine": true, "customTypesDynamo": true, "saveUnknown": true, "type": "fromDynamo", "modifiers": ["get"], "mapAttributes": true};
+const conformToSchemaSettings: ItemObjectFromSchemaSettings = {
+  "combine": true,
+  "customTypesDynamo": true,
+  "saveUnknown": true,
+  "type": "fromDynamo",
+  "modifiers": ["get"],
+  "mapAttributes": true,
+  // bubble up the table option so behaviour is consistent everywhere
+  "readStrict": table.getInternalProperties(internalProperties).options.readStrict
+};

This keeps behaviour deterministic no matter which code path produced the item.


680-681: Strip trailing whitespace – linter is failing

Line 680 contains nothing but spaces.
Please delete the superfluous whitespace to unblock CI (no-trailing-spaces).


705-706: Same whitespace issue as above

Another blank line with trailing spaces (line 705). Remove it for a clean lint run.


769-773: Use optional chaining to avoid undefined-access & satisfy the linter

customType may be undefined. The linter already points this out:

-if (customType && customType.functions[settings.type] && !isCorrectTypeAlready) {
-  const customValue = customType.functions[settings.type](value);
+if (customType?.functions?.[settings.type] && !isCorrectTypeAlready) {
+  const customValue = customType.functions[settings.type](value);
 }

This silences the useOptionalChain warning and guards against a runtime TypeError.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 838ae4b and 86e9756.

📒 Files selected for processing (1)
  • packages/dynamoose/lib/Item.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.ts`: - Ensure code is clean, readable, and maintainable. - Adhere to proper naming conventions and consistent formatting. - Split functionality into smaller, reusable modules...

**/*.ts: - Ensure code is clean, readable, and maintainable.

  • Adhere to proper naming conventions and consistent formatting.
  • Split functionality into smaller, reusable modules.
  • Keep files small by extracting related functionalities into separate modules.
  • Use imports to connect modules effectively.
  • Write concise, technical, and type-safe TypeScript code.
  • Import types with import type to avoid importing implementations.
  • Use @ts-expect-error instead of @ts-ignore and add a comment explaining why the error is expected.
  • Use early return patterns to avoid deep nesting.
  • Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
  • Use AWS SDK V3 instead of V2.
  • Use Zod for data validation.
  • Use the full import path for packages when possible to enable tree shaking and reduce bundle size.
  • packages/dynamoose/lib/Item.ts
🪛 GitHub Check: lint
packages/dynamoose/lib/Item.ts

[failure] 705-705:
Trailing spaces not allowed


[failure] 680-680:
Trailing spaces not allowed

🪛 Biome (1.9.4)
packages/dynamoose/lib/Item.ts

[error] 772-772: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🪛 GitHub Actions: CI
packages/dynamoose/lib/Item.ts

[error] 680-680: ESLint: Trailing spaces not allowed (no-trailing-spaces)

@jimmyn jimmyn merged commit cbbcb83 into main Jun 18, 2025
25 of 26 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Jun 18, 2025
@jimmyn jimmyn deleted the read-strict branch June 18, 2025 12:46
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants