Skip to content

BlakePeterson54/in-memory-inventory-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

In-Memory Inventory (JS)

Tiny, side effecting inventory core written in plain JavaScript. Started as a freeCodeCamp exercise and expanded to include strict parsing, safe integer guards, and a unified result contract for all operations.

Why this exists

  • Practice writing small, reliable stateful code (no frameworks)
  • Show a clear result contract instead of console-only output

What it does

  • Tracks items as {name, quantity} in memory
  • Normalizes inputs (name trimmed + lowercase; quantity must be a positive safe integer)
  • Provides two mutating APIs:
    • addProduct(name, quantity)
    • removeProduct(name, quantity)
  • Returns the same JSON shape for every outcome (created, updated, removed, not_found, insufficient)

Quick Start

Browser (drop in)

<script src="./main.js"></script>
<script>
  addProduct("Widget", 5); //created
  addProduct("widget", 2); //updated (same normalized name)
  removeProduct("widget", 3); //updated
  console.log(inventory); //[{name: 'widget', quantity: 4}]
</script>

State lives in the global inventory array exposed by main.js

API

addProduct(name, quantity)

  • Adds a new item or increases quantity of an existing type (existing product)
  • Returns a result object (see contract below)

Enumerations

In code these are frozen with Object.freeze to prevent mutation

const OP = Object.freeze({ ADD: "add", REMOVE: "remove" });
const STATUS = Object.freeze({
  created: "created",
  updated: "updated",
  removed: "removed",
  notFound: "not_found",
  insufficient: "insufficient",
});

Unified result contract

Every call returns the same shape:

{ op: 'add' | 'remove', //which API
  status: 'created'| 'updated' | 'removed' | 'not_found' | 'insufficient', // outcome
  name: string,                    // normalized product name
  requested: number,              // user's input (always positive)
  applied: number,               // +q for add, -q for remove, 0 if blocked
  previous: number | null,      // qty before op (null if not_found/new)
  current: number | null,      // qty after op (null if not_found)
  shortage: number | null,    // remove-only: (requested - previous) when insufficient
  changed: boolean,          // whether the inventory mutated
}

Invariants (always true)

  • When previous is not null: current === previous + applied
  • applied is requested for adds, 0 for blocked operations (not_found, insufficient), and -requested for successful removes
  • shortage is null except when status === 'insufficient', where shortage === requested - previous and shortage > 0
  • changed is true only for created, updated, removed

Examples

Create

addProduct("Bolts", 5);
// { op: 'add', status:'created', name: 'bolts', requested: 5, applied: 5,
// previous: null, current: 5, changed: true }

Update (add more)

addProduct("bolts", 3);
// { op: 'add', status: 'updated', name: 'bolts', requested:3, applied: 3,
// previous: 5, current: 8, shortage: null, changed: true }

Insufficient remove

removeProduct("bolts", 10);
// { op: 'remove', status: 'insufficient', name: 'bolts', requested: 10, applied: 0,
// previous: 8, current: 8, shortage: 2, changed: false }

Exact remove

removeProduct("bolts", 8);
// { op: 'remove', status: 'removed', name: 'bolts', requested: 8, applied: -8,
// previous: 8, current: 0, shortage: null, changed: true }

Not found

removeProduct("nuts", 1);
// { op: 'remove', status: 'not_found', name: 'nuts', requested: 1, applied: 0,
// previous: null, current: null, shortage: null, changed: false }

Errors (what it throws)

These are programmer/data errors and will throw exceptions:

  • parseName:
    • non-string -> TypeError
    • empty after trim -> RangeError
  • parseQuantity:
    • non-numeric / non-digit string -> TypeError
    • ≤ 0 or not a safe integer -> RangeError
  • Add overflow:
    • previous + requested is not a safe integer -> RangeError

Business rule failures (not_found, insufficient) do not throw; they return a result with status explaining what happened.

Limitations

  • In-memory only; data resets on page reload. State is kept in a module level inventory array for simplicity
  • Case-insensitive names by design (stored lowercase)

Roadmap / Future Work

This project was focused on data validation and invariants

  • Instance factory (multiple inventories via a closure)
  • Add automated tests, learn Node's built in test runner and codify these invariants
  • Optional 'safe' wrapper that never throws and returns {status: 'error', ...} envelopes for boundary use

Attribution

  • Inspired by a freeCodeCamp JavaScript exercise; expanded with input validation, safe integer checks, and unified return contract

License

MIT

About

Tiny in-memory inventory core with strict validation and a unified result contract

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published