2 #include <node_object_wrap.h>
20 static v8::Local<v8::Object> index_result_to_object(
22 struct index_result* result
24 static v8::Local<v8::Object> index_results_to_object(
26 struct index_result* results,
27 unsigned int num_results,
28 double/*unsigned long int*/ total_results
31 class IndexObject : public node::ObjectWrap {
33 static void Init(v8::Local<v8::Object> exports);
38 explicit IndexObject(struct index* idx0);
41 static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
42 static void Search(const v8::FunctionCallbackInfo<v8::Value>& args);
43 static v8::Persistent<v8::Function> constructor;
46 v8::Persistent<v8::Function> IndexObject::constructor;
48 IndexObject::IndexObject(struct index* idx0) : idx(idx0) {
51 IndexObject::~IndexObject() {
54 void IndexObject::Init(v8::Local<v8::Object> exports) {
55 v8::Isolate* isolate = exports->GetIsolate();
57 // Prepare constructor template
58 v8::Local<v8::FunctionTemplate> tpl =
59 v8::FunctionTemplate::New(isolate, New);
60 tpl->SetClassName(v8::String::NewFromUtf8(isolate, "Index"));
61 tpl->InstanceTemplate()->SetInternalFieldCount(1);
64 NODE_SET_PROTOTYPE_METHOD(tpl, "search", Search);
66 constructor.Reset(isolate, tpl->GetFunction());
68 v8::String::NewFromUtf8(isolate, "Index"),
73 void IndexObject::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
74 v8::Isolate* isolate = args.GetIsolate();
76 if (args.IsConstructCall()) {
77 // Invoked as constructor: `new Index(...)`
78 v8::String::Utf8Value prefix(args[0]);
79 struct index* idx = NULL;;
80 int lopts = INDEX_LOAD_NOOPT;
81 struct index_load_opt lopt;
83 lopts |= INDEX_LOAD_IGNORE_VERSION; /* quick hack */
87 args[0]->IsString() ? *prefix : "index",
94 isolate->ThrowException(
95 v8::String::NewFromUtf8(isolate, "Unable to load index")
99 IndexObject* obj = new IndexObject(idx);
100 obj->Wrap(args.This());
101 args.GetReturnValue().Set(args.This());
103 // Invoked as plain function `Index(...)`, turn into construct call.
105 v8::Local<v8::Value> argv[argc] = { args[0] };
106 v8::Local<v8::Context> context = isolate->GetCurrentContext();
107 v8::Local<v8::Function> cons =
108 v8::Local<v8::Function>::New(isolate, constructor);
109 v8::Local<v8::Object> result =
110 cons->NewInstance(context, argc, argv).ToLocalChecked();
111 args.GetReturnValue().Set(result);
115 void IndexObject::Search(const v8::FunctionCallbackInfo<v8::Value>& args) {
116 v8::Isolate* isolate = args.GetIsolate();
118 v8::String::Utf8Value query(args[0]);
119 v8::String::Utf8Value optType(args[3]);
120 v8::Local<v8::Array> optArgsTuple;
121 if (args[4]->IsArray())
122 optArgsTuple = args[4].As<v8::Array>();
123 unsigned long startdoc = args[1]->IntegerValue();
124 unsigned long len = args[2]->IntegerValue();
125 IndexObject* Index = node::ObjectWrap::Unwrap<IndexObject>(args.Holder());
126 struct index_result* result;
127 unsigned int results;
128 double/*unsigned long int*/ total_results;
130 unsigned int accumulator_limit = args[5]->Uint32Value();
131 int opts = INDEX_SEARCH_NOOPT;
132 struct index_search_opt opt;
134 opt.u.okapi_k3.k1 = 1.2;
135 opt.u.okapi_k3.k3 = 1e10;
136 opt.u.okapi_k3.b = 0.75;
139 (result = (struct index_result*)malloc(sizeof(*result) * len)) == NULL
141 isolate->ThrowException(
142 v8::String::NewFromUtf8(isolate, "Unable to allocate results")
146 if (args[3]->IsString()) {
147 if (strcmp(*optType, "COSINE") == 0) {
148 opts = INDEX_SEARCH_COSINE_RANK;
149 } else if (strcmp(*optType, "OKAPI") == 0) {
150 opts = INDEX_SEARCH_OKAPI_RANK;
151 } else if (strcmp(*optType, "OKAPI_K3") == 0) {
152 if (optArgsTuple.IsEmpty()) {
153 isolate->ThrowException(
154 v8::String::NewFromUtf8(isolate, "Must supply args to search type")
159 opts = INDEX_SEARCH_OKAPI_RANK;
160 opt.u.okapi_k3.k1 = optArgsTuple->Get(0)->IntegerValue();
161 opt.u.okapi_k3.k3 = optArgsTuple->Get(1)->IntegerValue();
162 opt.u.okapi_k3.b = optArgsTuple->Get(2)->IntegerValue();
163 } else if (strcmp(*optType, "HAWKAPI") == 0) {
164 if (optArgsTuple.IsEmpty()) {
165 isolate->ThrowException(
166 v8::String::NewFromUtf8(isolate, "Must supply args to search type")
171 opts = INDEX_SEARCH_HAWKAPI_RANK;
172 opt.u.hawkapi.alpha = optArgsTuple->Get(0)->IntegerValue();
173 opt.u.hawkapi.k3 = optArgsTuple->Get(1)->IntegerValue();
174 } else if (strcmp(*optType, "DIRICHLET") == 0) {
175 opts = INDEX_SEARCH_DIRICHLET_RANK;
176 if (optArgsTuple.IsEmpty() || optArgsTuple->Length() == 0)
177 opt.u.dirichlet.mu = 2500.0;
179 opt.u.dirichlet.mu = optArgsTuple->Get(0)->NumberValue();
181 isolate->ThrowException(
182 v8::String::NewFromUtf8(isolate, "Unknown search type")
188 if (accumulator_limit != 0) {
189 opts |= INDEX_SEARCH_ACCUMULATOR_LIMIT;
190 opt.accumulator_limit = accumulator_limit;
193 opts |= INDEX_SEARCH_SUMMARY_TYPE;
194 opt.summary_type = INDEX_SUMMARISE_CAPITALISE;
196 if (!index_search(Index->idx, *query, startdoc, len,
197 result, &results, &total_results, &est, opts, &opt)) {
199 snprintf(err_buf, 1024, "Unable to perform search for query '%s'; "
200 "system error is '%s'\n", *query, strerror(errno));
201 isolate->ThrowException(
202 v8::String::NewFromUtf8(isolate, err_buf)
207 args.GetReturnValue().Set(
208 index_results_to_object(isolate, result, results, total_results)
214 static v8::Local<v8::Object> index_result_to_object(
215 v8::Isolate* isolate,
216 struct index_result* result
218 v8::EscapableHandleScope handle_scope(isolate);
219 v8::Local<v8::Object> result_object = v8::Object::New(isolate);
221 v8::String::NewFromUtf8(isolate, "docno"),
222 v8::Integer::New(isolate, result->docno)
225 v8::String::NewFromUtf8(isolate, "score"),
226 v8::Number::New(isolate, result->score)
229 v8::String::NewFromUtf8(isolate, "summary"),
230 v8::String::NewFromUtf8(isolate, result->summary)
233 v8::String::NewFromUtf8(isolate, "title"),
234 v8::String::NewFromUtf8(isolate, result->title)
237 v8::String::NewFromUtf8(isolate, "auxiliary"),
238 v8::String::NewFromUtf8(isolate, result->auxilliary)
240 return handle_scope.Escape(result_object);
243 static v8::Local<v8::Object> index_results_to_object(
244 v8::Isolate* isolate,
245 struct index_result* results,
246 unsigned int num_results,
247 double/*unsigned long int*/ total_results
249 v8::EscapableHandleScope handle_scope(isolate);
250 v8::Local<v8::Object> results_object = v8::Object::New(isolate);
251 v8::Local<v8::Array> results_array = v8::Array::New(isolate, num_results);
252 for (unsigned int i = 0; i < num_results; ++i)
253 results_array->Set(i, index_result_to_object(isolate, results + i));
255 v8::String::NewFromUtf8(isolate, "results"),
259 v8::String::NewFromUtf8(isolate, "total_results"),
260 v8::Number::New(isolate, total_results)
262 return handle_scope.Escape(results_object);
265 void InitAll(v8::Local<v8::Object> exports) {
266 IndexObject::Init(exports);
269 NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)