Skip to content

Nimbu.Object

Nimbu.Object is the base class for all data objects in Nimbu. It provides methods for creating, reading, updating, and deleting data across all channels and built-in data types.

Creating Objects

Basic Object Creation

js
// Create a new object for a channel
const blogPost = new Nimbu.Object('blog');
blogPost.set('title', 'My First Post');
blogPost.set('content', 'Hello World!');
await blogPost.save();

Creating with Initial Data

js
const product = new Nimbu.Object('products', {
  name: 'Widget',
  price: 29.99,
  stock: 100
});
await product.save();

Creating Subclasses

For better code organization, create custom subclasses:

js
// Define a custom class
const Book = Nimbu.Object.extend('books');

// Use the custom class
const book = new Book();
book.set('title', 'The Great Gatsby');
book.set('author', 'F. Scott Fitzgerald');
await book.save();

ES6 Class Syntax

js
class Book extends Nimbu.Object {
  constructor() {
    super('books');
  }

  isLong() {
    return this.get('pages') > 300;
  }
}

// Register the subclass
Nimbu.Object.registerSubclass('books', Book);

// Use it
const book = new Book();
book.set('pages', 450);
console.log(book.isLong()); // true

Setting Attributes

Basic Set

js
const customer = new Nimbu.Object('customers');
customer.set('name', 'John Doe');
customer.set('email', '[email protected]');
customer.set('age', 30);

Setting Multiple Attributes

js
customer.set({
  name: 'John Doe',
  email: '[email protected]',
  age: 30,
  subscribed: true
});

Setting Nested Objects

js
customer.set('address', {
  street: '123 Main St',
  city: 'New York',
  zip: '10001'
});

Setting Arrays

js
product.set('tags', ['electronics', 'gadgets', 'sale']);
product.set('colors', ['red', 'blue', 'green']);

Getting Attributes

Basic Get

js
const name = customer.get('name');
const email = customer.get('email');
const age = customer.get('age');

Getting with Default Value

js
const status = customer.get('status') || 'active';
const points = customer.get('loyalty_points') || 0;

Checking if Attribute Exists

js
if (customer.has('email')) {
  console.log('Email:', customer.get('email'));
}

Saving Objects

Basic Save

js
const entry = new Nimbu.Object('blog');
entry.set('title', 'New Post');

await entry.save();
console.log('Saved with ID:', entry.id);

Save with Error Handling

js
try {
  await entry.save();
  console.log('Save successful');
} catch (error) {
  console.error('Save failed:', error.message);
}

Save Specific Attributes

js
// Only save the 'status' field
await order.save({ status: 'shipped' });

Updating Objects

Fetch and Update

js
// Fetch existing object
const product = await new Nimbu.Query('products').get(productId);

// Update attributes
product.set('price', 39.99);
product.set('stock', 50);

// Save changes
await product.save();

Refresh from Server

js
// Reload latest data from server
await product.fetch();

// Now product has the latest data
const latestPrice = product.get('price');

Deleting Objects

Delete (Destroy)

js
const entry = await new Nimbu.Query('blog').get(entryId);
await entry.destroy();

console.log('Entry deleted');

Conditional Delete

js
const order = await new Nimbu.Query('orders').get(orderId);

if (order.get('status') === 'draft') {
  await order.destroy();
} else {
  console.log('Cannot delete non-draft order');
}

Special Fields

Object ID

js
// Get the unique ID
const id = object.id;

// Or using objectId
const sameId = object.get('id');

Created At

js
const createdAt = object.createdAt;
// or
const created = object.get('created_at');

console.log('Created:', createdAt.toLocaleDateString());

Updated At

js
const updatedAt = object.updatedAt;
// or
const updated = object.get('updated_at');

console.log('Last updated:', updatedAt.toLocaleString());

Check if Object is New

js
if (!object.id) {
  console.log('This is a new object');
} else {
  console.log('This object exists in the database');
}

Counters and Atomic Operations

Increment Counter

js
// Increment by 1
await customer.increment('loyalty_points');

// Increment by specific amount
await customer.increment('login_count', 1);
await customer.increment('balance', 50);

await customer.save();

Decrement Counter

js
// Decrement by 1
await product.increment('stock', -1);

