@goatlab/typesense
Version:
Modern TypeScript wrapper for Typesense search engine API
182 lines • 6.51 kB
JavaScript
"use strict";
/**
* Example of using TypesenseApi with multitenancy support
*/
Object.defineProperty(exports, "__esModule", { value: true });
const TypesenseApi_1 = require("../TypesenseApi");
const tenant_1 = require("../utils/tenant");
// Example 1: Creating separate API instances for different tenants
async function example1() {
// API instance for tenant "acme"
const acmeApi = new TypesenseApi_1.TypesenseApi({
prefixUrl: 'http://localhost:8108',
token: 'xyz',
tenantId: 'acme',
collectionName: 'products'
});
// API instance for tenant "globex"
const globexApi = new TypesenseApi_1.TypesenseApi({
prefixUrl: 'http://localhost:8108',
token: 'xyz',
tenantId: 'globex',
collectionName: 'products'
});
// Define schema
const productSchema = {
name: 'products',
fields: [
{ name: 'name', type: 'string' },
{ name: 'price', type: 'float' },
{ name: 'category', type: 'string', facet: true }
]
};
// Create collections - each tenant gets their own prefixed collection
// This creates "acme__products" collection
await acmeApi.collections.create(productSchema);
// This creates "globex__products" collection
await globexApi.collections.create(productSchema);
// Insert documents - completely isolated between tenants
await acmeApi.documents.insert({
id: '1',
name: 'Acme Widget',
price: 19.99,
category: 'widgets'
});
await globexApi.documents.insert({
id: '1', // Same ID is fine - different collection
name: 'Globex Gadget',
price: 29.99,
category: 'gadgets'
});
// Search - each tenant only sees their own data
const acmeResults = await acmeApi.search.text({
q: '*',
query_by: 'name'
});
console.log('Acme products:', acmeResults.hits); // Only Acme Widget
const globexResults = await globexApi.search.text({
q: '*',
query_by: 'name'
});
console.log('Globex products:', globexResults.hits); // Only Globex Gadget
}
// Example 2: Admin operations across tenants
async function example2() {
const adminApi = new TypesenseApi_1.TypesenseApi({
prefixUrl: 'http://localhost:8108',
token: 'xyz',
tenantId: 'acme'
});
// List all collections for the tenant
const tenantCollections = await adminApi.listTenantCollections();
console.log('Acme collections:', tenantCollections);
// Output: ['acme__products', 'acme__users', 'acme__orders']
// Get base collection names (without tenant prefix)
const baseNames = await adminApi.listTenantBaseCollectionNames();
console.log('Base collection names:', baseNames);
// Output: ['products', 'users', 'orders']
// Check if a specific collection exists
const exists = await adminApi.tenantCollectionExists('products');
console.log('Products collection exists:', exists);
// Delete all tenant data (use with caution!)
// await adminApi.deleteAllTenantCollections()
}
// Example 3: Working with multiple collections per tenant
async function example3() {
const api = new TypesenseApi_1.TypesenseApi({
prefixUrl: 'http://localhost:8108',
token: 'xyz',
tenantId: 'acme'
});
// Create multiple collections for the tenant
await api.collections.create({
name: 'users',
fields: [
{ name: 'email', type: 'string' },
{ name: 'name', type: 'string' }
]
});
await api.collections.create({
name: 'orders',
fields: [
{ name: 'order_id', type: 'string' },
{ name: 'user_email', type: 'string' },
{ name: 'total', type: 'float' }
]
});
// Work with different collections by changing the context
const userApi = new TypesenseApi_1.TypesenseApi({
prefixUrl: 'http://localhost:8108',
token: 'xyz',
tenantId: 'acme',
collectionName: 'users'
});
const orderApi = new TypesenseApi_1.TypesenseApi({
prefixUrl: 'http://localhost:8108',
token: 'xyz',
tenantId: 'acme',
collectionName: 'orders'
});
// Insert data into different collections
await userApi.documents.insert({
id: 'user-1',
email: 'john@acme.com',
name: 'John Doe'
});
await orderApi.documents.insert({
id: 'ORD-001',
order_id: 'ORD-001',
user_email: 'john@acme.com',
total: 99.99
});
}
// Example 4: Migrating existing non-tenant data
async function example4() {
// API without tenant (legacy mode)
const legacyApi = new TypesenseApi_1.TypesenseApi({
prefixUrl: 'http://localhost:8108',
token: 'xyz',
collectionName: 'products'
});
// API with tenant
const tenantApi = new TypesenseApi_1.TypesenseApi({
prefixUrl: 'http://localhost:8108',
token: 'xyz',
tenantId: 'legacy',
collectionName: 'products'
});
// Export from legacy collection
const legacyData = await legacyApi.documents.export();
// Create new tenant collection
const schema = await legacyApi.collections.get('products');
await tenantApi.collections.create(schema);
// Import into tenant collection
await tenantApi.documents.import(legacyData);
}
// Example 5: Using tenant utilities directly
async function example5() {
// Validate tenant ID
try {
const tenantId = (0, tenant_1.sanitizeTenantId)('ACME-Corp');
console.log('Sanitized:', tenantId); // 'acme-corp'
}
catch (error) {
console.error('Invalid tenant ID:', error.message);
}
// Create fully qualified collection name
const fqcn = (0, tenant_1.createFQCN)('acme', 'products');
console.log('FQCN:', fqcn); // 'acme__products'
// Parse collection name
const parsed = (0, tenant_1.parseFQCN)('acme__products');
console.log('Parsed:', parsed); // { tenantId: 'acme', baseCollectionName: 'products' }
// Filter collections by tenant
const allCollections = [
'acme__products',
'acme__users',
'globex__products',
'legacy_collection'
];
const acmeCollections = (0, tenant_1.filterCollectionsByTenant)(allCollections, 'acme');
console.log('Acme collections:', acmeCollections); // ['acme__products', 'acme__users']
}
//# sourceMappingURL=multitenancy-example.js.map