npm package: @feedmepos/mongoquery
Description: MongoDB query library for TypeScript with CJS and ESM support
Author: FeedMe POS
Latest version: 1.0.0

# @feedmepos/mongoquery

MongoDB query library for TypeScript with CJS and ESM support.

## Installation

```bash
pnpm add @feedmepos/mongoquery
# or
npm install @feedmepos/mongoquery
# or
yarn add @feedmepos/mongoquery
```

## Features

- 🎯 Full TypeScript support with type definitions
- 📦 Multiple module formats: CJS and ESM
- 🔍 MongoDB query parsing and validation
- 🔗 Fluent query builder with method chaining
- ⚡ Query evaluation against JSON documents
- 🛡️ Type-safe query operations
- 🪶 Lightweight with no dependencies
- ⚡ Built with tsup for optimal bundle size

## Usage

### Query Runner

The query runner evaluates MongoDB queries against JSON documents and returns true or false.

```typescript
import { MongoQueryRunner, createRunner } from '@feedmepos/mongoquery';

const document = {
  name: 'John Doe',
  age: 25,
  email: 'john@example.com',
  status: 'active',
  tags: ['javascript', 'typescript']
};

// Using the class
const runner = new MongoQueryRunner();

// Simple equality
const matches1 = runner.evaluate({ status: 'active' }, document); // true

// Comparison operators
const matches2 = runner.evaluate({ age: { $gte: 18 } }, document); // true

// Complex query
const matches3 = runner.evaluate({
  status: 'active',
  age: { $gte: 18, $lte: 30 },
  email: { $exists: true }
}, document); // true

// Using the factory function
const strictRunner = createRunner({ strict: true });
const matches4 = strictRunner.evaluate({ age: { $gt: 20 } }, document); // true
```

### Query Builder (Fluent API)

The query builder provides a fluent API for constructing MongoDB queries with method chaining.

```typescript
import { MongoQueryBuilder, createBuilder } from '@feedmepos/mongoquery';

// Using the class
const builder = new MongoQueryBuilder();
const query = builder
  .gte('age', 18)
  .lte('age', 65)
  .in('status', ['active', 'pending'])
  .exists('email', true)
  .build();

// Using the factory function
const query2 = createBuilder()
  .where('name', 'John')
  .gt('score', 80)
  .build();
```

### Query Parser

The parser validates and processes MongoDB query objects.

```typescript
import { MongoQueryParser, createParser } from '@feedmepos/mongoquery';

// Using the class
const parser = new MongoQueryParser();
const query = parser.parse({ age: { $gt: 18 } });

// Using the factory function
const strictParser = createParser({ strict: true });
const validatedQuery = strictParser.parse({ name: { $eq: 'John' } });
```

### ES Modules (ESM)

```typescript
import { MongoQueryBuilder, MongoQueryParser } from '@feedmepos/mongoquery';

const builder = new MongoQueryBuilder();
const query = builder.gte('age', 18).build();

const parser = new MongoQueryParser();
const parsedQuery = parser.parse(query);
```

### CommonJS (CJS)

```javascript
const { MongoQueryBuilder, MongoQueryParser } = require('@feedmepos/mongoquery');

const builder = new MongoQueryBuilder();
const query = builder.gte('age', 21).build();
```

## API

### MongoQueryRunner

The query runner for evaluating MongoDB queries against JSON documents.

#### Constructor

```typescript
new MongoQueryRunner(options?: ParserOptions)
```

**Options:**
- `strict` (boolean): Enable strict operator validation. Default: `false`

#### Methods

##### evaluate(query: MongoQuery, document: any): boolean

Evaluates a MongoDB query against a document and returns true if the document matches the query.

```typescript
const runner = new MongoQueryRunner();
const document = { name: 'John', age: 25, status: 'active' };

// Simple equality
const result1 = runner.evaluate({ status: 'active' }, document); // true

// Complex query
const result2 = runner.evaluate({
  age: { $gte: 18 },
  status: { $in: ['active', 'pending'] }
}, document); // true
```

#### Supported Operations

The runner supports all standard MongoDB query operators:

**Comparison Operators:** `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`

**Logical Operators:** `$and`, `$or`, `$not`, `$nor`

**Element Operators:** `$exists`, `$type`

