CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sift

MongoDB query filtering in JavaScript

Pending
Overview
Eval results
Files

advanced-features.mddocs/

Advanced Features

Advanced functionality for custom operations, fine-grained control, and extending Sift's capabilities.

Capabilities

Custom Query Operations

Create query testers with custom operation sets, allowing for fine-grained control over which operations are available.

Create Query Tester

Creates a query tester without built-in operations, enabling custom operation sets.

/**
 * Creates a query tester without built-in operations for custom operation sets
 * @param query - Query object using available operations
 * @param options - Configuration including custom operations and comparison function
 * @returns Filter function that can be used with Array.filter() or for testing values
 */
function createQueryTester<TItem, TSchema = TItem>(
  query: Query<TSchema>,
  options?: Partial<Options>
): (item: TItem) => boolean;

Usage Examples:

import { createQueryTester, $eq, $gt, $in } from "sift";

// Create tester with only specific operations
const customFilter = createQueryTester(
  { age: { $gt: 18 }, status: { $in: ["active", "pending"] } },
  { 
    operations: { $eq, $gt, $in },
    compare: (a, b) => a === b // Custom comparison
  }
);

const users = [
  { age: 25, status: "active" },
  { age: 16, status: "pending" },
  { age: 30, status: "inactive" }
];

const filtered = users.filter(customFilter); 
// [{ age: 25, status: "active" }]

Create Default Query Operation

Creates a query operation with all default MongoDB operations.

/**
 * Creates a query operation with all default MongoDB operations
 * @param query - Query object
 * @param ownerQuery - Parent query object
 * @param options - Partial options (operations will be merged with defaults)
 * @returns QueryOperation instance
 */
function createDefaultQueryOperation<TItem, TSchema extends TItem = TItem>(
  query: Query<TSchema>,
  ownerQuery: any,
  options?: Partial<Options>
): QueryOperation<TItem>;

Create Query Operation

Creates a query operation from a query object with custom options.

/**
 * Creates a query operation from a query object
 * @param query - Query object
 * @param ownerQuery - Parent query object (optional)
 * @param options - Partial options including operations and comparison function
 * @returns QueryOperation instance
 */
function createQueryOperation<TItem, TSchema = TItem>(
  query: Query<TSchema>,
  ownerQuery?: any,
  options?: Partial<Options>
): QueryOperation<TItem>;

Operation Infrastructure

Low-level operation creation and testing functionality for building custom operations.

Create Operation Tester

Creates a tester function from an operation instance.

/**
 * Creates a tester function from an operation instance
 * @param operation - Operation instance to create tester for
 * @returns Function that tests items against the operation
 */
function createOperationTester<TItem>(
  operation: Operation<TItem>
): (item: TItem, key?: Key, owner?: any) => boolean;

Create Equals Operation

Creates an equals operation for custom operation development.

/**
 * Creates an equals operation for custom operation development
 * @param params - Parameters for the operation (value to match or test function)
 * @param ownerQuery - Parent query object
 * @param options - Operation options including comparison function
 * @returns EqualsOperation instance
 */
function createEqualsOperation(
  params: any,
  ownerQuery: any,
  options: Options
): EqualsOperation;

Usage Examples:

import { 
  createQueryOperation, 
  createOperationTester, 
  createEqualsOperation, 
  $eq 
} from "sift";

// Create custom operation
const customEquals = createEqualsOperation(
  (value) => value > 10,
  null,
  { 
    operations: { $eq },
    compare: (a, b) => a === b 
  }
);

// Test the operation
const tester = createOperationTester(customEquals);
console.log(tester(15)); // true
console.log(tester(5));  // false

// Build complex query operation
const queryOp = createQueryOperation(
  { age: { $eq: 25 } },
  null,
  { 
    operations: { $eq },
    compare: (a, b) => a === b 
  }
);

const queryTester = createOperationTester(queryOp);
console.log(queryTester({ age: 25 })); // true

Utility Functions

Helper functions for comparison, type checking, and operation creation.

Create Tester

Creates a tester function from a value, function, or regular expression.

