Build Your First dcupl Application

In this tutorial, you will build a complete dcupl application from scratch. By the end, you will have a working app that loads data, queries it, and displays results.

Time required: 15 minutes

What you will build: A simple book library app that filters books by genre and displays results.

Prerequisites

Before starting, make sure you have:

  • Node.js 18 or higher installed (node -v to check)
  • A code editor (VS Code recommended)
  • Basic familiarity with TypeScript/JavaScript

Step 1: Create a New Project

Create a new directory for your project and initialize it.

terminal
mkdir my-dcupl-app
cd my-dcupl-app
npm init -y

Install the dcupl core package:

npm install @dcupl/core
yarn add @dcupl/core
pnpm add @dcupl/core

TypeScript types are included, so no additional packages are needed.

Step 2: Create the Application File

Create a new file called app.ts in your project root:

app.ts
import { Dcupl } from '@dcupl/core';

async function main() {
  console.log('Starting dcupl app...');

  // We will add code here in the next steps
}

main();

Run it to make sure everything is set up correctly:

terminal
npx tsx app.ts

You should see "Starting dcupl app..." in your terminal.

Step 3: Create a dcupl Instance

The Dcupl class is the entry point for everything. Create an instance at the top of your main function:

app.ts
import { Dcupl } from '@dcupl/core';

async function main() {
  // Create the dcupl instance
  const dcupl = new Dcupl();

  console.log('dcupl instance created');
}

main();

The dcupl instance is an empty container. Next, you will tell it what kind of data to expect.

Step 4: Define a Model

Models describe the structure of your data. Think of them like TypeScript interfaces or database schemas.

Add this model definition after creating the dcupl instance:

app.ts
import { Dcupl } from '@dcupl/core';

async function main() {
  const dcupl = new Dcupl();

  // Define the Book model
  dcupl.models.set({
    key: 'Book',
    properties: [
      { key: 'title', type: 'string' },
      { key: 'author', type: 'string' },
      { key: 'genre', type: 'string' },
      { key: 'year', type: 'int' },
      { key: 'rating', type: 'float' },
    ],
  });

  console.log('Model defined');
}

main();

This tells dcupl that "Book" items have five properties: title, author, genre, year, and rating.

Step 5: Load Data

Now add some data that matches the model. In a real app, this could come from an API or file. For now, use inline data:

app.ts
import { Dcupl } from '@dcupl/core';

async function main() {
  const dcupl = new Dcupl();

  // Define the Book model
  dcupl.models.set({
    key: 'Book',
    properties: [
      { key: 'title', type: 'string' },
      { key: 'author', type: 'string' },
      { key: 'genre', type: 'string' },
      { key: 'year', type: 'int' },
      { key: 'rating', type: 'float' },
    ],
  });

  // Load book data
  dcupl.data.set(
    [
      {
        key: 'b1',
        title: 'The Great Gatsby',
        author: 'F. Scott Fitzgerald',
        genre: 'Fiction',
        year: 1925,
        rating: 4.5,
      },
      {
        key: 'b2',
        title: 'To Kill a Mockingbird',
        author: 'Harper Lee',
        genre: 'Fiction',
        year: 1960,
        rating: 4.8,
      },
      {
        key: 'b3',
        title: 'A Brief History of Time',
        author: 'Stephen Hawking',
        genre: 'Science',
        year: 1988,
        rating: 4.6,
      },
      {
        key: 'b4',
        title: 'The Selfish Gene',
        author: 'Richard Dawkins',
        genre: 'Science',
        year: 1976,
        rating: 4.3,
      },
      {
        key: 'b5',
        title: '1984',
        author: 'George Orwell',
        genre: 'Fiction',
        year: 1949,
        rating: 4.7,
      },
      {
        key: 'b6',
        title: 'Cosmos',
        author: 'Carl Sagan',
        genre: 'Science',
        year: 1980,
        rating: 4.9,
      },
    ],
    { model: 'Book' }
  );

  console.log('Data loaded');
}

main();

