GitHunt
LJ

ljlm0402/object-querybuilder

🧩 Obejct Query Builder


Project Logo

Object Query Builder

🧩 A powerful, type-safe SQL-like query builder for JavaScript objects

npm Info

npm Version npm Release Version npm Downloads npm Package License

github Stars github Forks github Contributors github Issues

Β· English Β· Korean


✨ Features

  • 🎨 Fluent API - Chainable methods for readable queries
  • 🎯 SQL-like Syntax - Familiar query syntax for filtering, sorting, and joining
  • πŸ”§ Extensible - Easy to add custom functionality
  • πŸ”’ Type-Safe - Full TypeScript support with generics
  • ⚑ High Performance - Optimized algorithms (O(n) joins with Map)
  • πŸ“¦ Zero Dependencies - Pure TypeScript, no external dependencies
  • πŸš€ Modern Build - Dual CJS/ESM support with tsup

πŸš€ Installation

npm install object-querybuilder

yarn add object-querybuilder

pnpm add object-querybuilder

πŸ“– Quick Start

TypeScript

import QueryBuilder from 'object-querybuilder';

interface User {
    name: string;
    age: number;
    gender: string;
}

const users: User[] = [
    { name: 'Lucy', age: 23, gender: 'woman' },
    { name: 'Emma', age: 31, gender: 'woman' },
    { name: 'Daniel', age: 18, gender: 'man' },
    { name: 'Olivia', age: 42, gender: 'woman' },
    { name: 'Alex', age: 33, gender: 'man' }
];

const result = QueryBuilder.create<User>()
    .select(['name', 'age'])
    .from(users)
    .where('age', '>', 25)
    .where('gender', '=', 'woman')
    .orderBy('age', 'desc')
    .run();

console.log(result);
// Output: [
//   { name: 'Olivia', age: 42 },
//   { name: 'Emma', age: 31 }
// ]

JavaScript (CommonJS)

const QueryBuilder = require('object-querybuilder').default;

const users = [
    { name: 'Lucy', age: 23, gender: 'woman' },
    { name: 'Emma', age: 31, gender: 'woman' }
];

const result = QueryBuilder.create()
    .select(['*'])
    .from(users)
    .where('age', '>', 25)
    .run();

JavaScript (ESM)

import QueryBuilder from 'object-querybuilder';

const result = QueryBuilder.create()
    .select(['name', 'age'])
    .from(users)
    .orderBy('age', 'asc')
    .limit(5)
    .run();

πŸ“š API Reference

Core Query Methods

Method Description Example
select(fields) Specify fields to return (['*'] for all) .select(['name', 'age'])
from(data) Set data source (array or single object) .from(users)
where(key, op, value) Filter by condition .where('age', '>', 25)
whereIn(key, values) Filter by array inclusion .whereIn('status', ['active', 'pending'])
whereNotIn(key, values) Filter by array exclusion .whereNotIn('role', ['admin'])
orderBy(key, order) Sort results (asc/desc) .orderBy('age', 'desc')
orderByMultiple(criteria) Sort by multiple fields .orderByMultiple([{key: 'dept', order: 'asc'}])
limit(count) Limit number of results .limit(10)
offset(count) Skip number of results .offset(20)
distinct() Remove duplicates .distinct()
run() Execute query and return results .run()

Join Methods

Method Description Example
join(data, key) Inner join on common key .join(addresses, 'userId')
leftJoin(data, key) Left outer join .leftJoin(addresses, 'userId')

Aggregation Methods

Method Description Example
count() Count results .count()
aggregate(func, key) Apply function (sum, avg, min, max) .aggregate('sum', 'salary')
groupBy(key) Group results by field .groupBy('department')
first() Get first result .first()
last() Get last result .last()

Utility Methods

Method Description Example
clone() Create independent copy .clone()

Supported Operators

Operator Description Example
> Greater than .where('age', '>', 25)
< Less than .where('price', '<', 100)
>= Greater than or equal .where('score', '>=', 90)
<= Less than or equal .where('stock', '<=', 10)
= Equal .where('status', '=', 'active')
!= Not equal .where('type', '!=', 'draft')
like Pattern matching (%, _) .where('email', 'like', '%@gmail.com')

πŸ’‘ Examples

