Repository: Kysumi/dyno-table
Pull request #37: Entity framework - next release
Author: login: Kysumi
Labels: name: released
Created: 2025-05-11T21:35:18Z | Merged: 2025-05-12T01:09:08Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Chores**
  - Updated the package version to 0.2.0-0.  
- **Documentation**
  - Revamped README for improved clarity, structure, and presentation.  
  - Added flexible schema validation to key benefits.  
  - Enhanced installation and quick start sections with better formatting and alternative package manager commands.  
  - Updated examples to use new key template utilities and standardized index naming.  
  - Improved query patterns and replaced scans with queries in examples.  
  - Removed lifecycle hooks section and fixed minor typos.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/README.md b/README.md
index b8f49dd..5aeef6d 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,23 @@
-# 🦖 dyno-table [![npm version](https://img.shields.io/npm/v/dyno-table.svg?style=flat-square)](https://www.npmjs.com/package/dyno-table) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
+<div align="center">
 
-**A type-safe, fluent interface for DynamoDB single-table designs**  
-*Tame the NoSQL wilderness with a robust abstraction layer that brings order to DynamoDB operations*
+# 🦖 dyno-table
+
+### **Tame Your DynamoDB Data with Type-Safe Precision**
+
+[![npm version](https://img.shields.io/npm/v/dyno-table.svg?style=for-the-badge)](https://www.npmjs.com/package/dyno-table) 
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](https://opensource.org/licenses/MIT)
+[![TypeScript](https://img.shields.io/badge/TypeScript-4.0%2B-blue?style=for-the-badge&logo=typescript)](https://www.typescriptlang.org/)
+[![AWS DynamoDB](https://img.shields.io/badge/AWS-DynamoDB-orange?style=for-the-badge&logo=amazon-aws)](https://aws.amazon.com/dynamodb/)
+
+</div>
+
+<p align="center"><strong>A powerful, type-safe abstraction layer for DynamoDB single-table designs</strong><br/>
+<em>Write cleaner, safer, and more maintainable DynamoDB code</em></p>
 
 <img src="docs/images/geoff-the-dyno.png" width="400" height="250" alt="Geoff the Dyno" style="float: right; margin-left: 20px; margin-bottom: 20px;">
 
+## 🔥 Why Developers Choose dyno-table
+
 ```ts
 // Type-safe dinosaur tracking operations made simple
 await dinoTable
@@ -18,80 +31,120 @@ await dinoTable
   .execute();
 ```
 
-> This README provides a concise overview of dyno-table's features with dinosaur-themed examples. For detailed documentation on specific features, please refer to the individual markdown files in the `docs/` directory.
-
-## 🌟 Why dyno-table for your Dinosaur Data?
-
-- **🦕 Dinosaur-sized data made manageable** - Clean abstraction layer for complex DynamoDB patterns
-- **🛡️ Extinction-proof type safety** - Full TypeScript support with strict type checking
-- **⚡ Velociraptor-fast API** - Chainable builder pattern for complex operations
-- **🔒 T-Rex-proof transactional safety** - ACID-compliant operations with easy-to-use transactions
-- **📈 Jurassic-scale performance** - Automatic batch chunking and pagination handling
+## 🌟 Why dyno-table Stands Out From The Pack
+
+<table>
+<tr>
+  <td width="50%">
+    <h3>🦕 Dinosaur-sized data made manageable</h3>
+    <p>Clean abstraction layer that simplifies complex DynamoDB patterns and makes single-table design approachable</p>
+  </td>
+  <td width="50%">
+    <h3>🛡️ Extinction-proof type safety</h3>
+    <p>Full TypeScript support with strict type checking that catches errors at compile time, not runtime</p>
+  </td>
+</tr>
+<tr>
+  <td>
+    <h3>⚡ Velociraptor-fast API</h3>
+    <p>Intuitive chainable builder pattern for complex operations that feels natural and reduces boilerplate</p>
+  </td>
+</tr>
+<tr>
+  <td width="50%">
+    <h3>📈 Jurassic-scale performance</h3>
+    <p>Automatic batch chunking and pagination handling that scales with your data without extra code</p>
+  </td>
+  <td width="50%">
+    <h3>🧩 Flexible schema validation</h3>
+    <p>Works with your favorite validation libraries including Zod, ArkType, and Valibot</p>
+  </td>
+</tr>
+</table>
 
 ## 📑 Table of Contents
 
-- [🦖 dyno-table  ](#-dyno-table--)
-  - [🌟 Why dyno-table for your Dinosaur Data?](#-why-dyno-table-for-your-dinosaur-data)
-  - [📑 Table of Contents](#-table-of-contents)
-  - [📦 Installation](#-installation)
-  - [🚀 Quick Start](#-quick-start)
-    - [1. Configure Your Jurassic Table](#1-configure-your-jurassic-table)
-    - [2. Perform Type-Safe Dinosaur Operations](#2-perform-type-safe-dinosaur-operations)
-  - [🏗️ Entity Pattern](#️-entity-pattern-with-standard-schema-validators)
-    - [Defining Entities](#defining-entities)
-    - [Entity Features](#entity-features)
-      - [1. Schema Validation](#1-schema-validation)
-      - [2. CRUD Operations](#2-crud-operations)
-      - [3. Custom Queries](#3-custom-queries)
-      - [4. Indexes for Efficient Querying](#4-indexes-for-efficient-querying)
-      - [5. Lifecycle Hooks](#5-lifecycle-hooks)
-    - [Complete Entity Example](#complete-entity-example)
-  - [🧩 Advanced Features](#-advanced-features)
-    - [Transactional Operations](#transactional-operations)
-    - [Batch Processing](#batch-processing)
-    - [Pagination Made Simple](#pagination-made-simple)
-  - [🛡️ Type-Safe Query Building](#️-type-safe-query-building)
-    - [Comparison Operators](#comparison-operators)
-    - [Logical Operators](#logical-operators)
-    - [Query Operations](#query-operations)
-    - [Put Operations](#put-operations)
-    - [Update Operations](#update-operations)
-      - [Condition Operators](#condition-operators)
-      - [Multiple Operations](#multiple-operations)
-  - [🔄 Type Safety Features](#-type-safety-features)
-    - [Nested Object Support](#nested-object-support)
-    - [Type-Safe Conditions](#type-safe-conditions)
-  - [🔄 Batch Operations](#-batch-operations)
-    - [Batch Get](#batch-get)
-    - [Batch Write](#batch-write)
-  - [🔒 Transaction Operations](#-transaction-operations)
-    - [Transaction Builder](#transaction-builder)
-    - [Transaction Options](#transaction-options)
-  - [🚨 Error Handling](#-error-handling)
-  - [📚 API Reference](#-api-reference)
-    - [Condition Operators](#condition-operators-1)
-      - [Comparison Operators](#comparison-operators-1)
-      - [Attribute Operators](#attribute-operators)
-      - [Logical Operators](#logical-operators-1)
-    - [Key Condition Operators](#key-condition-operators)
-  - [🔮 Future Roadmap](#-future-roadmap)
-  - [🤝 Contributing](#-contributing)
-  - [🦔 Running Examples](#-running-examples)
+- [📦 Installation](#-installation)
+- [🚀 Quick Start](#-quick-start)
+  - [1. Configure Your Jurassic Table](#1-configure-your-jurassic-table)
+  - [2. Perform Type-Safe Dinosaur Operations](#2-perform-type-safe-dinosaur-operations)
+- [🏗️ Entity Pattern](#-entity-pattern-with-standard-schema-validators)
+  - [Defining Entities](#defining-entities)
+  - [Entity Features](#entity-features)
+    - [1. Schema Validation](#1-schema-validation)
+    - [2. CRUD Operations](#2-crud-operations)
+    - [3. Custom Queries](#3-custom-queries)
+    - [4. Defining GSI Access Patterns](#4-defining-gsi-access-patterns)
+    - [5. Lifecycle Hooks](#5-lifecycle-hooks)
+  - [Complete Entity Example](#complete-entity-example)
+- [🧩 Advanced Features](#-advanced-features)
+  - [Transactional Operations](#transactional-operations)
+  - [Batch Processing](#batch-processing)
+  - [Pagination Made Simple](#pagination-made-simple)
+- [🛡️ Type-Safe Query Building](#️-type-safe-query-building)
+  - [Comparison Operators](#comparison-operators)
+  - [Logical Operators](#logical-operators)
+  - [Query Operations](#query-operations)
+  - [Put Operations](#put-operations)
+  - [Update Operations](#update-operations)
+    - [Condition Operators](#condition-operators)
+    - [Multiple Operations](#multiple-operations)
+- [🔄 Type Safety Features](#-type-safety-features)
+  - [Nested Object Support](#nested-object-support)
+  - [Type-Safe Conditions](#type-safe-conditions)
+- [🔄 Batch Operations](#-batch-operations)
+  - [Batch Get](#batch-get)
+  - [Batch Write](#batch-write)
+- [🔒 Transaction Operations](#-transaction-operations)
+  - [Transaction Builder](#transaction-builder)
+  - [Transaction Options](#transaction-options)
+- [🚨 Error Handling](#-error-handling)
+- [📚 API Reference](#-api-reference)
+  - [Condition Operators](#condition-operators-1)
+    - [Comparison Operators](#comparison-operators-1)
+    - [Attribute Operators](#attribute-operators)
+    - [Logical Operators](#logical-operators-1)
+  - [Key Condition Operators](#key-condition-operators)
+- [🔮 Future Roadmap](#-future-roadmap)
+- [🤝 Contributing](#-contributing)
+- [🦔 Running Examples](#-running-examples)
 
 ## 📦 Installation
 
+<div align="center">
+
+### Get Started in Seconds
+
+</div>
+
 ```bash
+# Install the core library
 npm install dyno-table
+
+# Install required AWS SDK v3 peer dependencies
+npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
 ```
 
-*Note: Requires AWS SDK v3 as peer dependency*
+<details>
+<summary><b>📋 Other Package Managers</b></summary>
 
 ```bash
-npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
+# Using Yarn
+yarn add dyno-table @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
+
+# Using PNPM
+pnpm add dyno-table @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
 ```
+</details>
 
 ## 🚀 Quick Start
 
+<div align="center">
+
+### From Zero to DynamoDB Hero in Minutes
+
+</div>
+
 ### 1. Configure Your Jurassic Table
 
 ```ts
@@ -99,20 +152,20 @@ import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
 import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb";
 import { Table } from "dyno-table/table";
 
-// Configure AWS SDK clients - your gateway to the prehistoric database
+// Configure AWS SDK clients
 const client = new DynamoDBClient({ region: "us-west-2" });
 const docClient = DynamoDBDocument.from(client);
 
-// Initialize table with single-table design schema - your dinosaur park database
+// Initialise table
 const dinoTable = new Table({
   client: docClient,
-  tableName: "JurassicPark", // Your central dinosaur tracking system
+  tableName: "JurassicPark",
   indexes: {
-    partitionKey: "pk",      // Primary partition key for fast dinosaur lookups
-    sortKey: "sk",           // Sort key for organizing dinosaur data
+    partitionKey: "pk",
+    sortKey: "sk",
     gsis: {
-      // Global Secondary Index for querying dinosaurs by species
-      speciesId: {
+      // Global Secondary Index setup in an abstract to allow unique access patterns per Entity Type for single table design
+      gsi1: {
         partitionKey: "gsi1pk",
         sortKey: "gsi1sk",
       },
@@ -123,60 +176,173 @@ const dinoTable = new Table({
 
 ### 2. Perform Type-Safe Dinosaur Operations
 
-**🦖 Creating a new dinosaur specimen**
+<table>
+<tr>
+<td>
+
+#### 🦖 Creating a new dinosaur specimen
+
 ```ts
-// Add a new T-Rex to your collection with complete type safety
+// Add a new T-Rex with complete type safety
 const rex = await dinoTable
   .create<Dinosaur>({
-    pk: "SPECIES#trex",           // Partition key identifies the species
-    sk: "PROFILE#trex",           // Sort key for the specific profile
-    speciesId: "trex",            // For GSI queries
-    name: "Tyrannosaurus Rex",    // Display name
-    diet: "carnivore",            // Dietary classification
-    length: 12.3,                 // Size in meters
-    discoveryYear: 1902           // When first discovered
+    pk: "SPECIES#trex",
+    sk: "PROFILE#trex",
+    speciesId: "trex",
+    name: "Tyrannosaurus Rex",
+    diet: "carnivore",
+    length: 12.3,
+    discoveryYear: 1902
   })
   .execute();
 ```
 
-**🔍 Query for specific dinosaurs with conditions**
+</td>
+<td>
+
+#### 🔍 Query with powerful conditions
+
 ```ts
-// Find large carnivorous dinosaurs in the T-Rex species
+// Find large carnivorous dinosaurs
 const largeDinos = await dinoTable
   .query<Dinosaur>({ 
-    pk: "SPECIES#trex",                    // Target the T-Rex species
-    sk: (op) => op.beginsWith("PROFILE#")  // Look in profile records
+    pk: "SPECIES#trex",
+    sk: (op) => op.beginsWith("PROFILE#")
   })
   .filter((op) => op.and(
-    op.gte("length", 10),                  // Only dinosaurs longer than 10 meters
-    op.eq("diet", "carnivore")             // Must be carnivores
+    op.gte("length", 10),
+    op.eq("diet", "carnivore")
   ))
-  .limit(10)                               // Limit to 10 results
+  .limit(10)
   .execute();
 ```
 
-**🔄 Update dinosaur classification**
+</td>
+</tr>
+<tr>
+<td>
+
+#### 🔄 Update with type-safe operations
+
 ```ts
-// Update a dinosaur's diet classification based on new research
+// Update a dinosaur's classification
 await dinoTable
   .update<Dinosaur>({ 
-    pk: "SPECIES#trex",           // Target the T-Rex species
-    sk: "PROFILE#trex"            // Specific profile to update
+    pk: "SPECIES#trex",
+    sk: "PROFILE#trex"
+  })
+  .set("diet", "omnivore")
+  .add("discoveryYear", 1)
+  .remove("outdatedField")
+  .condition((op) => 
+    op.attributeExists("discoverySite")
+  )
+  .execute();
+```
+
+</td>
+<td>
+
+#### 🔒 Transactional operations
+
+```ts
+// Perform multiple operations atomically
+await dinoTable.transaction(async (tx) => {
+  // Move dinosaur to new enclosure
+  await dinoTable
+    .delete({ pk: "ENCLOSURE#A", sk: "DINO#1" })
+    .withTransaction(tx);
+
+  await dinoTable
+    .create({ pk: "ENCLOSURE#B", sk: "DINO#1", 
+      status: "ACTIVE" })
+    .withTransaction(tx);
+});
+```
+
+</td>
+</tr>
+</table>
+
+<div align="center">
+<h3>💡 See the difference with dyno-table</h3>
+</div>
+
+<table>
+<tr>
+<th>With dyno-table</th>
+<th>Without dyno-table</th>
+</tr>
+<tr>
+<td>
+
+```ts
+// Type-safe, clean, and intuitive
+await dinoTable
+  .query<Dinosaur>({ 
+    pk: "SPECIES#trex"
   })
-  .set("diet", "omnivore")        // New diet classification based on fossil evidence
-  .add("discoveryYear", 1)        // Adjust discovery year with new findings
-  .remove("outdatedField")        // Remove deprecated information
-  .condition((op) => op.attributeExists("discoverySite"))  // Only if discovery site is documented
+  .filter(op => 
+    op.contains("features", "feathers")
+  )
   .execute();
 ```
 
+</td>
+<td>
+
+```ts
+// Verbose, error-prone, no type safety
+await docClient.send(new QueryCommand({
+  TableName: "JurassicPark",
+  KeyConditionExpression: "#pk = :pk",
+  FilterExpression: "contains(#features, :feathers)",
+  ExpressionAttributeNames: {
+    "#pk": "pk",
+    "#features": "features"
+  },
+  ExpressionAttributeValues: {
+    ":pk": "SPECIES#trex",
+    ":feathers": "feathers"
+  }
+}));
+```
+
+</td>
+</tr>
+</table>
+
 ## 🏗️ Entity Pattern with Standard Schema validators
 
-The entity pattern provides a structured, type-safe way to work with DynamoDB items.
-It combines schema validation, key management, and repository operations into a cohesive abstraction.
+<div align="center">
+
+### The Most Type-Safe Way to Model Your DynamoDB Data
+
+</div>
+
+<table>
+<tr>
+<td width="70%">
+<p>The entity pattern provides a structured, type-safe way to work with DynamoDB items. It combines schema validation, key management, and repository operations into a cohesive abstraction.</p>
+
+<p>✨ This library supports all <a href="https://github.com/standard-schema/standard-schema#what-schema-libraries-implement-the-spec">Standard Schema</a> validation libraries, including <strong>zod</strong>, <strong>arktype</strong>, and <strong>valibot</strong>, allowing you to choose your preferred validation tool!</p>
+
+<p>You can find a full example implementation here of <a href="https://github.com/Kysumi/dyno-table/blob/main/examples/entity-example/src/dinosaur-entity.ts">Entities</a></p>
+</td>
+<td width="30%">
+
+#### Entity Pattern Benefits
 
-✨ This library supports all standard schema validation libraries, including **zod**, **arktype**, and **valibot**,
-allowing you to choose your preferred validation tool!
+- 🛡️ **Type-safe operations**
+- 🧪 **Schema validation**
+- 🔑 **Automatic key generation**
+- 📦 **Repository pattern**
+- 🔍 **Custom query builders**
+- 🔄 **Lifecycle hooks**
+
+</td>
+</tr>
+</table>
 
 ### Defining Entities
 
@@ -251,7 +417,8 @@ const DinosaurEntity = defineEntity({
   primaryKey: createIndex()
           .input(z.object({ id: z.string(), diet: z.string(), species: z.string() }))
           .partitionKey(({ diet }) => dinosaurPK({ diet }))
-          .sortKey(({ id, species }) => dinosaurSK({ species, id }))
+          // could also be .withoutSortKey() if your table doesn't use sort keys
+          .sortKey(({ id, species }) => dinosaurSK({ species, id })) 
 });
 ```
 
@@ -315,8 +482,9 @@ const DinosaurEntity = defineEntity({
       )
       .query(({ input, entity }) => {
         return entity
-          .scan()
-          .filter((op) => op.eq("diet", input.diet));
+          .query({
+            pk: dinosaurPK({diet: input.diet})
+          });
       }),
 
     bySpecies: createQuery
@@ -338,18 +506,22 @@ const carnivores = await dinosaurRepo.query.byDiet({ diet: "carnivore" }).execut
 const trexes = await dinosaurRepo.query.bySpecies({ species: "Tyrannosaurus Rex" }).execute();
 ```
 
-#### 4. Indexes for Efficient Querying
+#### 4. Defining GSI access patterns
 
-Define indexes for efficient access patterns:
+Define GSI (LSI support coming later)
 
 ```ts
 import { createIndex } from "dyno-table/entity";
 
-// Define GSI for querying by species
+// Define GSIs templates for querying by species
+const gsi1PK = partitionKey`SPECIES#${"species"}`
+const gsi1SK = sortKey`DINOSAUR#${"id"}`
+
+// Implement typesafe generator for the GSI - This is used in create calls to ensure the GSI is generated
 const speciesIndex = createIndex()
   .input(dinosaurSchema)
-  .partitionKey(({ species }) => `SPECIES#${species}`)
-  .sortKey(({ id }) => `DINOSAUR#${id}`);
+  .partitionKey(({ species }) => gsi1PK({ species }))
+  .sortKey(({ id }) => gsi1SK({ id }));
 
 const DinosaurEntity = defineEntity({
   name: "Dinosaur",
@@ -367,49 +539,27 @@ const DinosaurEntity = defineEntity({
       )
       .query(({ input, entity }) => {
         return entity
-          .queryBuilder({
-            pk: `SPECIES#${input.species}`,
+          .query({
+            // Use the GSI template generator to avoid typos
+            pk: gsi1PK({species: input.species}),
           })
-          .useIndex("species");
+          // Use the template name as defined in the table instance
+          .useIndex("gsi1");
       }),
   },
 });
 ```
 
-#### 5. Lifecycle Hooks
-
-Add hooks for pre/post processing:
-
-```ts
-const dinosaurHooks = {
-  afterGet: async (data: Dinosaur | undefined) => {
-    if (data) {
-      return {
-        ...data,
-        displayName: `${data.name} (${data.species})`,
-        threatLevel: data.dangerLevel > 7 ? "HIGH" : "MODERATE",
-      };
-    }
-    return data;
-  },
-};
-
-const DinosaurEntity = defineEntity({
-  name: "Dinosaur",
-  schema: dinosaurSchema,
-  primaryKey,
-  hooks: dinosaurHooks,
-});
-```
-
 ### Complete Entity Example
 
-Here's a complete example using Zod schemas directly:
+Here's a complete example of using Zod schemas directly:
 
 ```ts
 import { z } from "zod";
 import { defineEntity, createQueries, createIndex } from "dyno-table/entity";
 import { Table } from "dyno-table/table";
+import { sortKey } from "dyno-table/utils/sort-key-template";
+import { partitionKey } from "dyno-table/utils/partition-key-template";
 
 // Define the schema with Zod
 const dinosaurSchema = z.object({
@@ -432,8 +582,14 @@ const dinosaurSchema = z.object({
 type Dinosaur = z.infer<typeof dinosaurSchema>;
 
 // Define key templates
-const dinosaurPK = (id: string) => `DINOSAUR#${id}`;
-const dinosaurSK = (status: string) => `STATUS#${status}`;
+const dinosaurPK = partitionKey`DINOSAUR#${"id"}`;
+const dinosaurSK = sortKey`STATUS#${"status"}`;
+
+const gsi1PK = partitionKey`SPECIES#${"species"}`
+const gsi1SK = sortKey`DINOSAUR#${"id"}`
+
+const gsi2PK = partitionKey`ENCLOSURE#${"enclosureId"}`
+const gsi2SK = sortKey`DINOSAUR#${"id"}`
 
 // Create a primary index
 const primaryKey = createIndex()
@@ -444,14 +600,14 @@ const primaryKey = createIndex()
 // Create a GSI for querying by species
 const speciesIndex = createIndex()
   .input(dinosaurSchema)
-  .partitionKey(({ species }) => `SPECIES#${species}`)
-  .sortKey(({ id }) => `DINOSAUR#${id}`);
+  .partitionKey(({ species }) => gsi1PK({ species }))
+  .sortKey(({ id }) => gsiSK({ id }));
 
 // Create a GSI for querying by enclosure
 const enclosureIndex = createIndex()
   .input(dinosaurSchema)
-  .partitionKey(({ enclosureId }) => `ENCLOSURE#${enclosureId}`)
-  .sortKey(({ id }) => `DINOSAUR#${id}`);
+  .partitionKey(({ enclosureId }) => gsi2PK({ enclosureId }))
+  .sortKey(({ id }) => gsi2SK({ id }));
 
 // Create query builders
 const createQuery = createQueries<Dinosaur>();
@@ -462,8 +618,9 @@ const DinosaurEntity = defineEntity({
   schema: dinosaurSchema,
   primaryKey,
   indexes: {
-    species: speciesIndex,
-    enclosure: enclosureIndex,
+    // These keys need to be named after the name of the GSI that is defined in your table instance 
+    gsi1: speciesIndex,
+    gsi2: enclosureIndex,
   },
   queries: {
     bySpecies: createQuery
@@ -474,10 +631,10 @@ const DinosaurEntity = defineEntity({
       )
       .query(({ input, entity }) => {
         return entity
-          .queryBuilder({
-            pk: `SPECIES#${input.species}`,
+          .query({
+            pk: gsi1PK({ species: input.species }),
           })
-          .useIndex("species");
+          .useIndex("gsi1");
       }),
 
     byEnclosure: createQuery
@@ -488,10 +645,10 @@ const DinosaurEntity = defineEntity({
       )
       .query(({ input, entity }) => {
         return entity
-          .queryBuilder({
-            pk: `ENCLOSURE#${input.enclosureId}`,
+          .query({
+            pk: gsi2PK({ enclosureId: input.enclosureId }),
           })
-          .useIndex("enclosure");
+          .useIndex("gsi2");
       }),
 
     dangerousInEnclosure: createQuery
@@ -503,10 +660,10 @@ const DinosaurEntity = defineEntity({
       )
       .query(({ input, entity }) => {
         return entity
-          .queryBuilder({
-            pk: `ENCLOSURE#${input.enclosureId}`,
+          .query({
+            pk: gsi2PK({ enclosureId: input.enclosureId }),
           })
-          .useIndex("enclosure")
+          .useIndex("gsi2")
           .filter((op) => op.gte("dangerLevel", input.minDangerLevel));
       }),
   },
@@ -548,7 +705,7 @@ async function main() {
 
 **Key benefits:**
 - 🚫 Prevents accidental cross-type data access
-- 🔍 Automatically filters queries/scans to repository type
+- 🔍 Automatically filters queries/scans to a repository type
 - 🛡️ Ensures consistent key structure across entities
 - 📦 Encapsulates domain-specific query logic
 - 🧪 Validates data with Zod schemas
@@ -661,7 +818,6 @@ await dinoTable.transaction(
 - 🔄 Uses the same familiar API as non-transactional operations
 - 🧠 Maintains consistent mental model for developers
 - 🔒 All operations within the callback are executed as a single transaction
-- ✅ All-or-nothing operations (ACID compliance)
 - 🛡️ Prevents race conditions and data inconsistencies
 - 📊 Supports up to 100 actions per transaction
 
diff --git a/package.json b/package.json
index 6bfcd42..ce405e4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "dyno-table",
-  "version": "1.0.0-alpha.1",
+  "version": "0.2.0-0",
   "description": "A TypeScript library to simplify working with DynamoDB",
   "main": "./dist/index.cjs",
   "module": "./dist/index.js",


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>♻️ Duplicate comments (1)</summary><blockquote>

<details>
<summary>README.md (1)</summary><blockquote>

`438-439`: **SortKey typo in complete example (duplicate).**  
This is the same `gsiSK` reference issue noted earlier. It should call `gsi1SK` instead of `gsiSK`.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>README.md (2)</summary><blockquote>

`181-181`: **Improve clarity of the example link sentence.**  
The sentence reads:  
  “You can find a full example implementation here of [Entities](https://github.com/Kysumi/dyno-table/blob/main/examples/entity-example/src/dinosaur-entity.ts)”  
Consider rephrasing to:  
  “You can find the full example implementation of **Entities** here: [link]”  
to enhance readability and maintain a consistent call-to-action style.

---

`256-256`: **Add punctuation to inline comment.**  
The comment `// could also be .withoutSortKey() if your table doesn't use sort keys` would read more cleanly with a period at the end:
```diff
-  .sortKey(({ id, species }) => dinosaurSK({ species, id })) // could also be .withoutSortKey() if your table doesn't use sort keys
+  .sortKey(({ id, species }) => dinosaurSK({ species, id })) // could also be .withoutSortKey() if your table doesn't use sort keys.
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

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

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 2e86f76e6cf58d3cab4e438d93e42a6f4e3cba05 and f5eb07a6530c94f7bb67bd3c7d46f01cfffe0d5c.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `README.md` (12 hunks)
* `package.json` (1 hunks)

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* package.json

</details>

<details>
<summary>🔇 Additional comments (11)</summary><blockquote>

<details>
<summary>README.md (11)</summary>

`320-322`: **Good: Switched from `.scan().filter()` to `.query()`.**  
Using `.query({ pk: ... })` instead of `.scan()` with a post-filter greatly improves efficiency by leveraging DynamoDB’s key-condition optimizations.

---

`351-353`: **Nice: Introducing typed key template generators for GSIs.**  
Defining `gsi1PK` and `gsi1SK` improves type safety and reduces hard-coded key typos.

---

`355-355`: **Helpful clarification for GSI template usage.**  
The comment clearly explains that these generators are used in create calls to generate GSI attributes.

---

`377-379`: **Great: Query using the GSI template generator.**  
The snippet correctly uses `gsi1PK({ species: input.species })` for partition-key conditions. This aligns with the new typed‐template approach.

---

`382-382`: **Verify index name consistency.**  
This uses `.useIndex("gsi1")` but earlier examples define the GSI in the table instance under a different key (e.g., `speciesId`). Ensure the string passed to `useIndex` matches the actual GSI name in your `Table` configuration.

---

`396-397`: **Good import of key-template utilities.**  
Bringing in `sortKey` and `partitionKey` from the `utils` directory makes the example self-contained and clear.

---

`420-421`: **Clear definition of primary key templates.**  
Defining `dinosaurPK` and `dinosaurSK` with template literals provides a concise, type-safe way to generate primary keys.

---

`423-424`: **Correct GSI#1 template definition.**  
Using `partitionKey\`SPECIES#\${"species"}\`` and `sortKey\`DINOSAUR#\${"id"}\`` is consistent with other examples.

---

`444-445`: **Correct GSI#2 usage in complete example.**  
The partition and sort keys for `enclosureIndex` correctly reference `gsi2PK` and `gsi2SK`, once the templates are fixed.

---

`456-458`: **Consistent GSI naming in entity definition.**  
Using `gsi1` and `gsi2` as object keys matches the `.useIndex("gsi1")`/.`useIndex("gsi2")` calls and aligns with the table instance naming convention.

---

`543-543`: **Typo-free bullet point.**  
The bullet “🔍 Automatically filters queries/scans to a repository type” is clear and consistent with surrounding items.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T00:37:39Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>♻️ Duplicate comments (3)</summary><blockquote>

<details>
<summary>README.md (3)</summary><blockquote>

`77-77`: **Update Table of Contents entry.**  
The section has been renamed to “Defining GSI access patterns” but the TOC still shows “Indexes for Efficient Querying”.  
```diff
-     - [4. Indexes for Efficient Querying](#4-defining-gsi-access-patterns)
+     - [4. Defining GSI access patterns](#4-defining-gsi-access-patterns)
```

---

`523-524`: **Fix undefined variable `gsiSK`.**  
The sortKey generator should reference `gsi1SK`, not the undefined `gsiSK`.  
```diff
-   .sortKey(({ id }) => gsiSK({ id }));
+   .sortKey(({ id }) => gsi1SK({ id }));
```

---

`603-604`: **Fix undefined variable `gsiSK`.**  
Reapply the same correction for the GSI in the complete example.  
```diff
-           .sortKey(({ id }) => gsiSK({ id }));
+           .sortKey(({ id }) => gsi1SK({ id }));
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (5)</summary><blockquote>

<details>
<summary>README.md (5)</summary><blockquote>

`5-5`: **Consistent heading levels.**  
Heading jumps from H1 to H3 here—consider using H2 (`##`) instead of H3 for the tagline to follow heading-increment best practices.  
```diff
- ### **Tame Your DynamoDB Data with Type-Safe Precision**
+ ## **Tame Your DynamoDB Data with Type-Safe Precision**
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

5-5: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

</details>

</details>

---

`67-67`: **Fix invalid anchor fragment.**  
Link fragment `#-installation` should not have a leading hyphen.  
```diff
- - [📦 Installation](#-installation)
+ - [📦 Installation](#installation)
```

---

`71-71`: **Fix invalid anchor fragment.**  
Link fragment `#-entity-pattern-with-standard-schema-validators` should drop the leading hyphen.  
```diff
- - [🏗️ Entity Pattern](#-entity-pattern-with-standard-schema-validators)
+ - [🏗️ Entity Pattern](#entity-pattern-with-standard-schema-validators)
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

71-71: Link fragments should be valid
null

(MD051, link-fragments)

</details>

</details>

---

`78-78`: **Remove outdated TOC entry.**  
The “Lifecycle Hooks” section was removed; this TOC entry should be deleted to avoid broken links.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

78-78: Link fragments should be valid
null

(MD051, link-fragments)

</details>

</details>

---

`585-592`: **Ensure semicolon consistency.**  
Key template constants are declared with semicolons above; add semicolons here for consistency.  
```diff
- const gsi1PK = partitionKey`SPECIES#${"species"}`
- const gsi1SK = sortKey`DINOSAUR#${"id"}`
- const gsi2PK = partitionKey`ENCLOSURE#${"enclosureId"}`
- const gsi2SK = sortKey`DINOSAUR#${"id"}`
+ const gsi1PK = partitionKey`SPECIES#${"species"}`;
+ const gsi1SK = sortKey`DINOSAUR#${"id"}`;
+ const gsi2PK = partitionKey`ENCLOSURE#${"enclosureId"}`;
+ const gsi2SK = sortKey`DINOSAUR#${"id"}`;
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

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

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between f5eb07a6530c94f7bb67bd3c7d46f01cfffe0d5c and ff789e9f5e56d2c459b469d3fdd77618075c0984.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `README.md` (14 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

<details>
<summary>README.md</summary>

5-5: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

---

71-71: Link fragments should be valid
null

(MD051, link-fragments)

---

78-78: Link fragments should be valid
null

(MD051, link-fragments)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (7)</summary><blockquote>

<details>
<summary>README.md (7)</summary>

`1-3`: **Nice header layout.**  
The centered container and main title provide a polished introduction to the library.

---

`7-10`: **Badges look good.**  
The badges are clear, relevant, and styled consistently.

---

`12-15`: **Tagline formatting approved.**  
The closing `</div>` and centered paragraph create a strong, accessible tagline section.

---

`19-19`: **Section heading approved.**  
The “Why Developers Choose dyno-table” heading is clear and properly leveled.

---

`34-34`: **Section heading approved.**  
The “Why dyno-table Stands Out From The Pack” heading reads well and follows the document flow.

---

`112-118`: **Installation section formatting approved.**  
Centered headings and a collapsible “Other Package Managers” section improve readability and accessibility.

---

`140-142`: **Quick Start header formatting approved.**  
The centered “From Zero to DynamoDB Hero in Minutes” section and step numbering render clearly for users.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T01:07:46Z

Review comments:
diff_hunk: @@ -338,18 +341,22 @@ const carnivores = await dinosaurRepo.query.byDiet({ diet: "carnivore" }).execut
 const trexes = await dinosaurRepo.query.bySpecies({ species: "Tyrannosaurus Rex" }).execute();
 ```
 
-#### 4. Indexes for Efficient Querying
+#### 4. Defining GSI access patterns
 
-Define indexes for efficient access patterns:
+Define GSI (LSI support coming later)
 
 ```ts
 import { createIndex } from "dyno-table/entity";
 
-// Define GSI for querying by species
+// Define GSIs templates for querying by species
+const gsi1PK = partitionKey`SPECIES#${"species"}`
+const gsi1SK = sortKey`DINOSAUR#${"id"}`
+
+// Implement typesafe generator for the GSI - This is used in create calls to ensure the GSI is generated
 const speciesIndex = createIndex()
   .input(dinosaurSchema)
-  .partitionKey(({ species }) => `SPECIES#${species}`)
-  .sortKey(({ id }) => `DINOSAUR#${id}`);
+  .partitionKey(({ species }) => gsi1PK({ species }))
+  .sortKey(({ id }) => gsiSK({ id }));
path: README.md
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix variable name typo in GSI sortKey.**  
The code references `gsiSK`, which is undefined. It should call `gsi1SK` to match the template declared above:
```diff
-  .sortKey(({ id }) => gsiSK({ id }));
+  .sortKey(({ id }) => gsi1SK({ id }));
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  .partitionKey(({ species }) => gsi1PK({ species }))
  .sortKey(({ id }) => gsi1SK({ id }));
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In README.md around lines 358 to 359, the code uses an undefined variable
`gsiSK` for the sortKey function. Replace `gsiSK` with the correctly defined
`gsi1SK` to match the naming convention used for the GSI keys and ensure the
code functions as intended.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits 1319ed9 to 17e7c7d
created_at: 2025-05-12T00:37:38Z
author_association: NONE
diff_hunk: @@ -338,18 +341,22 @@ const carnivores = await dinosaurRepo.query.byDiet({ diet: "carnivore" }).execut
 const trexes = await dinosaurRepo.query.bySpecies({ species: "Tyrannosaurus Rex" }).execute();
 ```
 
-#### 4. Indexes for Efficient Querying
+#### 4. Defining GSI access patterns
 
-Define indexes for efficient access patterns:
+Define GSI (LSI support coming later)
path: README.md
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Table of Contents link now broken by heading change.**  
The section was renamed to “4. Defining GSI access patterns” but the TOC still references “4. Indexes for Efficient Querying”. Please update the entry at line 46 in the TOC to match the new heading text and anchor:
```diff
- - [4. Indexes for Efficient Querying](#4-indexes-for-efficient-querying)
+ - [4. Defining GSI access patterns](#4-defining-gsi-access-patterns)
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
- [4. Defining GSI access patterns](#4-defining-gsi-access-patterns)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In README.md around lines 44 to 46, the Table of Contents entry for section 4
still references the old heading "4. Indexes for Efficient Querying" which no
longer matches the updated section title "4. Defining GSI access patterns".
Update the TOC entry at line 46 to exactly match the new heading text and anchor
so the link works correctly.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits 1319ed9 to 17e7c7d
created_at: 2025-05-12T00:37:39Z
author_association: NONE
diff_hunk: @@ -432,8 +417,14 @@ const dinosaurSchema = z.object({
 type Dinosaur = z.infer<typeof dinosaurSchema>;
 
 // Define key templates
-const dinosaurPK = (id: string) => `DINOSAUR#${id}`;
-const dinosaurSK = (status: string) => `STATUS#${status}`;
+const dinosaurPK = partitionKey`DINOSAUR#${"id"}`;
+const dinosaurSK = sortKey`STATUS#${"status"}`;
+
+const gsi1PK = partitionKey`SPECIES#${"species"}`
+const gsi1SK = sortKey`DINOSAUR#${"id"}`
+
+const gsi2PK = partitionKey`ENCLOSURE#${enclosureId}`
+const gsi2SK = sortKey`DINOSAUR#${id}`
path: README.md
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix placeholder syntax in GSI#2 template.**  
The placeholders must be string literals matching the input property names. Update as follows:
```diff
- const gsi2PK = partitionKey`ENCLOSURE#${enclosureId}`
- const gsi2SK = sortKey`DINOSAUR#${id}`
+ const gsi2PK = partitionKey`ENCLOSURE#${"enclosureId"}`
+ const gsi2SK = sortKey`DINOSAUR#${"id"}`
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
const gsi2PK = partitionKey`ENCLOSURE#${"enclosureId"}`
const gsi2SK = sortKey`DINOSAUR#${"id"}`
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In README.md around lines 426 to 427, the placeholders in the GSI#2 template use
template literals with variables, which is incorrect. Replace the template
literals with string literals that exactly match the input property names,
ensuring the placeholders are properly formatted for the partitionKey and
sortKey functions.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits e5dc823 to ff789e9
created_at: 2025-05-12T00:37:39Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-11T21:35:24Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: failure by coderabbit.ai -->

> [!CAUTION]
> ## Review failed
> 
> The pull request is closed.

<!-- end of auto-generated comment: failure by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

The package version in package.json was changed from "1.0.0-alpha.1" to "0.2.0-0" without other modifications. The README.md was extensively updated to improve entity pattern documentation, standardize key template usage, enhance query examples, rename GSI indexes, and remove lifecycle hooks, with no changes to exported entities.

## Changes

| File(s)      | Change Summary                                                                                   |
|--------------|-------------------------------------------------------------------------------------------------|
| package.json | Changed package version from "1.0.0-alpha.1" to "0.2.0-0".                                      |
| README.md    | Extensively revised formatting and structure; added centered badges and tagline; redesigned "Why dyno-table" as a benefits table including flexible schema validation; updated Table of Contents with renamed sections; enhanced installation instructions with collapsible alternative commands; reformatted Quick Start with two-column layout and improved examples; added side-by-side comparison with AWS SDK; enriched Entity Pattern section with benefits table and example link; updated example code to use `partitionKey` and `sortKey` utilities; renamed GSI indexes to `gsi1` and `gsi2`; replaced `.scan().filter()` with `.query()` calls; removed lifecycle hooks subsection; minor wording and formatting fixes throughout. |

## Possibly related PRs

- Kysumi/dyno-table#19: Also updates README.md with restructuring and enhancements, including a repository pattern example, related through documentation improvements but not overlapping in code changes.  
- Kysumi/dyno-table#24: Involves README.md reorganization and content updates similar in scope to this PR’s documentation improvements.  
- Kysumi/dyno-table#37: Modifies package version and README.md with similar restructuring, key template updates, and query improvements, indicating direct relation.

## Suggested reviewers

- Kysumi

## Poem

> 🐇 A version hops from alpha's nest,  
> To zero point two, a tidy quest.  
> Keys and queries now aligned,  
> GSI names refined and signed.  
> Docs refreshed with clearer light,  
> A rabbit's leap to code done right! 🥕

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->

---

<details>
<summary>📜 Recent review details</summary>

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

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between ff789e9f5e56d2c459b469d3fdd77618075c0984 and 17e7c7d9c478760b63dabc7a094d11722afb176a.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `README.md` (14 hunks)

</details>

</details>
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Kysumi/dyno-table&utm_content=37):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `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 generate unit testing code for this file.`
  -	`@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 generate unit testing code.`
  - `@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](https://www.coderabbit.ai/contact-us/support) 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](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in 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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-12T01:27:19Z
body: :tada: This PR is included in version 1.0.0 :tada:

The release is available on:
- [npm package (@latest dist-tag)](https://www.npmjs.com/package/dyno-table/v/1.0.0)
- [GitHub release](https://github.com/Kysumi/dyno-table/releases/tag/v1.0.0)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:
author_association: NONE