Each item needs a unique key property. This is how dcupl identifies items internally.

Step 6: Initialize dcupl

Before querying, you must call init(). This builds indexes for fast lookups:

app.ts
// ... previous code ...

  // Initialize dcupl (builds indexes)
  await dcupl.init();

  console.log('dcupl initialized and ready');
}

main();

Run the app again to verify everything works:

terminal
npx tsx app.ts

Step 7: Create Your First Query

Now for the fun part. Create a list to query your data:

app.ts
import { Dcupl } from '@dcupl/core';

async function main() {
  const dcupl = new Dcupl();

  dcupl.models.set({
    key: 'Book',
    properties: [
      { key: 'title', type: 'string' },
      { key: 'author', type: 'string' },
      { key: 'genre', type: 'string' },
      { key: 'year', type: 'int' },
      { key: 'rating', type: 'float' },
    ],
  });

  dcupl.data.set(
    [
      {
        key: 'b1',
        title: 'The Great Gatsby',
        author: 'F. Scott Fitzgerald',
        genre: 'Fiction',
        year: 1925,
        rating: 4.5,
      },
      {
        key: 'b2',
        title: 'To Kill a Mockingbird',
        author: 'Harper Lee',
        genre: 'Fiction',
        year: 1960,
        rating: 4.8,
      },
      {
        key: 'b3',
        title: 'A Brief History of Time',
        author: 'Stephen Hawking',
        genre: 'Science',
        year: 1988,
        rating: 4.6,
      },
      {
        key: 'b4',
        title: 'The Selfish Gene',
        author: 'Richard Dawkins',
        genre: 'Science',
        year: 1976,
        rating: 4.3,
      },
      {
        key: 'b5',
        title: '1984',
        author: 'George Orwell',
        genre: 'Fiction',
        year: 1949,
        rating: 4.7,
      },
      {
        key: 'b6',
        title: 'Cosmos',
        author: 'Carl Sagan',
        genre: 'Science',
        year: 1980,
        rating: 4.9,
      },
    ],
    { model: 'Book' }
  );

  await dcupl.init();

  // Create a list for the Book model
  const bookList = dcupl.lists.create({ modelKey: 'Book' });

  // Get all books
  const allBooks = bookList.catalog.query.items();
  console.log('All books:', allBooks.length);

  // Get the first book
  const firstBook = bookList.catalog.query.first();
  console.log('First book:', firstBook?.title);
}

main();

Run it:

terminal
npx tsx app.ts

You should see:

All books: 6
First book: The Great Gatsby

Step 8: Add Filters

Filter the list to show only science books:

app.ts
// ... after creating bookList ...

// Filter by genre
bookList.catalog.query.addCondition({
  attribute: 'genre',
  operator: 'eq',
  value: 'Science',
});

const scienceBooks = bookList.catalog.query.items();
console.log('\nScience books:');
scienceBooks.forEach((book) => {
  console.log(`  - ${book.title} by ${book.author}`);
});

Output:

Science books:
  - A Brief History of Time by Stephen Hawking
  - The Selfish Gene by Richard Dawkins
  - Cosmos by Carl Sagan

Step 9: Add Multiple Filters

Add another filter to find highly-rated science books:

app.ts
// Add a second condition (rating >= 4.5)
bookList.catalog.query.addCondition({
  attribute: 'rating',
  operator: 'gte',
  value: 4.5,
});

const topScienceBooks = bookList.catalog.query.items();
console.log('\nTop-rated science books (4.5+):');
topScienceBooks.forEach((book) => {
  console.log(`  - ${book.title} (${book.rating})`);
});

Multiple conditions use AND logic by default.

Step 10: Sort and Paginate

Sort results and limit the output:

app.ts
// Clear previous filters
bookList.catalog.query.clear();

// Get all books sorted by year (newest first)
const sortedBooks = bookList.catalog.query.items({
  sort: { attributes: ['year'], order: ['desc'] },
});

