@graphscope-neug/osx-arm64 0.1.3-alpha.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CMakeLists.txt CHANGED
@@ -60,9 +60,6 @@ target_include_directories(neug_node_bind PRIVATE
60
60
  add_dependencies(neug_node_bind neug_proto)
61
61
 
62
62
  set(NEUG_LIBRARIES neug)
63
- if (BUILD_HTTP_SERVER)
64
- set(NEUG_LIBRARIES ${NEUG_LIBRARIES})
65
- endif()
66
63
 
67
64
  find_package(OpenSSL REQUIRED)
68
65
  target_link_libraries(neug_node_bind PRIVATE
package/README.md CHANGED
@@ -62,7 +62,7 @@ Create a self-contained, distributable npm package tarball (`.tgz`). This will:
62
62
  The resulting tarball can be installed without a C++ build environment:
63
63
 
64
64
  ```bash
65
- npm install ./neug-0.1.2.tgz
65
+ npm install ./neug-0.1.3.tgz
66
66
  ```
67
67
 
68
68
 
package/lib/database.js CHANGED
@@ -91,7 +91,6 @@ class Database {
91
91
 
92
92
  this._connections = [];
93
93
  this._asyncConnections = [];
94
- this._serving = false;
95
94
 
96
95
  // Validate path
97
96
  const dbPath = databasePath !== null ? databasePath : '';
@@ -187,17 +186,12 @@ class Database {
187
186
  * Connect to the database and return a Connection object.
188
187
  *
189
188
  * @returns {Connection} A connection to the database.
190
- * @throws {Error} If the database is closed or serving.
189
+ * @throws {Error} If the database is closed.
191
190
  */
192
191
  connect() {
193
192
  if (!this._database) {
194
193
  throw new Error('Database is closed.');
195
194
  }
196
- if (this._serving) {
197
- throw new Error(
198
- 'Cannot create connection while the database server is running.'
199
- );
200
- }
201
195
  const nativeConn = this._database.connect();
202
196
  const conn = new Connection(nativeConn);
203
197
  this._connections.push(conn);
@@ -208,79 +202,18 @@ class Database {
208
202
  * Connect to the database asynchronously.
209
203
  *
210
204
  * @returns {AsyncConnection} An async connection to the database.
211
- * @throws {Error} If the database is closed or serving.
205
+ * @throws {Error} If the database is closed.
212
206
  */
213
207
  asyncConnect() {
214
208
  if (!this._database) {
215
209
  throw new Error('Database is closed.');
216
210
  }
217
- if (this._serving) {
218
- throw new Error(
219
- 'Cannot create async connection while the database server is running.'
220
- );
221
- }
222
211
  const nativeConn = this._database.connect();
223
212
  const asyncConn = new AsyncConnection(nativeConn);
224
213
  this._asyncConnections.push(asyncConn);
225
214
  return asyncConn;
226
215
  }
227
216
 
228
- /**
229
- * Start the database server for handling remote connections (TP mode).
230
- *
231
- * @param {Object} [options] - Server options.
232
- * @param {number} [options.port=10000] - The port to listen on.
233
- * @param {string} [options.host='localhost'] - The host to bind to.
234
- * @param {boolean} [options.blocking=true] - Whether to block until server stops.
235
- * @returns {string} The URI of the server.
236
- */
237
- serve(options = {}) {
238
- const { port = 10000, host = 'localhost', blocking = true } = options;
239
-
240
- // Check all connections are closed
241
- for (const conn of this._connections) {
242
- if (conn && conn.isOpen) {
243
- throw new Error(
244
- 'Cannot start the server while there are open connections to the local database.'
245
- );
246
- }
247
- }
248
- for (const asyncConn of this._asyncConnections) {
249
- if (asyncConn && asyncConn.isOpen) {
250
- throw new Error(
251
- 'Cannot start the server while there are open async connections to the local database.'
252
- );
253
- }
254
- }
255
-
256
- if (this._serving) {
257
- console.log('[neug] Database server is already running.');
258
- return;
259
- }
260
- this._serving = true;
261
- console.log(`[neug] Starting database server on ${host}:${port}.`);
262
-
263
- try {
264
- return this._database.serve(port, host, this._maxThreadNum, blocking);
265
- } catch (e) {
266
- this._serving = false;
267
- throw e;
268
- }
269
- }
270
-
271
- /**
272
- * Stop the database server.
273
- * @throws {Error} If the server is not running.
274
- */
275
- stopServing() {
276
- if (!this._serving) {
277
- throw new Error('Database server is not running.');
278
- }
279
- console.log('[neug] Stopping database server.');
280
- this._database.stopServing();
281
- this._serving = false;
282
- }
283
-
284
217
  /**
285
218
  * Close the database connection and release all resources.
286
219
  */
package/lib/index.js CHANGED
@@ -46,7 +46,6 @@ const { Database } = require('./database');
46
46
  const { Connection } = require('./connection');
47
47
  const { AsyncConnection } = require('./async-connection');
48
48
  const { QueryResult } = require('./query-result');
49
- const { Session } = require('./session');
50
49
  const { parseAndFormatResults, printResultsAsTable, parseEntry } = require('./format');
51
50
  const { version } = require('./version');
52
51
  const errorCodes = require('./error-codes');
@@ -56,7 +55,6 @@ module.exports = {
56
55
  Connection,
57
56
  AsyncConnection,
58
57
  QueryResult,
59
- Session,
60
58
  parseAndFormatResults,
61
59
  printResultsAsTable,
62
60
  parseEntry,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphscope-neug/osx-arm64",
3
- "version": "0.1.3-alpha.1",
3
+ "version": "0.1.3",
4
4
  "description": "NeuG Graph Database Node.js bindings - high performance embedded graph database with Cypher query support",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -27,15 +27,13 @@ namespace neug {
27
27
  Napi::FunctionReference NodeDatabase::constructor;
28
28
 
29
29
  Napi::Object NodeDatabase::Init(Napi::Env env, Napi::Object exports) {
30
- Napi::Function func = DefineClass(
31
- env, "NodeDatabase",
32
- {
33
- InstanceMethod("connect", &NodeDatabase::Connect),
34
- InstanceMethod("close", &NodeDatabase::Close),
35
- InstanceMethod("serve", &NodeDatabase::Serve),
36
- InstanceMethod("stopServing", &NodeDatabase::StopServing),
37
- StaticMethod("cpuCount", &NodeDatabase::GetCpuCount),
38
- });
30
+ Napi::Function func =
31
+ DefineClass(env, "NodeDatabase",
32
+ {
33
+ InstanceMethod("connect", &NodeDatabase::Connect),
34
+ InstanceMethod("close", &NodeDatabase::Close),
35
+ StaticMethod("cpuCount", &NodeDatabase::GetCpuCount),
36
+ });
39
37
  constructor = Napi::Persistent(func);
40
38
  constructor.SuppressDestruct();
41
39
  exports.Set("NodeDatabase", func);
@@ -76,8 +74,10 @@ NodeDatabase::NodeDatabase(const Napi::CallbackInfo& info)
76
74
  }
77
75
 
78
76
  bool checkpoint_on_close = true;
79
- if (opts.Has("checkpointOnClose") && opts.Get("checkpointOnClose").IsBoolean()) {
80
- checkpoint_on_close = opts.Get("checkpointOnClose").As<Napi::Boolean>().Value();
77
+ if (opts.Has("checkpointOnClose") &&
78
+ opts.Get("checkpointOnClose").IsBoolean()) {
79
+ checkpoint_on_close =
80
+ opts.Get("checkpointOnClose").As<Napi::Boolean>().Value();
81
81
  }
82
82
 
83
83
  std::string buffer_strategy = "M_FULL";
@@ -95,8 +95,7 @@ NodeDatabase::NodeDatabase(const Napi::CallbackInfo& info)
95
95
  mode == "read-write") {
96
96
  mode_ = DBMode::READ_WRITE;
97
97
  } else {
98
- Napi::Error::New(env, "Invalid mode: " + mode)
99
- .ThrowAsJavaScriptException();
98
+ Napi::Error::New(env, "Invalid mode: " + mode).ThrowAsJavaScriptException();
100
99
  return;
101
100
  }
102
101
 
@@ -122,12 +121,6 @@ NodeDatabase::NodeDatabase(const Napi::CallbackInfo& info)
122
121
 
123
122
  NodeDatabase::~NodeDatabase() {
124
123
  std::lock_guard<std::recursive_mutex> lock(mtx_);
125
- #ifdef BUILD_HTTP_SERVER
126
- if (service_) {
127
- service_->Stop();
128
- service_.reset();
129
- }
130
- #endif
131
124
  if (database) {
132
125
  database->Close();
133
126
  database.reset();
@@ -155,12 +148,6 @@ Napi::Value NodeDatabase::Connect(const Napi::CallbackInfo& info) {
155
148
 
156
149
  Napi::Value NodeDatabase::Close(const Napi::CallbackInfo& info) {
157
150
  std::lock_guard<std::recursive_mutex> lock(mtx_);
158
- #ifdef BUILD_HTTP_SERVER
159
- if (service_) {
160
- service_->Stop();
161
- service_.reset();
162
- }
163
- #endif
164
151
  if (database) {
165
152
  database->Close();
166
153
  database.reset();
@@ -168,77 +155,6 @@ Napi::Value NodeDatabase::Close(const Napi::CallbackInfo& info) {
168
155
  return info.Env().Undefined();
169
156
  }
170
157
 
171
- Napi::Value NodeDatabase::Serve(const Napi::CallbackInfo& info) {
172
- Napi::Env env = info.Env();
173
- #ifdef BUILD_HTTP_SERVER
174
- if (!database) {
175
- Napi::Error::New(env, "Database is not initialized.")
176
- .ThrowAsJavaScriptException();
177
- return env.Null();
178
- }
179
- if (service_) {
180
- Napi::Error::New(env, "Server is already running.")
181
- .ThrowAsJavaScriptException();
182
- return env.Null();
183
- }
184
-
185
- int port = 10000;
186
- std::string host = "localhost";
187
- int32_t num_thread = 0;
188
- bool blocking = false;
189
-
190
- if (info.Length() >= 1 && info[0].IsNumber()) {
191
- port = info[0].As<Napi::Number>().Int32Value();
192
- }
193
- if (info.Length() >= 2 && info[1].IsString()) {
194
- host = info[1].As<Napi::String>().Utf8Value();
195
- }
196
- if (info.Length() >= 3 && info[2].IsNumber()) {
197
- num_thread = info[2].As<Napi::Number>().Int32Value();
198
- }
199
- if (info.Length() >= 4 && info[3].IsBoolean()) {
200
- blocking = info[3].As<Napi::Boolean>().Value();
201
- }
202
-
203
- std::lock_guard<std::recursive_mutex> lock(mtx_);
204
- database->Close();
205
- database->Open(database->config());
206
-
207
- neug::ServiceConfig config;
208
- config.query_port = port;
209
- config.host_str = host;
210
- config.shard_num =
211
- (num_thread == 0) ? std::thread::hardware_concurrency() : num_thread;
212
- #ifdef __APPLE__
213
- if (host == "localhost") {
214
- config.host_str = "127.0.0.1";
215
- }
216
- #endif
217
-
218
- service_ = std::make_unique<neug::NeugDBService>(*database, config);
219
- if (blocking) {
220
- service_->run_and_wait_for_exit();
221
- return Napi::String::New(env, "");
222
- }
223
- return Napi::String::New(env, service_->Start());
224
- #else
225
- Napi::Error::New(env, "HTTP server is not enabled in this build.")
226
- .ThrowAsJavaScriptException();
227
- return env.Null();
228
- #endif
229
- }
230
-
231
- Napi::Value NodeDatabase::StopServing(const Napi::CallbackInfo& info) {
232
- std::lock_guard<std::recursive_mutex> lock(mtx_);
233
- #ifdef BUILD_HTTP_SERVER
234
- if (service_) {
235
- service_->Stop();
236
- service_.reset();
237
- }
238
- #endif
239
- return info.Env().Undefined();
240
- }
241
-
242
158
  Napi::Value NodeDatabase::GetCpuCount(const Napi::CallbackInfo& info) {
243
159
  long n = sysconf(_SC_NPROCESSORS_ONLN);
244
160
  if (n < 1) {
@@ -23,9 +23,6 @@
23
23
  #include <string>
24
24
 
25
25
  #include "neug/main/neug_db.h"
26
- #ifdef BUILD_HTTP_SERVER
27
- #include "neug/server/neug_db_service.h"
28
- #endif
29
26
  #include "node_connection.h"
30
27
 
31
28
  namespace neug {
@@ -40,8 +37,6 @@ class NodeDatabase : public Napi::ObjectWrap<NodeDatabase> {
40
37
 
41
38
  Napi::Value Connect(const Napi::CallbackInfo& info);
42
39
  Napi::Value Close(const Napi::CallbackInfo& info);
43
- Napi::Value Serve(const Napi::CallbackInfo& info);
44
- Napi::Value StopServing(const Napi::CallbackInfo& info);
45
40
 
46
41
  private:
47
42
  static Napi::FunctionReference constructor;
@@ -51,9 +46,6 @@ class NodeDatabase : public Napi::ObjectWrap<NodeDatabase> {
51
46
  std::recursive_mutex mtx_;
52
47
  std::string db_dir_;
53
48
  std::unique_ptr<NeugDB> database;
54
- #ifdef BUILD_HTTP_SERVER
55
- std::unique_ptr<NeugDBService> service_;
56
- #endif
57
49
  };
58
50
 
59
51
  } // namespace neug
package/lib/session.js DELETED
@@ -1,275 +0,0 @@
1
- /** Copyright 2020 Alibaba Group Holding Limited.
2
- *
3
- * Licensed under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License.
5
- * You may obtain a copy of the License at
6
- *
7
- * http://www.apache.org/licenses/LICENSE-2.0
8
- *
9
- * Unless required by applicable law or agreed to in writing, software
10
- * distributed under the License is distributed on an "AS IS" BASIS,
11
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- * See the License for the specific language governing permissions and
13
- * limitations under the License.
14
- */
15
-
16
- 'use strict';
17
-
18
- const http = require('http');
19
- const https = require('https');
20
- const { URL } = require('url');
21
- const { QueryResult } = require('./query-result');
22
- const { isAccessModeValid, validAccessModes } = require('./utils');
23
- const { ERR_NETWORK, ERR_SESSION_CLOSED } = require('./error-codes');
24
-
25
- // Load the native binding (unified loader handles prebuilds/ and build/)
26
- const nativeBinding = require('./binding');
27
-
28
- /**
29
- * Parse a timeout string to milliseconds.
30
- * @param {string|number} timeout - Timeout value (e.g., '10s', '500ms', or number of seconds).
31
- * @returns {number} Timeout in milliseconds.
32
- */
33
- function parseTimeout(timeout) {
34
- if (typeof timeout === 'number') {
35
- return timeout * 1000;
36
- }
37
- if (typeof timeout === 'string') {
38
- if (timeout.endsWith('ms')) {
39
- return parseInt(timeout.slice(0, -2), 10);
40
- } else if (timeout.endsWith('s')) {
41
- return parseInt(timeout.slice(0, -1), 10) * 1000;
42
- }
43
- }
44
- return 10000; // default 10 seconds
45
- }
46
-
47
- /**
48
- * Make an HTTP request using Node.js built-in http/https modules.
49
- * @param {string} url - The URL to request.
50
- * @param {Object} options - Request options.
51
- * @param {string} [options.method='GET'] - HTTP method.
52
- * @param {string} [options.body] - Request body.
53
- * @param {number} [options.timeout=10000] - Timeout in milliseconds.
54
- * @returns {Promise<{statusCode: number, body: Buffer}>}
55
- */
56
- function httpRequest(url, options = {}) {
57
- return new Promise((resolve, reject) => {
58
- const parsedUrl = new URL(url);
59
- const isHttps = parsedUrl.protocol === 'https:';
60
- const lib = isHttps ? https : http;
61
-
62
- const reqOptions = {
63
- hostname: parsedUrl.hostname,
64
- port: parsedUrl.port || (isHttps ? 443 : 80),
65
- path: parsedUrl.pathname + parsedUrl.search,
66
- method: options.method || 'GET',
67
- timeout: options.timeout || 10000,
68
- headers: options.headers || {},
69
- };
70
-
71
- const req = lib.request(reqOptions, (res) => {
72
- const chunks = [];
73
- res.on('data', (chunk) => chunks.push(chunk));
74
- res.on('end', () => {
75
- resolve({
76
- statusCode: res.statusCode,
77
- body: Buffer.concat(chunks),
78
- });
79
- });
80
- });
81
-
82
- req.on('error', reject);
83
- req.on('timeout', () => {
84
- req.destroy();
85
- reject(new Error('Request timed out'));
86
- });
87
-
88
- if (options.body) {
89
- req.write(options.body);
90
- }
91
- req.end();
92
- });
93
- }
94
-
95
- /**
96
- * Session connects to a NeuG server and provides the same query interface as Connection.
97
- *
98
- * @example
99
- * // Start the server
100
- * const db = new Database({ databasePath: '/tmp/test.db', mode: 'w' });
101
- * db.serve({ port: 10000, host: 'localhost' });
102
- *
103
- * // In another process, connect via Session
104
- * const session = new Session({ endpoint: 'http://localhost:10000' });
105
- * const result = session.execute('MATCH (n) RETURN count(n)');
106
- * for (const row of result) {
107
- * console.log(row);
108
- * }
109
- * session.close();
110
- */
111
- class Session {
112
- /**
113
- * @param {Object} [options] - Session options.
114
- * @param {string} [options.endpoint='http://localhost:10000'] - The server endpoint URL.
115
- * @param {string|number} [options.timeout='10s'] - Request timeout.
116
- */
117
- constructor(options = {}) {
118
- const {
119
- endpoint = 'http://localhost:10000',
120
- timeout = '10s',
121
- } = options;
122
-
123
- this._endpoint = endpoint.replace(/\/+$/, '');
124
- this._queryEndpoint = `${this._endpoint}/cypher`;
125
- this._statusEndpoint = `${this._endpoint}/service_status`;
126
- this._schemaEndpoint = `${this._endpoint}/schema`;
127
- this._timeout = parseTimeout(timeout);
128
- this._closed = false;
129
-
130
- // Quick connectivity check
131
- // (We do this synchronously-ish via the constructor, but it's fire-and-forget)
132
- // For a proper async init, use Session.open() instead.
133
- }
134
-
135
- /**
136
- * Open a session with connectivity check.
137
- *
138
- * @param {Object} [options] - Session options (same as constructor).
139
- * @returns {Promise<Session>} A connected Session instance.
140
- */
141
- static async open(options = {}) {
142
- const session = new Session(options);
143
- // Wait for the server to be ready, same purpose as Python's
144
- // implicit readiness via slower HTTP client startup.
145
- const maxRetries = 5;
146
- const retryDelayMs = 200;
147
- for (let attempt = 0; attempt < maxRetries; attempt++) {
148
- try {
149
- await session._checkConnection();
150
- return session;
151
- } catch (_) {
152
- if (attempt < maxRetries - 1) {
153
- await new Promise((r) => setTimeout(r, retryDelayMs));
154
- }
155
- }
156
- }
157
- // Return anyway — let actual queries surface the real error
158
- return session;
159
- }
160
-
161
- /**
162
- * Check connectivity to the server.
163
- * @private
164
- */
165
- async _checkConnection() {
166
- await httpRequest(this._statusEndpoint, {
167
- method: 'GET',
168
- timeout: this._timeout,
169
- });
170
- }
171
-
172
- /**
173
- * Close the session.
174
- */
175
- close() {
176
- if (this._closed) {
177
- console.warn('[neug] Session is already closed.');
178
- return;
179
- }
180
- this._closed = true;
181
- }
182
-
183
- /**
184
- * Execute a query on the NeuG server.
185
- *
186
- * @param {string} query - The cypher query string.
187
- * @param {string} [accessMode=''] - The access mode.
188
- * @param {Object} [parameters=null] - Query parameters.
189
- * @returns {Promise<QueryResult>} The query result.
190
- * @throws {Error} If the session is closed or the request fails.
191
- */
192
- async execute(query, accessMode = '', parameters = null) {
193
- if (this._closed) {
194
- throw new Error(
195
- `Session is closed. Cannot execute query. Error code: ${ERR_SESSION_CLOSED}`
196
- );
197
- }
198
-
199
- if (accessMode !== '' && !isAccessModeValid(accessMode.toLowerCase())) {
200
- throw new Error(
201
- `Invalid access_mode: ${accessMode}. Supported access modes are ` +
202
- `[${validAccessModes.join(', ')}].`
203
- );
204
- }
205
-
206
- // Build payload
207
- const payload = JSON.stringify({
208
- query,
209
- access_mode: accessMode || 'update',
210
- parameters: parameters || {},
211
- });
212
-
213
- let response;
214
- try {
215
- response = await httpRequest(this._queryEndpoint, {
216
- method: 'POST',
217
- body: payload,
218
- timeout: this._timeout,
219
- headers: {
220
- 'Content-Type': 'application/json',
221
- 'Content-Length': Buffer.byteLength(payload),
222
- },
223
- });
224
- } catch (e) {
225
- throw new Error(
226
- `Could not execute query: ${query}. Error code: ${ERR_NETWORK}. ` +
227
- `Details: ${e.message}`
228
- );
229
- }
230
-
231
- if (response.statusCode !== 200) {
232
- throw new Error(
233
- `Failed to execute query: ${query}. Http code: ${response.statusCode}, ` +
234
- `Response: ${response.body.toString()}`
235
- );
236
- }
237
-
238
- // The response body is a protobuf-serialized QueryResponse.
239
- // Use the native binding to deserialize it.
240
- if (!nativeBinding || !nativeBinding.NodeQueryResult) {
241
- throw new Error(
242
- 'Native binding is required for Session but was not loaded. ' +
243
- 'Please ensure the neug native addon is built and available.'
244
- );
245
- }
246
- const nativeResult = nativeBinding.NodeQueryResult.fromString(response.body);
247
- return new QueryResult(nativeResult);
248
- }
249
-
250
- /**
251
- * Get the service status of the NeuG server.
252
- * @returns {Promise<Object>} The server status as a JSON object.
253
- */
254
- async serviceStatus() {
255
- const response = await httpRequest(this._statusEndpoint, {
256
- method: 'GET',
257
- timeout: this._timeout,
258
- });
259
- return JSON.parse(response.body.toString());
260
- }
261
-
262
- /**
263
- * Get the schema of the NeuG database from the server.
264
- * @returns {Promise<Object>} The schema as a JSON object.
265
- */
266
- async getSchema() {
267
- const response = await httpRequest(this._schemaEndpoint, {
268
- method: 'GET',
269
- timeout: this._timeout,
270
- });
271
- return JSON.parse(response.body.toString());
272
- }
273
- }
274
-
275
- module.exports = { Session };