Migration Guide

This guide helps you migrate between dcupl SDK versions and adopt new API patterns. The SDK maintains backward compatibility, so migrations are optional but recommended for better developer experience.

Query API Migration (v2.1+)

The query refactor introduces clearer method names while maintaining 100% backward compatibility. Old methods continue to work, but new methods provide better IntelliSense and type safety.

Migration Strategy

You don't need to migrate everything at once:

  1. Continue using old methods (they're not going away in v2.x)
  2. Adopt new methods incrementally as you work on code
  3. Use new methods for all new code

Type Aliases

import { DcuplQuery, DcuplQueryGroup, DcuplGlobalQueryOptions } from '@dcupl/common';

const condition: DcuplQuery = { operator: 'eq', attribute: 'status', value: 'active' };
const group: DcuplQueryGroup = { groupType: 'and', queries: [condition] };
import { QueryCondition, QueryConditionGroup, QueryExecutionContext } from '@dcupl/common';

const condition: QueryCondition = { operator: 'eq', attribute: 'status', value: 'active' };
const group: QueryConditionGroup = { groupType: 'and', queries: [condition] };

Adding Query Conditions

// Magic applyQuery with mode options
builder.applyQuery(condition, { mode: 'add' });
builder.applyQuery([condition1, condition2], { mode: 'add' });
builder.applyQuery(group, { mode: 'add' });
// Explicit methods that reveal intent
builder.addCondition(condition);
builder.addCondition([condition1, condition2]);
builder.addGroup(group);

Replacing Query Conditions

builder.applyQuery(condition, { mode: 'set' });
list.catalog.query.apply(condition, { mode: 'set' });
builder.setCondition(condition);
list.catalog.query.setCondition(condition);

State Management

builder.reset();
builder.removeAllQueries();
builder.getQuery();
builder.clear();
builder.clearConditions();
builder.getCurrentQuery();

Executing Queries

const items = list.catalog.query.execute();
const limited = list.catalog.query.execute({ count: 10 });
const query = list.catalog.query.get();
const items = list.catalog.query.items();
const limited = list.catalog.query.items({ count: 10 });
const first = list.catalog.query.first();
const exists = list.catalog.query.any();
const total = list.catalog.query.count();
const query = list.catalog.query.current();

Complete Migration Example

const builder = new DcuplQueryBuilder();
builder.init({ modelKey: 'Product' });

builder.applyQuery({ operator: 'eq', attribute: 'status', value: 'active' }, { mode: 'add' });
builder.applyQuery({ operator: 'gte', attribute: 'price', value: 100 }, { mode: 'add' });
builder.applyQuery(
  {
    groupKey: 'categories',
    groupType: 'or',
    queries: [
      { operator: 'eq', attribute: 'category', value: 'electronics' },
      { operator: 'eq', attribute: 'category', value: 'books' },
    ],
  },
  { mode: 'add' }
);

const query = builder.getQuery();
const attrs = builder.getQueryAttributes();
const builder = new DcuplQueryBuilder();
builder.init({ modelKey: 'Product' });

builder.addCondition({ operator: 'eq', attribute: 'status', value: 'active' });
builder.addCondition({ operator: 'gte', attribute: 'price', value: 100 });
builder.addGroup({
  groupKey: 'categories',
  groupType: 'or',
  queries: [
    { operator: 'eq', attribute: 'category', value: 'electronics' },
    { operator: 'eq', attribute: 'category', value: 'books' },
  ],
});

const query = builder.getCurrentQuery();
const attrs = builder.getAttributeNames();
const count = builder.getConditionCount();
const isEmpty = builder.isEmpty();

Interactive List Migration

function applyStatusFilter(status: string) {
  list.catalog.query.apply({ operator: 'eq', attribute: 'status', value: status }, { mode: 'add' });
  return list.catalog.query.execute();
}

function clearFilters() {
  list.catalog.query.reset();
  return list.catalog.query.execute();
}

function getFirstProduct() {
  const results = list.catalog.query.execute({ count: 1 });
  return results[0];
}
function applyStatusFilter(status: string) {
  list.catalog.query.addCondition({ operator: 'eq', attribute: 'status', value: status });
  return list.catalog.query.items();
}

function clearFilters() {
  list.catalog.query.clear();
  return list.catalog.query.items();
}

function getFirstProduct() {
  return list.catalog.query.first();
}

// Additional new capabilities
function hasProducts() {
  return list.catalog.query.any();
}

function getProductCount() {
  return list.catalog.query.count();
}

function hasFilters() {
  return !list.catalog.query.isEmpty();
}

Quick Reference Tables

DcuplQueryBuilder Methods

Old Method New Method Purpose
getQueryAttributes() getAttributeNames() Get attribute name strings
extractQueryAttributes() getAttributeDetails() Get detailed attribute info
applyQuery(..., {mode:'add'}) addCondition() Add condition(s)
applyQuery(group, {mode:'add'}) addGroup() Add query group
applyQuery(..., {mode:'set'}) setCondition() Replace condition(s)
reset() clear() Full reset
removeAllQueries() clearConditions() Remove conditions only
getQuery() getCurrentQuery() Get current state
hasQueryGroup() hasGroup() Check group exists
- isEmpty() Check if empty
- hasCondition() Check condition exists
- getConditionCount() Count conditions

CatalogApi Methods

Old Method New Method Purpose
apply(..., {mode:'add'}) addCondition() Add condition(s)
apply(group, {mode:'add'}) addGroup() Add query group
apply(..., {mode:'set'}) setCondition() Replace condition(s)
remove(condition) removeCondition() Remove condition(s)
remove({groupKey}) removeGroup() Remove group
reset() clear() Clear all conditions
get() current() Get current query
execute() items() Get all results
- first() Get first result
- any() Check if results exist
- count() Count results
- isEmpty() Check if empty

Benefits of New API

Old API Challenges:

  • applyQuery() - Implicit behavior based on parameters
  • Mode options - Need to remember { mode: 'add' } vs { mode: 'set' }
  • Limited inspection - Hard to introspect query state

New API Advantages:

  • Explicit methods - addCondition() vs setCondition() clearly show intent
  • Intuitive names - first(), count(), any() match expectations
  • Flexible arguments - Methods accept both single items and arrays
  • Rich inspection - Many methods to understand query state
  • Better IntelliSense - Comprehensive documentation in IDE
  • No breaking changes - Old methods still work

Deprecation Timeline

Current Status: All old methods are marked @deprecated in JSDoc but remain fully functional.

Future: Old methods will be removed in a future versions, but:

  • Ample warning will be provided
  • Old methods will be supported throughout v2.x lifecycle

Recommendation: Start using new methods for new code, migrate existing code opportunistically.

What's Next?