/**
 * Creates a tester function from a value, function, or regular expression
 * @param a - Value, function, or RegExp to create tester from
 * @param compare - Comparison function for value testing
 * @returns Tester function
 */
function createTester(a: any, compare: Comparator): Tester;

type Tester = (
  item: any,
  key?: Key,
  owner?: any,
  root?: boolean,
  leaf?: boolean
) => boolean;

Contains Operation

Checks if a query object contains operation keys.

/**
 * Checks if a query object contains operation keys
 * @param query - Query object to inspect
 * @param options - Options containing available operations
 * @returns True if query contains operations, false otherwise
 */
function containsOperation(query: any, options: Options): boolean;

Numerical Operation Creator

Higher-order function for creating numerical operations with type coercion.

/**
 * Creates numerical operations with automatic type coercion
 * @param createTester - Function that creates the test logic
 * @returns Operation creator function
 */
function numericalOperation(
  createTester: (value: any) => Tester
): OperationCreator<any>;

/**
 * Higher-order function for numerical operation creators
 * @param createNumericalOperation - Operation creator for numerical operations
 * @returns Wrapped operation creator
 */
function numericalOperationCreator(
  createNumericalOperation: OperationCreator<any>
): OperationCreator<any>;

Usage Examples:

import { 
  createTester, 
  containsOperation, 
  numericalOperation,
  $eq 
} from "sift";

// Create custom tester from function
const customTester = createTester(
  (value) => typeof value === "string" && value.length > 5,
  (a, b) => a === b
);

console.log(customTester("hello world")); // true
console.log(customTester("hi")); // false

// Check if query contains operations
const hasOps = containsOperation(
  { age: { $eq: 25 } },
  { operations: { $eq }, compare: (a, b) => a === b }
); // true

const noOps = containsOperation(
  { name: "Alice" },
  { operations: { $eq }, compare: (a, b) => a === b }
); // false

// Create custom numerical operation
const $between = numericalOperation((range) => (value) => {
  const [min, max] = range;
  return value >= min && value <= max;
});

// Use custom operation
const customQuery = createQueryTester(
  { score: [70, 90] }, // between 70 and 90
  { operations: { $between } }
);

Type Checking Utilities

Utility functions for type detection and value comparison.

Type Checker

Creates type checking functions for runtime type validation.

/**
 * Creates type checking functions for runtime validation
 * @param type - Type name to check for
 * @returns Type guard function
 */
function typeChecker<TType>(type: string): (value: any) => value is TType;

Comparison and Utility Functions

/**
 * Converts values to comparable form (handles Dates, arrays, toJSON)
 * @param value - Value to make comparable
 * @returns Comparable representation of value
 */
function comparable(value: any): any;

/**
 * Coerces potentially null values to null
 * @param value - Value to coerce
 * @returns Coerced value
 */
function coercePotentiallyNull(value: any): any;

/**
 * Deep equality comparison function
 * @param a - First value
 * @param b - Second value  
 * @returns True if values are deeply equal
 */
function equals(a: any, b: any): boolean;

/**
 * Type guard for arrays
 * @param value - Value to check
 * @returns True if value is an array
 */
function isArray(value: any): value is Array<any>;

/**
 * Type guard for objects
 * @param value - Value to check
 * @returns True if value is an object
 */
function isObject(value: any): value is Object;

/**
 * Type guard for functions
 * @param value - Value to check
 * @returns True if value is a function
 */
function isFunction(value: any): value is Function;

/**
 * Checks if key is a property (not a function) of an object
 * @param item - Object to check
 * @param key - Key to test
 * @returns True if key is a non-function property
 */
function isProperty(item: any, key: any): boolean;

/**
 * Checks if value is a plain object (not instance of custom class)
 * @param value - Value to check
 * @returns True if value is a vanilla object
 */
function isVanillaObject(value: any): boolean;

Usage Examples:

import { 
  typeChecker, 
  comparable, 
  equals, 
  isArray, 
  isVanillaObject 
} from "sift";

// Create type checkers
const isString = typeChecker<string>("String");
const isNumber = typeChecker<number>("Number");

console.log(isString("hello")); // true
console.log(isNumber(42)); // true
console.log(isString(42)); // false

