A TypeScript SDK for Rag Upstash.
npm install @microfox/rag-upstashA TypeScript SDK for working with Upstash Vector for RAG (Retrieval-Augmented Generation) applications.
- 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
``bash`
npm install rag-upstash
`typescript
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(),
});
`
The SDK supports both string-based filters (legacy) and object-based filters (new). The object-based system provides type safety and better developer experience.
`typescript
// 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;
`
| 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') |
#### 1. Using Filter Builder (Recommended)
`typescript
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 AND
`
#### 2. Using Filter Helpers
`typescript
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
`typescript
const filter: FilterCondition = {
field: 'country',
operator: '=',
value: 'Turkey',
};
const compoundFilter: CompoundFilter = {
operator: 'AND',
filters: [
{ field: 'country', operator: '=', value: 'Turkey' },
{ field: 'population', operator: '>', value: 1000000 },
],
};
`
The filter system supports nested objects using dot notation:
`typescript`
const filter = createFilter()
.eq('geography.continent', 'Asia')
.gte('geography.coordinates.latitude', 35.0)
.lt('geography.coordinates.longitude', 30.0)
.build();
#### Array Elements
`typescript`
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
`typescript`
const filter = createFilter()
.in('country', ['Turkey', 'Germany', 'France'])
.notIn('currency', ['USD', 'EUR'])
.build();
`typescript`
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();
`typescript`
const filter = createFilter()
.hasField('geography.coordinates') // Field exists
.hasNotField('geography.coordinates.longitude') // Field doesn't exist
.build();
`typescript`
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')
);
The filter system includes built-in validation:
`typescript
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);
}
`
Convert filters to strings for debugging:
`typescript
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"
`
`typescript
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
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);
`
#### Constructor
`typescript`
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
- 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
- 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
- filterToString(filter) - Convert filter to stringvalidateFilter(filter)
- - Validate filter with Zod schema
If you're currently using string filters, you can gradually migrate to object filters:
`typescript
// 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.
MIT