@microfox/rag-upstash
v1.2.0
Published
A TypeScript SDK for Rag Upstash.
Readme
RAG Upstash SDK
A TypeScript SDK for working with Upstash Vector for RAG (Retrieval-Augmented Generation) applications.
Features
- Type-safe filter system with support for nested objects and complex queries
- Multiple filter syntaxes: String-based (legacy) and object-based (new)
- Comprehensive operator support: All Upstash Vector filter operators
- Validation: Built-in Zod schema validation for filters
- Builder pattern: Fluent API for building complex filters
Installation
npm install rag-upstashQuick Start
import { RagUpstashSdk, createFilter, FilterHelpers } from 'rag-upstash';
// Initialize the SDK
const sdk = new RagUpstashSdk({
upstashUrl: process.env.UPSTASH_VECTOR_REST_URL!,
upstashToken: process.env.UPSTASH_VECTOR_REST_TOKEN!,
});
// Query with simple string filter (legacy way)
const result1 = await sdk.queryDocsFromRAG({
data: 'Find cities in Turkey',
topK: 5,
filter: "country = 'Turkey' AND population > 1000000",
});
// Query with object filter (new way)
const result2 = await sdk.queryDocsFromRAG({
data: 'Find cities in Turkey',
topK: 5,
filter: createFilter()
.eq('country', 'Turkey')
.gt('population', 1000000)
.build(),
});Filter System
The SDK supports both string-based filters (legacy) and object-based filters (new). The object-based system provides type safety and better developer experience.
Filter Types
// Simple condition
interface FilterCondition {
field: string;
operator: FilterOperator;
value: FilterValue;
}
// Compound filter with boolean operators
interface CompoundFilter {
operator: 'AND' | 'OR';
filters: (FilterCondition | CompoundFilter)[];
}
// Union type for all filters
type Filter = FilterCondition | CompoundFilter | string;Supported Operators
| Operator | Description | Example |
| --------------- | --------------------- | -------------------------------------- |
| = | Equals | eq('country', 'Turkey') |
| != | Not equals | ne('country', 'Germany') |
| < | Less than | lt('population', 1000000) |
| <= | Less than or equal | lte('population', 1000000) |
| > | Greater than | gt('population', 1000000) |
| >= | Greater than or equal | gte('population', 1000000) |
| GLOB | Pattern matching | glob('city', 'I*bul') |
| NOT GLOB | Not pattern matching | notGlob('city', 'A*') |
| IN | In array | in('country', ['Turkey', 'Germany']) |
| NOT IN | Not in array | notIn('currency', ['USD', 'EUR']) |
| CONTAINS | Array contains | contains('industries', 'Tourism') |
| NOT CONTAINS | Array not contains | notContains('industries', 'Steel') |
| HAS FIELD | Field exists | hasField('coordinates') |
| HAS NOT FIELD | Field doesn't exist | hasNotField('coordinates') |
Creating Filters
1. Using Filter Builder (Recommended)
import { createFilter } from 'rag-upstash';
const filter = createFilter()
.eq('country', 'Turkey')
.gt('population', 1000000)
.contains('industries', 'Tourism')
.build();
// Or chain with boolean operators
const complexFilter = createFilter()
.eq('continent', 'Europe')
.gt('population', 5000000)
.or(); // Combines all conditions with OR
const andFilter = createFilter()
.eq('country', 'Germany')
.lt('population', 10000000)
.and(); // Combines all conditions with AND2. Using Filter Helpers
import { FilterHelpers } from 'rag-upstash';
const filter = FilterHelpers.and(
FilterHelpers.eq('country', 'Turkey'),
FilterHelpers.gt('population', 1000000),
FilterHelpers.or(
FilterHelpers.eq('is_capital', true),
FilterHelpers.contains('industries', 'Tourism')
)
);3. Direct Object Creation
const filter: FilterCondition = {
field: 'country',
operator: '=',
value: 'Turkey',
};
const compoundFilter: CompoundFilter = {
operator: 'AND',
filters: [
{ field: 'country', operator: '=', value: 'Turkey' },
{ field: 'population', operator: '>', value: 1000000 },
],
};Nested Object Support
The filter system supports nested objects using dot notation:
const filter = createFilter()
.eq('geography.continent', 'Asia')
.gte('geography.coordinates.latitude', 35.0)
.lt('geography.coordinates.longitude', 30.0)
.build();Array Support
Array Elements
const filter = createFilter()
.eq('industries[0]', 'Tourism') // First element
.eq('industries[#-1]', 'Finance') // Last element
.contains('industries', 'Technology') // Array contains
.notContains('industries', 'Steel') // Array not contains
.build();Array Operators
const filter = createFilter()
.in('country', ['Turkey', 'Germany', 'France'])
.notIn('currency', ['USD', 'EUR'])
.build();String Pattern Matching
const filter = createFilter()
.glob('city', 'I*bul') // Cities starting with 'I' and ending with 'bul'
.glob('city', '?[sz]*') // Cities with second character 's' or 'z'
.notGlob('city', 'A*') // Cities not starting with 'A'
.build();Field Existence
const filter = createFilter()
.hasField('geography.coordinates') // Field exists
.hasNotField('geography.coordinates.longitude') // Field doesn't exist
.build();Complex Boolean Combinations
const filter = FilterHelpers.and(
FilterHelpers.eq('geography.continent', 'Europe'),
FilterHelpers.or(
FilterHelpers.gt('population', 5000000),
FilterHelpers.eq('is_capital', true)
),
FilterHelpers.notIn('economy.currency', ['USD', 'EUR']),
FilterHelpers.contains('economy.major_industries', 'Finance')
);Validation
The filter system includes built-in validation:
import { validateFilter } from 'rag-upstash';
try {
const filter = createFilter()
.eq('invalid-field-name!', 'value') // Invalid field name
.build();
const validatedFilter = validateFilter(filter);
} catch (error) {
console.error('Validation error:', error.message);
}Debugging
Convert filters to strings for debugging:
const filter = createFilter()
.eq('country', 'Turkey')
.gt('population', 1000000)
.build();
const filterString = filter.toString();
console.log('Generated filter:', filterString);
// Output: "country = 'Turkey' AND population > 1000000"Complete Example
import { RagUpstashSdk, createFilter } from 'rag-upstash';
interface CityMetadata {
city: string;
country: string;
is_capital: boolean;
population: number;
geography: {
continent: string;
coordinates: {
latitude: number;
longitude: number;
};
};
economy: {
currency: string;
major_industries: string[];
};
}
const sdk = new RagUpstashSdk<CityMetadata>({
upstashUrl: process.env.UPSTASH_VECTOR_REST_URL!,
upstashToken: process.env.UPSTASH_VECTOR_REST_TOKEN!,
});
// Complex query with nested objects and arrays
const filter = createFilter()
.eq('geography.continent', 'Asia')
.gt('population', 1000000)
.contains('economy.major_industries', 'Tourism')
.ne('country', 'China')
.gte('geography.coordinates.latitude', 20.0)
.lte('geography.coordinates.latitude', 50.0)
.build();
const result = await sdk.queryDocsFromRAG({
data: 'Find Asian cities with tourism industry',
topK: 5,
filter,
});
console.log('Found cities:', result);API Reference
RagUpstashSdk
Constructor
new RagUpstashSdk(config: RagUpstashSdkConfig)Methods
queryDocsFromRAG(query, namespace?)- Query documents with filtersfeedDocsToRAG(docs, namespace?)- Add documents to the indexgetDocFromRAG(id, namespace?)- Get a specific documentdeleteDocFromRAG(id, namespace?)- Delete a document
Filter Builder
createFilter()- Create a new filter builderFilterBuilder.eq(field, value)- Add equality conditionFilterBuilder.ne(field, value)- Add not equality conditionFilterBuilder.lt(field, value)- Add less than conditionFilterBuilder.lte(field, value)- Add less than or equal conditionFilterBuilder.gt(field, value)- Add greater than conditionFilterBuilder.gte(field, value)- Add greater than or equal conditionFilterBuilder.glob(field, pattern)- Add glob pattern conditionFilterBuilder.notGlob(field, pattern)- Add not glob pattern conditionFilterBuilder.in(field, values)- Add in array conditionFilterBuilder.notIn(field, values)- Add not in array conditionFilterBuilder.contains(field, value)- Add contains conditionFilterBuilder.notContains(field, value)- Add not contains conditionFilterBuilder.hasField(field)- Add has field conditionFilterBuilder.hasNotField(field)- Add has not field conditionFilterBuilder.and()- Combine conditions with ANDFilterBuilder.or()- Combine conditions with ORFilterBuilder.build()- Build the filterFilterBuilder.toString()- Convert to string
Filter Helpers
FilterHelpers.eq(field, value)- Create equality conditionFilterHelpers.ne(field, value)- Create not equality conditionFilterHelpers.lt(field, value)- Create less than conditionFilterHelpers.lte(field, value)- Create less than or equal conditionFilterHelpers.gt(field, value)- Create greater than conditionFilterHelpers.gte(field, value)- Create greater than or equal conditionFilterHelpers.glob(field, pattern)- Create glob pattern conditionFilterHelpers.notGlob(field, pattern)- Create not glob pattern conditionFilterHelpers.in(field, values)- Create in array conditionFilterHelpers.notIn(field, values)- Create not in array conditionFilterHelpers.contains(field, value)- Create contains conditionFilterHelpers.notContains(field, value)- Create not contains conditionFilterHelpers.hasField(field)- Create has field conditionFilterHelpers.hasNotField(field)- Create has not field conditionFilterHelpers.and(...filters)- Create AND compound filterFilterHelpers.or(...filters)- Create OR compound filter
Utility Functions
filterToString(filter)- Convert filter to stringvalidateFilter(filter)- Validate filter with Zod schema
Migration from String Filters
If you're currently using string filters, you can gradually migrate to object filters:
// Before (string filter)
const result = await sdk.queryDocsFromRAG({
data: 'query',
topK: 5,
filter: "country = 'Turkey' AND population > 1000000",
});
// After (object filter)
const result = await sdk.queryDocsFromRAG({
data: 'query',
topK: 5,
filter: createFilter()
.eq('country', 'Turkey')
.gt('population', 1000000)
.build(),
});String filters are still supported for backward compatibility.
License
MIT