console.log('\nBooks by year (newest first):');
sortedBooks.forEach((book) => {
  console.log(`  - ${book.year}: ${book.title}`);
});

// Paginate: get first 3 books
const firstPage = bookList.catalog.query.items({
  start: 0,
  count: 3,
});

console.log('\nFirst page (3 books):');
firstPage.forEach((book) => {
  console.log(`  - ${book.title}`);
});

Step 11: Get Facet Counts

Facets tell you how many items exist for each value. This is useful for building filter UIs:

app.ts
// Get facet counts for genres
const genreFacets = bookList.catalog.fn.facets({ attribute: 'genre' });

console.log('\nBooks by genre:');
genreFacets.forEach((facet) => {
  console.log(`  - ${facet.value}: ${facet.count} books`);
});

Output:

Books by genre:
  - Fiction: 3 books
  - Science: 3 books

Complete Code

Here is the complete application:

app.ts
import { Dcupl } from '@dcupl/core';

async function main() {
  // 1. Create dcupl instance
  const dcupl = new Dcupl();

  // 2. Define model
  dcupl.models.set({
    key: 'Book',
    properties: [
      { key: 'title', type: 'string' },
      { key: 'author', type: 'string' },
      { key: 'genre', type: 'string' },
      { key: 'year', type: 'int' },
      { key: 'rating', type: 'float' },
    ],
  });

  // 3. Load data
  dcupl.data.set(
    [
      {
        key: 'b1',
        title: 'The Great Gatsby',
        author: 'F. Scott Fitzgerald',
        genre: 'Fiction',
        year: 1925,
        rating: 4.5,
      },
      {
        key: 'b2',
        title: 'To Kill a Mockingbird',
        author: 'Harper Lee',
        genre: 'Fiction',
        year: 1960,
        rating: 4.8,
      },
      {
        key: 'b3',
        title: 'A Brief History of Time',
        author: 'Stephen Hawking',
        genre: 'Science',
        year: 1988,
        rating: 4.6,
      },
      {
        key: 'b4',
        title: 'The Selfish Gene',
        author: 'Richard Dawkins',
        genre: 'Science',
        year: 1976,
        rating: 4.3,
      },
      {
        key: 'b5',
        title: '1984',
        author: 'George Orwell',
        genre: 'Fiction',
        year: 1949,
        rating: 4.7,
      },
      {
        key: 'b6',
        title: 'Cosmos',
        author: 'Carl Sagan',
        genre: 'Science',
        year: 1980,
        rating: 4.9,
      },
    ],
    { model: 'Book' }
  );

  // 4. Initialize
  await dcupl.init();

  // 5. Create a queryable list
  const bookList = dcupl.lists.create({ modelKey: 'Book' });

  // Get all books
  console.log('Total books:', bookList.catalog.query.count());

  // Filter by genre
  bookList.catalog.query.addCondition({
    attribute: 'genre',
    operator: 'eq',
    value: 'Science',
  });

  console.log('\nScience books:');
  bookList.catalog.query.items().forEach((book) => {
    console.log(`  - ${book.title} by ${book.author}`);
  });

  // Clear and show facets
  bookList.catalog.query.clear();

  console.log('\nBooks by genre:');
  bookList.catalog.fn.facets({ attribute: 'genre' }).forEach((facet) => {
    console.log(`  - ${facet.value}: ${facet.count}`);
  });
}

main();

What You Learned

In this tutorial, you learned how to:

  1. Create a dcupl instance
  2. Define a model with typed properties
  3. Load data into the model
  4. Initialize dcupl to build indexes
  5. Create a list to query data
  6. Filter data with conditions
  7. Sort and paginate results
  8. Get facet counts for building filter UIs

Next Steps

Now that you have the basics, try these tutorials:

Troubleshooting

Error: "Cannot find module '@dcupl/core'"

Make sure you installed the package:

npm install @dcupl/core

Error: "Model not found"

Make sure you call dcupl.models.set() before dcupl.init().

Query returns no results

Check that your filter values match exactly. Filters are case-sensitive by default.