Skip to main content
Glama
custom-aggregate.cpp3.95 kB
class CustomAggregate : public CustomFunction { public: explicit CustomAggregate( v8::Isolate* isolate, Database* db, const char* name, v8::Local<v8::Value> start, v8::Local<v8::Function> step, v8::Local<v8::Value> inverse, v8::Local<v8::Value> result, bool safe_ints ) : CustomFunction(isolate, db, name, step, safe_ints), invoke_result(result->IsFunction()), invoke_start(start->IsFunction()), inverse(isolate, inverse->IsFunction() ? inverse.As<v8::Function>() : v8::Local<v8::Function>()), result(isolate, result->IsFunction() ? result.As<v8::Function>() : v8::Local<v8::Function>()), start(isolate, start) {} static void xStep(sqlite3_context* invocation, int argc, sqlite3_value** argv) { xStepBase(invocation, argc, argv, &CustomAggregate::fn); } static void xInverse(sqlite3_context* invocation, int argc, sqlite3_value** argv) { xStepBase(invocation, argc, argv, &CustomAggregate::inverse); } static void xValue(sqlite3_context* invocation) { xValueBase(invocation, false); } static void xFinal(sqlite3_context* invocation) { xValueBase(invocation, true); } private: static inline void xStepBase(sqlite3_context* invocation, int argc, sqlite3_value** argv, const v8::Global<v8::Function> CustomAggregate::*ptrtm) { AGGREGATE_START(); v8::Local<v8::Value> args_fast[5]; v8::Local<v8::Value>* args = argc <= 4 ? args_fast : ALLOC_ARRAY<v8::Local<v8::Value>>(argc + 1); args[0] = acc->value.Get(isolate); if (argc != 0) Data::GetArgumentsJS(isolate, args + 1, argv, argc, self->safe_ints); v8::MaybeLocal<v8::Value> maybeReturnValue = (self->*ptrtm).Get(isolate)->Call(OnlyContext, v8::Undefined(isolate), argc + 1, args); if (args != args_fast) delete[] args; if (maybeReturnValue.IsEmpty()) { self->PropagateJSError(invocation); } else { v8::Local<v8::Value> returnValue = maybeReturnValue.ToLocalChecked(); if (!returnValue->IsUndefined()) acc->value.Reset(isolate, returnValue); } } static inline void xValueBase(sqlite3_context* invocation, bool is_final) { AGGREGATE_START(); if (!is_final) { acc->is_window = true; } else if (acc->is_window) { DestroyAccumulator(invocation); return; } v8::Local<v8::Value> result = acc->value.Get(isolate); if (self->invoke_result) { v8::MaybeLocal<v8::Value> maybeResult = self->result.Get(isolate)->Call(OnlyContext, v8::Undefined(isolate), 1, &result); if (maybeResult.IsEmpty()) { self->PropagateJSError(invocation); return; } result = maybeResult.ToLocalChecked(); } Data::ResultValueFromJS(isolate, invocation, result, self); if (is_final) DestroyAccumulator(invocation); } struct Accumulator { public: v8::Global<v8::Value> value; bool initialized; bool is_window; }; Accumulator* GetAccumulator(sqlite3_context* invocation) { Accumulator* acc = static_cast<Accumulator*>(sqlite3_aggregate_context(invocation, sizeof(Accumulator))); if (!acc->initialized) { assert(acc->value.IsEmpty()); acc->initialized = true; if (invoke_start) { v8::MaybeLocal<v8::Value> maybeSeed = start.Get(isolate).As<v8::Function>()->Call(OnlyContext, v8::Undefined(isolate), 0, NULL); if (maybeSeed.IsEmpty()) PropagateJSError(invocation); else acc->value.Reset(isolate, maybeSeed.ToLocalChecked()); } else { assert(!start.IsEmpty()); acc->value.Reset(isolate, start); } } return acc; } static void DestroyAccumulator(sqlite3_context* invocation) { Accumulator* acc = static_cast<Accumulator*>(sqlite3_aggregate_context(invocation, sizeof(Accumulator))); assert(acc->initialized); acc->value.Reset(); } void PropagateJSError(sqlite3_context* invocation) { DestroyAccumulator(invocation); CustomFunction::PropagateJSError(invocation); } const bool invoke_result; const bool invoke_start; const v8::Global<v8::Function> inverse; const v8::Global<v8::Function> result; const v8::Global<v8::Value> start; };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mnehmos/mnehmos.synch.mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server