Create/Parse query parameter for optimus/bruno php
npm install bruno-query


A TypeScript library for building and parsing query parameters, designed for Bruno PHP library.
- ✅ Dynamic Optional Parameters - Support single objects and arrays with custom keys
- ✅ Multiple Build Formats - TypeScript, ES Modules, and CommonJS
- ✅ Type Safety - Full TypeScript support with interfaces and enums
- ✅ Flexible Query Building - Includes, sorting, filtering, pagination
- ✅ URL Generation - Convert queries to URL strings
- ✅ Query Parsing - Parse existing query strings back to objects
``bash`
npm install bruno-query
`typescript
import { BrunoQuery, SortDirection, QueryOperator } from 'bruno-query';
// Create a query
const query = new BrunoQuery()
.addIncludes('author', 'publisher')
.addSort({ key: 'name', direction: SortDirection.ASC })
.setLimit(20)
.setPage(1)
.setOptional({
category: 'books',
status: 'active'
});
// Get query string
const queryString = query.toQueryString();
// Result: "includes[]=author&includes[]=publisher&sort[0][key]=name&sort[0][direction]=ASC&limit=20&page=1&category=books&status=active"
// Get URL
const url = query.toURL('https://api.example.com/books');
// Result: "https://api.example.com/books?includes[]=author&includes[]=publisher&sort[0][key]=name&sort[0][direction]=ASC&limit=20&page=1&category=books&status=active"
`
`typescript
import { BrunoQuery } from 'bruno-query';
const query = new BrunoQuery()
.addIncludes('author')
.setLimit(10)
.setPage(1);
console.log(query.toQueryString());
// "includes[]=author&limit=10&page=1"
`
`typescript
import { BrunoQuery, QueryOperator } from 'bruno-query';
const query = new BrunoQuery()
.addFilterGroup({
or: false,
filters: [
{ key: 'category', operator: QueryOperator.equals, value: 'books' },
{ key: 'status', operator: QueryOperator.equals, value: 'active' }
]
})
.addSort({ key: 'created_at', direction: 'DESC' })
.setOptional({
filters: {
category: 'books',
status: 'active'
},
options: {
includeDeleted: false
}
});
console.log(query.toQueryString());
`
`typescript
import { BrunoQuery } from 'bruno-query';
const queryString = "includes[]=author&sort[0][key]=name&limit=20&category=books";
const query = BrunoQuery.fromQueryString(queryString);
console.log(query.toObject());
// {
// includes: ['author'],
// sort: [{ key: 'name', direction: 'ASC' }],
// limit: 20,
// page: 1,
// filter_groups: [],
// optional: { category: 'books' }
// }
`
`typescript
import { BrunoQuery } from 'bruno-query';
const query = new BrunoQuery()
.addIncludes('user', 'posts')
.addSort({ key: 'name', direction: 'ASC' })
.setLimit(10)
.setOptional({ custom_param: 'value', another_param: 123 });
// Convert to JSON string (optional parameters are flattened)
const jsonString = query.toJSON();
console.log(jsonString);
// {"includes":["user","posts"],"sort":[{"key":"name","direction":"ASC"}],"limit":10,"custom_param":"value","another_param":123}
// Parse JSON back to BrunoQuery (non-core parameters moved to optional)
const parsedQuery = BrunoQuery.fromJSON(jsonString);
console.log(parsedQuery.toObject());
// {
// includes: ['user', 'posts'],
// sort: [{ key: 'name', direction: 'ASC' }],
// limit: 10,
// optional: { custom_param: 'value', another_param: 123 }
// }
console.log(parsedQuery.toQueryString());
// includes[]=user&includes[]=posts&sort[0][key]=name&sort[0][direction]=ASC&limit=10&custom_param=value&another_param=123
`
Note: JSON serialization flattens optional parameters to the root level, ensuring consistency between JSON and query string representations.
BrunoQuery automatically removes duplicate filters within the same filter group based on the key-value-operator-not combination. This ensures clean and efficient query strings without redundant filters.
`typescript
import { BrunoQuery, QueryOperator } from 'bruno-query';
const query = new BrunoQuery()
.addFilterGroup({
or: false,
filters: [
{ key: 'name', value: 'John', operator: QueryOperator.contains },
{ key: 'name', value: 'John', operator: QueryOperator.contains }, // Duplicate - will be removed
{ key: 'age', value: 25, operator: QueryOperator.equals },
{ key: 'name', value: 'John', operator: QueryOperator.contains }, // Another duplicate - will be removed
{ key: 'status', value: 'active', operator: QueryOperator.equals }
]
});
console.log(query.toObject().filter_groups[0].filters.length);
// 3 (duplicates removed)
console.log(query.toQueryString());
// filter_groups[0][filters][0][key]=name&filter_groups[0][filters][0][value]=John&filter_groups[0][filters][0][operator]=ct&filter_groups[0][filters][1][key]=age&filter_groups[0][filters][1][value]=25&filter_groups[0][filters][1][operator]=eq&filter_groups[0][filters][2][key]=status&filter_groups[0][filters][2][value]=active&filter_groups[0][filters][2][operator]=eq
`
Note: Deduplication only applies within the same filter group. Different filter groups can have the same filters, and filters with different values, operators, or not values are not considered duplicates.
- addIncludes(...includes: string[]) - Add related resources to loadaddArrayIncludes(includes: string[])
- - Add includes from arraysetIncludes(...includes: string[])
- - Replace includessetArrayIncludes(includes: string[])
- - Replace includes from arrayaddSort(...sort: SortRule[])
- - Add sorting rulesaddArraySort(sort: SortRule[])
- - Add sorting rules from arraysetSort(...sort: SortRule[])
- - Replace sorting rulessetArraySort(sort: SortRule[])
- - Replace sorting rules from arrayaddFilterGroup(...groups: FilterGroup[])
- - Add filter groups (with automatic deduplication)addArrayFilterGroup(groups: FilterGroup[])
- - Add filter groups from array (with automatic deduplication)setFilterGroup(...groups: FilterGroup[])
- - Replace filter groups (with automatic deduplication)setArrayFilterGroup(groups: FilterGroup[])
- - Replace filter groups from array (with automatic deduplication)setLimit(limit: number)
- - Set result limitsetPage(page: number)
- - Set page numbersetOptional(optional: Record
- - Set optional parametersaddOptional(optional: Record
- - Add/merge optional parametersreset()
- - Reset all parameters to defaults
- toQueryString() - Get query stringget()
- - Alias of toQueryString()toURL(baseUrl?: string)
- - Get full URLtoObject()
- - Get object representationtoJSON()
- - Get JSON string representationclone()
- - Create a copy of the query
- BrunoQuery.fromQueryString(queryString: string) - Parse query stringBrunoQuery.fromJSON(jsonString: string)
- - Parse JSON stringBrunoQuery.parse(queryString: string)
- - Alias of fromQueryStringBrunoQuery.build(...)
- - Build query with parameters
The library is built into 3 formats: cjs, mjs, d.ts
`bashBuild all formats
npm run build