// Value comparison
const date1 = new Date("2023-01-01");
const date2 = new Date("2023-01-01");

console.log(comparable(date1)); // timestamp number
console.log(equals(date1, date2)); // true (deep equality)

// Type checking
console.log(isArray([1, 2, 3])); // true
console.log(isVanillaObject({ a: 1 })); // true
console.log(isVanillaObject(new Date())); // false

// Custom comparison in operations
const customSift = createQueryTester(
  { created: new Date("2023-01-01") },
  {
    operations: { $eq },
    compare: (a, b) => {
      // Custom date comparison ignoring time
      if (a instanceof Date && b instanceof Date) {
        return a.toDateString() === b.toDateString();
      }
      return equals(a, b);
    }
  }
);

Custom Operation Development

Framework for developing custom query operations.

Base Operation Classes

/**
 * Base abstract class for all operations
 */
abstract class BaseOperation<TParams, TItem = any> implements Operation<TItem> {
  readonly keep: boolean;
  readonly done: boolean;
  abstract readonly propop: boolean;
  
  constructor(
    readonly params: TParams,
    readonly ownerQuery: any,
    readonly options: Options,
    readonly name?: string
  );
  
  protected init(): void;
  reset(): void;
  abstract next(
    item: any,
    key: Key,
    parent: any,
    root: boolean,
    leaf?: boolean
  ): void;
}

/**
 * Equals operation class for value matching
 */
class EqualsOperation<TParam> extends BaseOperation<TParam> {
  readonly propop = true;
  
  constructor(params: TParam, ownerQuery: any, options: Options);
  next(item: any, key: Key, parent: any): void;
}

/**
 * Query operation class for complex queries
 */
class QueryOperation<TItem> implements Operation<TItem> {
  readonly propop = true;
  readonly keep: boolean;
  readonly done: boolean;
  
  next(item: TItem, key: Key, parent: any, root: boolean): void;
  reset(): void;
}

Usage Examples:

import { BaseOperation, createQueryTester, Options, Query } from "sift";

// Custom operation example
class $startsWith extends BaseOperation<string> {
  readonly propop = true;
  private testValue: string;

  init() {
    this.testValue = this.params.toLowerCase();
  }

  next(item: any) {
    if (typeof item === "string") {
      if (item.toLowerCase().startsWith(this.testValue)) {
        this.done = true;
        this.keep = true;
      }
    }
  }
}

// Operation creator function
const createStartsWithOp = (
  params: string,
  ownerQuery: Query<any>,
  options: Options,
  name: string
) => new $startsWith(params, ownerQuery, options, name);

// Use custom operation
const customFilter = createQueryTester(
  { name: { $startsWith: "Al" } },
  { operations: { $startsWith: createStartsWithOp } }
);

const users = [
  { name: "Alice" },
  { name: "Bob" },
  { name: "Alexander" }
];

const filtered = users.filter(customFilter); 
// [{ name: "Alice" }, { name: "Alexander" }]

Error Handling

Sift operations can throw errors in specific circumstances:

  • $elemMatch: Throws Error if params is not an object
  • $and/$or/$nor: Throws Error if params is an empty array
  • $in operations: Throws Error if nested operations are used in $in/$nin values
  • $type: Throws Error if string type alias doesn't exist
  • $where: Throws Error in CSP mode when using string expressions
  • Unsupported operations: Throws Error for unknown $ operators

Error Handling Examples:

import sift from "sift";

try {
  // This will throw - empty array not allowed
  const filter = sift({ $and: [] });
} catch (error) {
  console.log(error.message); // "$and/$or/$nor must be a nonempty array"
}

try {
  // This will throw - malformed $elemMatch
  const filter = sift({ items: { $elemMatch: "invalid" } });
} catch (error) {
  console.log(error.message); // "Malformed query. $elemMatch must by an object."
}

try {
  // This will throw - unknown type alias
  const filter = sift({ field: { $type: "invalidtype" } });
} catch (error) {
  console.log(error.message); // "Type alias does not exist"
}

Install with Tessl CLI

npx tessl i tessl/npm-sift

docs

advanced-features.md

index.md

query-operators.md

tile.json