query-2jz
Version:
Query-2jz: A GraphQL alternative with faster performance and simpler use
158 lines (132 loc) • 3.76 kB
text/typescript
import { Server, Request, ResponseToolkit } from '@hapi/hapi';
import { Qryn, QrynConfig, QrynModel } from '../index';
/**
* Hapi Adapter for Qryn
*/
export class QrynHapiAdapter {
private qryn: Qryn;
constructor(config: QrynConfig, models: QrynModel[] = []) {
this.qryn = new Qryn(config, models);
}
/**
* Initialize the adapter
*/
async initialize(): Promise<void> {
await this.qryn.initialize();
}
/**
* Get Qryn instance
*/
getQryn(): Qryn {
return this.qryn;
}
/**
* Register Hapi routes
*/
async register(server: Server): Promise<void> {
// Health check
server.route({
method: 'GET',
path: '/health',
handler: async (request: Request, h: ResponseToolkit) => {
const stats = this.qryn.getStats();
return {
status: 'healthy',
timestamp: new Date().toISOString(),
...stats
};
}
});
// Query endpoint
server.route({
method: 'GET',
path: '/api/qryn/{model}',
handler: async (request: Request, h: ResponseToolkit) => {
const model = request.params.model;
const query = this.parseQueryParams(request.query);
const result = await this.qryn.query(query, model);
const response = h.response(result);
if (result.meta?.etag) {
response.header('ETag', result.meta.etag);
}
if (result.meta?.lastModified) {
response.header('Last-Modified', result.meta.lastModified);
}
response.header('Cache-Control', 'public, max-age=300');
return response;
}
});
// Mutation endpoint
server.route({
method: 'POST',
path: '/api/qryn/{model}',
handler: async (request: Request, h: ResponseToolkit) => {
const model = request.params.model;
const mutation = request.payload as any;
if (!mutation.operation) {
return h.response({
error: 'Invalid mutation',
message: 'Operation is required'
}).code(400);
}
const result = await this.qryn.mutate(mutation, model);
const response = h.response(result);
response.header('Cache-Control', 'no-cache');
return response;
}
});
// Statistics endpoint
server.route({
method: 'GET',
path: '/api/qryn/stats',
handler: async (request: Request, h: ResponseToolkit) => {
return this.qryn.getStats();
}
});
}
private parseQueryParams(queryParams: any): any {
const query: any = {};
if (queryParams.select) {
try {
query.select = JSON.parse(queryParams.select);
} catch {
query.select = {};
}
}
if (queryParams.where) {
try {
query.where = JSON.parse(queryParams.where);
} catch {
query.where = {};
}
}
if (queryParams.orderBy) {
try {
query.orderBy = JSON.parse(queryParams.orderBy);
} catch {
query.orderBy = {};
}
}
if (queryParams.limit) {
query.limit = parseInt(queryParams.limit);
}
if (queryParams.offset) {
query.offset = parseInt(queryParams.offset);
}
if (queryParams.live === 'true') {
query.live = true;
}
return query;
}
}
/**
* Hapi plugin factory
*/
export function createQrynPlugin(config: QrynConfig, models: QrynModel[] = []) {
const adapter = new QrynHapiAdapter(config, models);
return {
adapter,
plugin: adapter.register.bind(adapter),
initialize: () => adapter.initialize()
};
}