query-2jz
Version:
Query-2jz: A GraphQL alternative with faster performance and simpler use
340 lines (283 loc) • 9.53 kB
text/typescript
import { Query2jzConfig, Query2jzModel, Query2jzQuery, Query2jzMutation, Query2jzResponse } from './types';
import { Query2jzResolver } from './core/resolver';
import { Query2jzCache } from './core/cache';
import { Query2jzRealtime } from './core/realtime';
import { Query2jzOptimisticEngine } from './core/optimistic';
import { Query2jzTypeGenerator } from './core/typegen';
import { Query2jzEdgeRuntime, Query2jzEdgeHandler } from './core/edge';
import { FastifyInstance, FastifyPluginOptions } from 'fastify';
import fastify from 'fastify';
/**
* Main Query-2jz Engine - GraphQL alternative with faster performance and simpler use
*/
export class Query2jz {
private config: Query2jzConfig;
private models: Query2jzModel[];
private resolver?: Query2jzResolver;
private cache?: Query2jzCache;
private realtime?: Query2jzRealtime;
private optimistic?: Query2jzOptimisticEngine;
private typeGenerator?: Query2jzTypeGenerator;
private edgeRuntime?: Query2jzEdgeRuntime;
private server?: FastifyInstance;
private isInitialized = false;
constructor(config: Query2jzConfig, models: Query2jzModel[] = []) {
this.config = config;
this.models = models;
}
/**
* Initialize Query-2jz engine
*/
async initialize(): Promise<void> {
if (this.isInitialized) return;
console.log('Initializing Query-2jz engine...');
// Initialize core components
this.resolver = new Query2jzResolver(this.config, this.models);
this.cache = new Query2jzCache(this.config);
this.optimistic = new Query2jzOptimisticEngine();
this.typeGenerator = new Query2jzTypeGenerator(this.models);
// Initialize real-time if enabled
if (this.config.realtime?.enabled) {
this.realtime = new Query2jzRealtime(this.config);
}
// Initialize edge runtime if enabled
if (this.config.edge?.enabled) {
this.edgeRuntime = new Query2jzEdgeRuntime(this.config);
await this.edgeRuntime.initialize();
}
this.isInitialized = true;
console.log('Query-2jz engine initialized successfully');
}
/**
* Start the Query-2jz server
*/
async start(port: number = 3000): Promise<void> {
await this.ensureInitialized();
this.server = fastify({
logger: true,
trustProxy: true
});
// Register Query-2jz routes
await this.server.register(this.createQuery2jzRoutes.bind(this));
// Initialize real-time if enabled
if (this.realtime) {
await this.realtime.initialize(this.server.server);
}
// Start server
await this.server.listen({ port, host: '0.0.0.0' });
console.log(`Query-2jz server running on port ${port}`);
}
/**
* Stop the Query-2jz server
*/
async stop(): Promise<void> {
if (this.server) {
await this.server.close();
}
if (this.realtime) {
await this.realtime.cleanup();
}
if (this.edgeRuntime) {
await this.edgeRuntime.cleanup();
}
console.log('Query-2jz server stopped');
}
/**
* Execute a query
*/
async query(query: Query2jzQuery, modelName: string): Promise<Query2jzResponse> {
await this.ensureInitialized();
if (this.edgeRuntime) {
return await this.edgeRuntime.executeQuery(query, modelName);
}
return await this.resolver!.executeQuery(query, modelName);
}
/**
* Execute a mutation
*/
async mutate(mutation: Query2jzMutation, modelName: string): Promise<Query2jzResponse> {
await this.ensureInitialized();
if (this.edgeRuntime) {
return await this.edgeRuntime.executeMutation(mutation, modelName);
}
return await this.resolver!.executeMutation(mutation, modelName);
}
/**
* Subscribe to live query updates
*/
subscribe(
query: Query2jzQuery,
modelName: string,
callback: (data: any) => void
): string | null {
if (!this.realtime) {
console.warn('Real-time is not enabled');
return null;
}
return this.realtime.subscribe(query, modelName, callback);
}
/**
* Unsubscribe from live query updates
*/
unsubscribe(subscriptionId: string): void {
if (this.realtime) {
this.realtime.unsubscribe(subscriptionId);
}
}
/**
* Generate TypeScript types
*/
generateTypes(outputDir?: string): void {
if (!this.typeGenerator) {
throw new Error('Query-2jz not initialized');
}
if (outputDir) {
this.typeGenerator = new Query2jzTypeGenerator(this.models, outputDir);
}
this.typeGenerator.generateTypes();
console.log(`Types generated in ${outputDir || './generated'}`);
}
/**
* Add a model
*/
addModel(model: Query2jzModel): void {
this.models.push(model);
if (this.resolver) {
this.resolver.addModel(model);
}
if (this.typeGenerator) {
this.typeGenerator = new Query2jzTypeGenerator(this.models);
}
}
/**
* Remove a model
*/
removeModel(modelName: string): void {
this.models = this.models.filter(m => m.name !== modelName);
if (this.resolver) {
this.resolver.removeModel(modelName);
}
if (this.typeGenerator) {
this.typeGenerator = new Query2jzTypeGenerator(this.models);
}
}
/**
* Get all models
*/
getModels(): Query2jzModel[] {
return [...this.models];
}
/**
* Get model by name
*/
getModel(modelName: string): Query2jzModel | undefined {
return this.models.find(m => m.name === modelName);
}
/**
* Get Query-2jz statistics
*/
getStats(): any {
return {
initialized: this.isInitialized,
models: this.models.length,
cache: this.cache?.getStats(),
realtime: this.realtime?.getStats(),
optimistic: this.optimistic?.getStats(),
edge: this.edgeRuntime?.getStats()
};
}
/**
* Create Query-2jz routes for Fastify
*/
private async createQuery2jzRoutes(
fastify: FastifyInstance,
options: FastifyPluginOptions
): Promise<void> {
// Health check
fastify.get('/health', async (request, reply) => {
return { status: 'healthy', timestamp: new Date().toISOString() };
});
// Query endpoint
fastify.get('/api/query-2jz/:model', async (request, reply) => {
const { model } = request.params as { model: string };
const query = request.query as any;
try {
const result = await this.query(query, model);
// Set cache headers
if (result.meta?.etag) {
reply.header('ETag', result.meta.etag);
}
if (result.meta?.lastModified) {
reply.header('Last-Modified', result.meta.lastModified);
}
reply.header('Cache-Control', 'public, max-age=300');
return result;
} catch (error) {
reply.code(500);
return { error: 'Query execution failed', message: error.message };
}
});
// Mutation endpoint
fastify.post('/api/query-2jz/:model', async (request, reply) => {
const { model } = request.params as { model: string };
const mutation = request.body as Query2jzMutation;
try {
const result = await this.mutate(mutation, model);
reply.header('Cache-Control', 'no-cache');
return result;
} catch (error) {
reply.code(500);
return { error: 'Mutation execution failed', message: error.message };
}
});
// Real-time subscription endpoint
if (this.realtime) {
fastify.get('/api/query-2jz/:model/subscribe', async (request, reply) => {
const { model } = request.params as { model: string };
const query = request.query as any;
// This would handle SSE connections
reply.type('text/event-stream');
reply.header('Cache-Control', 'no-cache');
reply.header('Connection', 'keep-alive');
const subscriptionId = this.subscribe(query, model, (data) => {
reply.raw.write(`data: ${JSON.stringify(data)}\n\n`);
});
request.raw.on('close', () => {
if (subscriptionId) {
this.unsubscribe(subscriptionId);
}
});
return reply;
});
}
// Type generation endpoint
fastify.post('/api/query-2jz/generate-types', async (request, reply) => {
try {
this.generateTypes();
return { message: 'Types generated successfully' };
} catch (error) {
reply.code(500);
return { error: 'Type generation failed', message: error.message };
}
});
// Statistics endpoint
fastify.get('/api/query-2jz/stats', async (request, reply) => {
return this.getStats();
});
}
private async ensureInitialized(): Promise<void> {
if (!this.isInitialized) {
await this.initialize();
}
}
}
// Export types and classes
export * from './types';
export { Query2jzResolver } from './core/resolver';
export { Query2jzCache } from './core/cache';
export { Query2jzRealtime } from './core/realtime';
export { Query2jzOptimisticEngine } from './core/optimistic';
export { Query2jzTypeGenerator } from './core/typegen';
export { Query2jzEdgeRuntime, Query2jzEdgeHandler } from './core/edge';
// Default export
export default Query2jz;