**Array Operators:** `$all`, `$elemMatch`, `$size`

**Evaluation Operators:** `$regex`, `$mod`

**Nested Fields:** Supports dot notation (e.g., `address.city`)

### createRunner(options?: ParserOptions): MongoQueryRunner

Factory function to create a runner instance.

```typescript
const runner = createRunner({ strict: true });
const matches = runner.evaluate({ age: { $gt: 18 } }, { age: 25 }); // true
```

### MongoQueryBuilder

The fluent query builder for constructing MongoDB queries using method chaining.

#### Constructor

```typescript
new MongoQueryBuilder()
```

#### Methods

All methods return `this` for method chaining, except `build()` which returns the final query.

##### Basic Methods

- **`where(field: string, value: any): this`** - Set a field to a specific value
- **`build(): MongoQuery`** - Build and return the final query object
- **`reset(): this`** - Reset the builder to start a new query

##### Comparison Operators

- **`eq(field: string, value: any): this`** - Equal to ($eq)
- **`ne(field: string, value: any): this`** - Not equal to ($ne)
- **`gt(field: string, value: number | string | Date): this`** - Greater than ($gt)
- **`gte(field: string, value: number | string | Date): this`** - Greater than or equal ($gte)
- **`lt(field: string, value: number | string | Date): this`** - Less than ($lt)
- **`lte(field: string, value: number | string | Date): this`** - Less than or equal ($lte)
- **`in(field: string, values: any[]): this`** - In array ($in)
- **`nin(field: string, values: any[]): this`** - Not in array ($nin)

##### Logical Operators

- **`and(...conditions: MongoQuery[]): this`** - Logical AND ($and)
- **`or(...conditions: MongoQuery[]): this`** - Logical OR ($or)
- **`nor(...conditions: MongoQuery[]): this`** - Logical NOR ($nor)
- **`not(field: string, condition: any): this`** - Logical NOT ($not)

##### Element Operators

- **`exists(field: string, exists?: boolean): this`** - Field exists ($exists)
- **`type(field: string, type: number | string): this`** - Field type ($type)

##### Evaluation Operators

- **`regex(field: string, pattern: string | RegExp, options?: string): this`** - Regular expression ($regex)
- **`mod(field: string, divisor: number, remainder: number): this`** - Modulo operation ($mod)
- **`text(search: string, options?: object): this`** - Text search ($text)
- **`where_js(code: string | Function): this`** - JavaScript expression ($where)

##### Array Operators

- **`all(field: string, values: any[]): this`** - All elements match ($all)
- **`elemMatch(field: string, condition: MongoQuery): this`** - Element match ($elemMatch)
- **`size(field: string, size: number): this`** - Array size ($size)

#### Example Usage

```typescript
import { MongoQueryBuilder } from '@feedmepos/mongoquery';

const query = new MongoQueryBuilder()
  .gte('age', 18)
  .lte('age', 65)
  .in('status', ['active', 'pending'])
  .exists('email', true)
  .regex('name', '^John', 'i')
  .build();

console.log(query);
// {
//   age: { $gte: 18, $lte: 65 },
//   status: { $in: ['active', 'pending'] },
//   email: { $exists: true },
//   name: { $regex: '^John', $options: 'i' }
// }
```

### createBuilder(): MongoQueryBuilder

Factory function to create a new query builder instance.

```typescript
import { createBuilder } from '@feedmepos/mongoquery';

const query = createBuilder()
  .where('category', 'electronics')
  .gt('price', 100)
  .build();
```

### MongoQueryParser

The main query parser class.

#### Constructor

```typescript
new MongoQueryParser(options?: ParserOptions)
```

**Options:**
- `strict` (boolean): Enable strict operator validation. Default: `false`

#### Methods

##### parse(query: MongoQuery): MongoQuery

Parses and validates a MongoDB query.

```typescript
const parser = new MongoQueryParser();
const query = parser.parse({
  age: { $gte: 18, $lt: 65 },
  status: 'active'
});
```

##### isValid(query: MongoQuery): boolean

Checks if a query is valid without throwing errors.

```typescript
const parser = new MongoQueryParser();
const isValid = parser.isValid({ age: { $gt: 18 } }); // true
```

### createParser(options?: ParserOptions): MongoQueryParser

Factory function to create a parser instance.