Basic Filtering

// Single condition
QueryBuilder.create()
    .select(['*'])
    .from(products)
    .where('price', '<', 100)
    .run();

// Multiple conditions (chained)
QueryBuilder.create()
    .select(['*'])
    .from(users)
    .where('age', '>=', 18)
    .where('status', '=', 'active')
    .whereIn('role', ['user', 'moderator'])
    .run();

Pattern Matching

// Find emails from Gmail
QueryBuilder.create()
    .from(users)
    .where('email', 'like', '%@gmail.com')
    .run();

// Find names starting with 'A'
QueryBuilder.create()
    .from(users)
    .where('name', 'like', 'A%')
    .run();

// Find names containing 'son'
QueryBuilder.create()
    .from(users)
    .where('name', 'like', '%son%')
    .run();

Joining Data

const users = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
];

const orders = [
    { userId: 1, product: 'Laptop', amount: 1200 },
    { userId: 1, product: 'Mouse', amount: 25 },
    { userId: 2, product: 'Keyboard', amount: 75 }
];

// Inner join (only matching records)
const result = QueryBuilder.create()
    .from(users)
    .join(orders, 'userId')
    .run();

// Left join (all users, even without orders)
const result = QueryBuilder.create()
    .from(users)
    .leftJoin(orders, 'userId')
    .run();

Pagination

const PAGE_SIZE = 10;
const currentPage = 3;

const result = QueryBuilder.create()
    .select(['*'])
    .from(items)
    .orderBy('createdAt', 'desc')
    .limit(PAGE_SIZE)
    .offset((currentPage - 1) * PAGE_SIZE)
    .run();

Aggregation & Analytics

const sales = [
    { product: 'Laptop', price: 1200, quantity: 5 },
    { product: 'Mouse', price: 25, quantity: 50 },
    { product: 'Keyboard', price: 75, quantity: 20 }
];

// Total revenue
const total = QueryBuilder.create()
    .from(sales)
    .aggregate('sum', 'price');
// Result: 1300

// Average price
const avg = QueryBuilder.create()
    .from(sales)
    .aggregate('avg', 'price');
// Result: 433.33

// Most expensive item
const max = QueryBuilder.create()
    .from(sales)
    .aggregate('max', 'price');
// Result: 1200

// Group by and count
const grouped = QueryBuilder.create()
    .from(orders)
    .groupBy('status');
// Result: { 'pending': [...], 'completed': [...], 'cancelled': [...] }

Sorting

// Single field
QueryBuilder.create()
    .from(products)
    .orderBy('price', 'desc')
    .run();

// Multiple fields
QueryBuilder.create()
    .from(employees)
    .orderByMultiple([
        { key: 'department', order: 'asc' },
        { key: 'salary', order: 'desc' },
        { key: 'name', order: 'asc' }
    ])
    .run();

Advanced Use Cases

// Find top 5 most expensive products in Electronics
QueryBuilder.create()
    .select(['name', 'price', 'rating'])
    .from(products)
    .where('category', '=', 'Electronics')
    .where('inStock', '=', true)
    .orderBy('price', 'desc')
    .limit(5)
    .run();

// Get unique active users who made purchases
QueryBuilder.create()
    .select(['userId', 'username'])
    .from(transactions)
    .where('status', '=', 'completed')
    .whereIn('userId', activeUserIds)
    .distinct()
    .run();

// Reusable query with cloning
const baseQuery = QueryBuilder.create()
    .from(users)
    .where('status', '=', 'active');

const adults = baseQuery.clone()
    .where('age', '>=', 18)
    .run();

const minors = baseQuery.clone()
    .where('age', '<', 18)
    .run();

🎯 Use Cases

  • Frontend Data Filtering - Filter API responses in browser
  • Testing - Mock database queries without actual DB
  • Data Processing - Transform and analyze in-memory data
  • Prototyping - Quick data manipulation without backend
  • Report Generation - Aggregate and summarize data
  • ETL Operations - Extract, transform, load data pipelines

🀝 Contributing

Contributions are always welcome! Please feel free to open an issue or submit a pull request.

πŸ’³ License

MIT


Made with ❀️ by AGUMON πŸ¦–

ljlm0402/object-querybuilder | GitHunt