// Or by specific amount
await product.increment('stock', -5);

await product.save();

Why Use Counters?

Counters are atomic and prevent race conditions:

js
// BAD: Race condition possible
const current = product.get('stock');
product.set('stock', current - 1);
await product.save();

// GOOD: Atomic operation
await product.increment('stock', -1);
await product.save();

Working with Relations

One-to-One Relations

js
// Create related objects
const author = new Nimbu.Object('authors');
author.set('name', 'Jane Doe');
await author.save();

const book = new Nimbu.Object('books');
book.set('title', 'My Book');
book.set('author', author); // Set relation
await book.save();

// Access related object
const bookAuthor = book.get('author');
console.log('Author:', bookAuthor.get('name'));

Many-to-One Relations

js
// Multiple books can have the same author
const book1 = new Nimbu.Object('books');
book1.set('title', 'Book One');
book1.set('author', author);

const book2 = new Nimbu.Object('books');
book2.set('title', 'Book Two');
book2.set('author', author);

await book1.save();
await book2.save();

Working with Nimbu.Relation

js
// For many-to-many relationships
const customer = new Nimbu.Object('customers');
const favoriteProducts = customer.relation('favorite_products');

// Add products to the relation
const product1 = await new Nimbu.Query('products').get(id1);
const product2 = await new Nimbu.Query('products').get(id2);

favoriteProducts.add(product1);
favoriteProducts.add(product2);

await customer.save();

// Query the relation
const favorites = await favoriteProducts.query().collection().fetch();
console.log(`Customer has ${favorites.length} favorite products`);

Data Types

Supported Data Types

js
// String
object.set('name', 'John Doe');

// Number
object.set('age', 30);
object.set('price', 29.99);

// Boolean
object.set('active', true);

// Date
object.set('published_at', new Date());

// Array
object.set('tags', ['tag1', 'tag2']);

// Object
object.set('address', {
  street: '123 Main St',
  city: 'New York'
});

// Null
object.set('notes', null);

// Relations
object.set('author', authorObject);

Unsetting Attributes

Remove an Attribute

js
// Remove an attribute completely
object.unset('temporary_field');
await object.save();

Dirty Tracking

Check if Object Has Changes

js
if (object.dirty()) {
  console.log('Object has unsaved changes');
  await object.save();
}

Get Changed Attributes

js
const changes = object.dirtyKeys();
console.log('Changed fields:', changes);

Check Specific Field

js
if (object.dirty('price')) {
  console.log('Price was changed');
}

Common Patterns

Conditional Updates

js
const product = await new Nimbu.Query('products').get(productId);

if (product.get('stock') > 0) {
  await product.increment('stock', -1);
  await product.save();
} else {
  throw new Error('Out of stock');
}

Batch Creation

js
const entries = [];

for (let i = 0; i < 10; i++) {
  const entry = new Nimbu.Object('blog');
  entry.set('title', `Post ${i + 1}`);
  entries.push(entry);
}

// Save all
for (const entry of entries) {
  await entry.save();
}

Safe Updates

js
async function updateProduct(productId, updates) {
  try {
    const product = await new Nimbu.Query('products').get(productId);

    for (const [key, value] of Object.entries(updates)) {
      product.set(key, value);
    }

    await product.save();
    return { success: true, product };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

Best Practices

js
// Good: Save related objects before saving parent
const author = new Nimbu.Object('authors');
author.set('name', 'John');
await author.save(); // Save first

const book = new Nimbu.Object('books');
book.set('author', author);
await book.save(); // Then save parent

2. Use Atomic Operations for Counters

js
// Good
await product.increment('views', 1);
await product.save();

// Avoid
const views = product.get('views') || 0;
product.set('views', views + 1);
await product.save();

3. Handle Errors

js
try {
  await object.save();
} catch (error) {
  if (error.code === 101) {
    console.error('Object not found');
  } else {
    console.error('Save failed:', error.message);
  }
}

4. Use Subclasses for Organization

js
// Define reusable classes
const Product = Nimbu.Object.extend('products');
const Customer = Nimbu.Object.extend('customers');

// Use them throughout your code
const product = new Product();
const customer = new Customer();

Next Steps