```typescript
const parser = createParser({ strict: true });
```

## Supported Operators

### Comparison Operators
- `$eq` - Equal to
- `$ne` - Not equal to
- `$gt` - Greater than
- `$gte` - Greater than or equal to
- `$lt` - Less than
- `$lte` - Less than or equal to
- `$in` - In array
- `$nin` - Not in array

### Logical Operators
- `$and` - Logical AND
- `$or` - Logical OR
- `$not` - Logical NOT
- `$nor` - Logical NOR

### Element Operators
- `$exists` - Field exists
- `$type` - Field type

### Evaluation Operators
- `$regex` - Regular expression
- `$mod` - Modulo operation
- `$text` - Text search
- `$where` - JavaScript expression

### Array Operators
- `$all` - All elements match
- `$elemMatch` - Element match
- `$size` - Array size

## TypeScript Types

The package exports the following TypeScript types:

```typescript
import type {
  MongoQuery,
  ParserOptions,
  MongoOperator,
  ComparisonOperator,
  LogicalOperator,
  ElementOperator,
  EvaluationOperator,
  ArrayOperator,
  FieldCondition
} from '@feedmepos/mongoquery';
```

## Examples

### Query Runner Examples

#### Basic Matching

```typescript
import { MongoQueryRunner } from '@feedmepos/mongoquery';

const runner = new MongoQueryRunner();
const user = {
  name: 'John Doe',
  age: 25,
  status: 'active'
};

// Equality
runner.evaluate({ status: 'active' }, user); // true
runner.evaluate({ status: 'inactive' }, user); // false

// Comparison
runner.evaluate({ age: { $gte: 18 } }, user); // true
runner.evaluate({ age: { $lt: 20 } }, user); // false

// Multiple conditions (implicit AND)
runner.evaluate({ 
  status: 'active', 
  age: { $gte: 18 } 
}, user); // true
```

#### Logical Operators

```typescript
const runner = new MongoQueryRunner();
const user = { age: 25, status: 'active' };

// OR condition
runner.evaluate({
  $or: [
    { age: { $lt: 18 } },
    { status: 'inactive' }
  ]
}, user); // false

runner.evaluate({
  $or: [
    { age: { $gte: 18 } },
    { status: 'inactive' }
  ]
}, user); // true

// AND condition
runner.evaluate({
  $and: [
    { age: { $gte: 18 } },
    { status: 'active' }
  ]
}, user); // true
```

#### Array Operations

```typescript
const runner = new MongoQueryRunner();
const user = {
  name: 'John',
  tags: ['javascript', 'typescript', 'nodejs']
};

// Check if field contains any of the values
runner.evaluate({ tags: { $in: ['javascript', 'python'] } }, user); // true

// Check if field contains all values
runner.evaluate({ tags: { $all: ['javascript', 'typescript'] } }, user); // true
runner.evaluate({ tags: { $all: ['javascript', 'python'] } }, user); // false

// Check array size
runner.evaluate({ tags: { $size: 3 } }, user); // true
runner.evaluate({ tags: { $size: 2 } }, user); // false

// Element match on array of objects
const product = {
  reviews: [
    { rating: 5, comment: 'Great!' },
    { rating: 4, comment: 'Good' }
  ]
};

runner.evaluate({
  reviews: { $elemMatch: { rating: { $gte: 4 } } }
}, product); // true
```

#### Nested Fields

```typescript
const runner = new MongoQueryRunner();
const user = {
  name: 'John',
  address: {
    city: 'New York',
    country: 'USA'
  }
};

// Dot notation for nested fields
runner.evaluate({ 'address.city': 'New York' }, user); // true
runner.evaluate({ 'address.country': 'UK' }, user); // false
```

#### Regular Expressions

```typescript
const runner = new MongoQueryRunner();
const user = { name: 'John Doe', email: 'john@example.com' };

// Pattern matching
runner.evaluate({ name: { $regex: '^John' } }, user); // true
runner.evaluate({ email: { $regex: '@example\\.com$' } }, user); // true
```

#### Combining Builder and Runner

