Skip to main content

What is Id?

The Id class is a smart wrapper for entity identifiers. It automatically tracks whether an entity is new (needs INSERT) or existing (needs UPDATE).
import { Id } from "@woltz/rich-domain";

// New entity - generates UUID automatically
const newId = new Id();
console.log(newId.isNew()); // true
console.log(newId.value); // "550e8400-e29b-41d4-a716-446655440000"

// Existing entity - uses provided value
const existingId = new Id("user-123");
console.log(existingId.isNew()); // false
console.log(existingId.value); // "user-123"

Creating IDs

Auto-generated (New Entity)

// Using constructor
const id1 = new Id();

// Using static method
const id2 = Id.create();

id1.isNew(); // true
id2.isNew(); // true

From Existing Value (From Database)

// Using constructor
const id1 = new Id("user-123");

// Using static method
const id2 = Id.from("user-123");

id1.isNew(); // false
id2.isNew(); // false

Why This Matters

The isNew() method enables repositories to decide between INSERT and UPDATE:
class UserRepository {
  async save(user: User): Promise<void> {
    if (user.isNew()) {
      await this.insert(user);
    } else {
      await this.update(user);
    }
  }
}

Comparison & Equality

IDs can be compared with other IDs or strings:
const id1 = new Id("user-123");
const id2 = new Id("user-123");
const id3 = new Id("user-456");

// Compare with Id
id1.equals(id2); // true
id1.equals(id3); // false

// Compare with string
id1.equals("user-123"); // true
id1.equals("user-456"); // false

Entity Equality

Entities use ID for equality comparison:
const user1 = new User({
  id: Id.from("user-123"),
  name: "John",
  email: "john@example.com",
});

const user2 = new User({
  id: Id.from("user-123"),
  name: "John Updated", // Different name
  email: "john.new@example.com", // Different email
});

const user3 = new User({
  id: Id.from("user-456"),
  name: "John",
  email: "john@example.com",
});

user1.equals(user2); // true - same ID
user1.equals(user3); // false - different ID

// Can also compare entity with Id or string
user1.equals(Id.from("user-123")); // true
user1.equals("user-123"); // true

Working with Collections

IDs make it easy to find entities in collections:
const users = [
  new User({ id: Id.from("1"), name: "Alice" }),
  new User({ id: Id.from("2"), name: "Bob" }),
  new User({ id: Id.from("3"), name: "Charlie" }),
];

// Find by Id
const searchId = Id.from("2");
const found = users.find((user) => user.equals(searchId));
console.log(found?.name); // "Bob"

// Find by string
const foundByString = users.find((user) => user.equals("2"));
console.log(foundByString?.name); // "Bob"

// Filter by Id
const filtered = users.filter((user) => user.equals("1"));
console.log(filtered.length); // 1

// Check existence
const exists = users.some((user) => user.equals("3"));
console.log(exists); // true

Serialization

IDs serialize to their string value:
const id = new Id("user-123");

// toString
console.log(id.toString()); // "user-123"
console.log(String(id)); // "user-123"

// JSON
console.log(id.toJSON()); // "user-123"
console.log(JSON.stringify(id)); // '"user-123"'

// In entity toJson()
const user = new User({
  id: Id.from("user-123"),
  name: "John",
});

const json = user.toJSON();
console.log(json.id); // "user-123" (string, not Id object)

UUID Generation

When no value is provided, Id generates a UUID v4:
const id1 = new Id();
const id2 = new Id();
const id3 = new Id();

console.log(id1.value); // "550e8400-e29b-41d4-a716-446655440000"
console.log(id2.value); // "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
console.log(id3.value); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"

// All unique
console.log(id1.equals(id2)); // false
console.log(id2.equals(id3)); // false

Practical Example

// Domain model
class Order extends Aggregate<OrderProps> {
  static create(customerId: string): Order {
    return new Order({
      // New order - auto-generated ID
      customerId,
      status: "draft",
      items: [],
      createdAt: new Date(),
    });
  }

  static fromDatabase(data: OrderRow): Order {
    return new Order({
      // Existing order - ID from database
      id: Id.from(data.id),
      customerId: data.customer_id,
      status: data.status,
      items: data.items.map(
        (item) =>
          new OrderItem({
            id: Id.from(item.id),
            productId: item.product_id,
            quantity: item.quantity,
          })
      ),
      createdAt: data.created_at,
    });
  }
}

// Usage
const newOrder = Order.create("customer-123");
console.log(newOrder.isNew()); // true

const existingOrder = Order.fromDatabase(dbRow);
console.log(existingOrder.isNew()); // false

API Reference

Constructor

new Id(); // Generates UUID, isNew = true
new Id("value"); // Uses provided value, isNew = false
// With explicit isNew flag
new Id("value", true);   // Uses provided value, isNew = true (override)
new Id("value", false);  // Uses provided value, isNew = false (default)

Static Methods

MethodDescription
Id.create()Creates a new Id with auto-generated UUID
Id.from(value)Creates an Id from an existing value
Id.compose(a, b)Composes two IDs (Id or string) into a single string

Instance Methods

MethodReturnsDescription
isNew()booleanTrue if ID was auto-generated
equals(other)booleanCompare with Id or string
toString()stringReturns the ID value
toJSON()stringReturns the ID value (for serialization)
markAsNotNew()voidMarks the Id as not new (after persisting)
markAsNew()voidMarks the Id as new

Properties

PropertyTypeDescription
valuestringThe ID string value