```typescript
import { MongoQueryBuilder, MongoQueryRunner } from '@feedmepos/mongoquery';

// Build a query
const query = new MongoQueryBuilder()
  .gte('age', 18)
  .lte('age', 65)
  .in('status', ['active', 'pending'])
  .exists('email', true)
  .build();

// Evaluate against documents
const runner = new MongoQueryRunner();
const users = [
  { name: 'John', age: 25, status: 'active', email: 'john@example.com' },
  { name: 'Jane', age: 17, status: 'active', email: 'jane@example.com' },
  { name: 'Bob', age: 35, status: 'inactive' }
];

const matchingUsers = users.filter(user => runner.evaluate(query, user));
// Result: [{ name: 'John', age: 25, status: 'active', email: 'john@example.com' }]
```

### Query Builder Examples

#### Basic Queries

```typescript
import { MongoQueryBuilder } from '@feedmepos/mongoquery';

// Simple field matching
const query1 = new MongoQueryBuilder()
  .where('name', 'John')
  .where('age', 25)
  .build();
// Result: { name: 'John', age: 25 }

// Range queries
const query2 = new MongoQueryBuilder()
  .gte('age', 18)
  .lte('age', 65)
  .build();
// Result: { age: { $gte: 18, $lte: 65 } }
```

#### Logical Operators

```typescript
import { createBuilder } from '@feedmepos/mongoquery';

// OR conditions
const query = createBuilder()
  .or(
    { age: { $lt: 18 } },
    { status: 'inactive' }
  )
  .build();
// Result: { $or: [{ age: { $lt: 18 } }, { status: 'inactive' }] }

// AND conditions
const query2 = createBuilder()
  .and(
    { age: { $gte: 18 } },
    { status: 'active' }
  )
  .build();
// Result: { $and: [{ age: { $gte: 18 } }, { status: 'active' }] }
```

#### Array Operators

```typescript
import { createBuilder } from '@feedmepos/mongoquery';

const query = createBuilder()
  .in('status', ['active', 'pending'])
  .nin('role', ['admin'])
  .size('tags', 3)
  .build();
// Result: { 
//   status: { $in: ['active', 'pending'] },
//   role: { $nin: ['admin'] },
//   tags: { $size: 3 }
// }
```

#### Complex Query

```typescript
import { MongoQueryBuilder } from '@feedmepos/mongoquery';

const query = new MongoQueryBuilder()
  .gte('age', 18)
  .lte('age', 65)
  .in('department', ['sales', 'marketing'])
  .exists('email', true)
  .ne('status', 'inactive')
  .regex('name', '^John', 'i')
  .build();
// Result: {
//   age: { $gte: 18, $lte: 65 },
//   department: { $in: ['sales', 'marketing'] },
//   email: { $exists: true },
//   status: { $ne: 'inactive' },
//   name: { $regex: '^John', $options: 'i' }
// }
```

#### Builder Reuse

```typescript
import { createBuilder } from '@feedmepos/mongoquery';

const builder = createBuilder();

// First query
const query1 = builder
  .where('category', 'electronics')
  .gte('price', 100)
  .build();

// Reset and build a different query
const query2 = builder
  .reset()
  .where('category', 'books')
  .lte('price', 50)
  .build();
```

### Parser Examples

#### Basic Query

```typescript
import { MongoQueryParser } from '@feedmepos/mongoquery';

const parser = new MongoQueryParser();
const query = parser.parse({
  name: 'John',
  age: { $gte: 18 }
});
```

#### Complex Query

```typescript
import { createParser } from '@feedmepos/mongoquery';

const parser = createParser();
const query = parser.parse({
  $and: [
    { age: { $gte: 18 } },
    { status: { $in: ['active', 'pending'] } }
  ]
});
```

#### Strict Mode

```typescript
import { MongoQueryParser } from '@feedmepos/mongoquery';

const parser = new MongoQueryParser({ strict: true });

// This will throw an error for unknown operators
try {
  parser.parse({ field: { $unknownOp: 'value' } });
} catch (error) {
  console.error(error.message); // "Unknown operator: $unknownOp"
}
```

## Building

```bash
pnpm run build
```

This will generate:
- `dist/index.js` - CommonJS module
- `dist/index.mjs` - ES module
- `dist/index.d.ts` - TypeScript type definitions (CJS)
- `dist/index.d.mts` - TypeScript type definitions (ESM)

## Development

This package uses:
- **pnpm** as the package manager
- **tsup** for building and bundling
- **TypeScript** for type safety

## License

MIT