@dolthub/doltlite 0.10.0
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/README.md +167 -0
- package/binding.gyp +54 -0
- package/index.d.ts +192 -0
- package/index.js +27 -0
- package/package.json +51 -0
- package/prebuilds/darwin-arm64/doltlite.node +0 -0
- package/prebuilds/darwin-x64/doltlite.node +0 -0
- package/prebuilds/linux-arm64/doltlite.node +0 -0
- package/prebuilds/linux-x64/doltlite.node +0 -0
- package/prebuilds/win32-x64/doltlite.node +0 -0
- package/scripts/download.js +87 -0
- package/src/addon.cpp +15 -0
- package/src/database.cpp +423 -0
- package/src/database.h +53 -0
- package/src/statement.cpp +180 -0
- package/src/statement.h +29 -0
- package/src/util.h +124 -0
package/src/util.h
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <napi.h>
|
|
3
|
+
#include "doltlite.h"
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
// Converts a SQLite column value to a Napi::Value.
|
|
7
|
+
inline Napi::Value ColumnToNapi(Napi::Env env, sqlite3_stmt* stmt, int col) {
|
|
8
|
+
switch (sqlite3_column_type(stmt, col)) {
|
|
9
|
+
case SQLITE_INTEGER:
|
|
10
|
+
return Napi::Number::New(env, (double)sqlite3_column_int64(stmt, col));
|
|
11
|
+
case SQLITE_FLOAT:
|
|
12
|
+
return Napi::Number::New(env, sqlite3_column_double(stmt, col));
|
|
13
|
+
case SQLITE_TEXT: {
|
|
14
|
+
const char* text = (const char*)sqlite3_column_text(stmt, col);
|
|
15
|
+
int bytes = sqlite3_column_bytes(stmt, col);
|
|
16
|
+
return Napi::String::New(env, text, bytes);
|
|
17
|
+
}
|
|
18
|
+
case SQLITE_BLOB: {
|
|
19
|
+
const void* data = sqlite3_column_blob(stmt, col);
|
|
20
|
+
int bytes = sqlite3_column_bytes(stmt, col);
|
|
21
|
+
auto buf = Napi::Buffer<uint8_t>::Copy(env, (const uint8_t*)data, bytes);
|
|
22
|
+
return buf;
|
|
23
|
+
}
|
|
24
|
+
case SQLITE_NULL:
|
|
25
|
+
default:
|
|
26
|
+
return env.Null();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Builds a JS object from the current row of a prepared statement.
|
|
31
|
+
inline Napi::Object RowToObject(Napi::Env env, sqlite3_stmt* stmt) {
|
|
32
|
+
auto obj = Napi::Object::New(env);
|
|
33
|
+
int n = sqlite3_column_count(stmt);
|
|
34
|
+
for (int i = 0; i < n; i++) {
|
|
35
|
+
const char* name = sqlite3_column_name(stmt, i);
|
|
36
|
+
obj.Set(name, ColumnToNapi(env, stmt, i));
|
|
37
|
+
}
|
|
38
|
+
return obj;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Binds a JS value to a prepared statement parameter (1-based index).
|
|
42
|
+
inline bool BindNapi(Napi::Env env, sqlite3_stmt* stmt, int idx, Napi::Value val) {
|
|
43
|
+
if (val.IsNull() || val.IsUndefined()) {
|
|
44
|
+
sqlite3_bind_null(stmt, idx);
|
|
45
|
+
} else if (val.IsNumber()) {
|
|
46
|
+
double d = val.As<Napi::Number>().DoubleValue();
|
|
47
|
+
int64_t i = (int64_t)d;
|
|
48
|
+
if ((double)i == d) {
|
|
49
|
+
sqlite3_bind_int64(stmt, idx, i);
|
|
50
|
+
} else {
|
|
51
|
+
sqlite3_bind_double(stmt, idx, d);
|
|
52
|
+
}
|
|
53
|
+
} else if (val.IsString()) {
|
|
54
|
+
std::string s = val.As<Napi::String>().Utf8Value();
|
|
55
|
+
sqlite3_bind_text(stmt, idx, s.c_str(), (int)s.size(), SQLITE_TRANSIENT);
|
|
56
|
+
} else if (val.IsBoolean()) {
|
|
57
|
+
sqlite3_bind_int(stmt, idx, val.As<Napi::Boolean>().Value() ? 1 : 0);
|
|
58
|
+
} else if (val.IsBuffer()) {
|
|
59
|
+
auto buf = val.As<Napi::Buffer<uint8_t>>();
|
|
60
|
+
sqlite3_bind_blob(stmt, idx, buf.Data(), (int)buf.ByteLength(), SQLITE_TRANSIENT);
|
|
61
|
+
} else if (val.IsBigInt()) {
|
|
62
|
+
bool lossless;
|
|
63
|
+
int64_t i = val.As<Napi::BigInt>().Int64Value(&lossless);
|
|
64
|
+
sqlite3_bind_int64(stmt, idx, i);
|
|
65
|
+
} else {
|
|
66
|
+
Napi::TypeError::New(env, "Unsupported parameter type").ThrowAsJavaScriptException();
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Binds JS arguments (array or named object) to a prepared statement.
|
|
73
|
+
// positional: bind(val, val, ...) or bind([val, val, ...])
|
|
74
|
+
// named: bind({$name: val, ...}) or bare names {name: val} if allowBare=true
|
|
75
|
+
inline bool BindArgs(Napi::Env env, sqlite3_stmt* stmt,
|
|
76
|
+
const Napi::CallbackInfo& info, size_t startIdx = 0,
|
|
77
|
+
bool allowBare = true) {
|
|
78
|
+
sqlite3_clear_bindings(stmt);
|
|
79
|
+
if (info.Length() <= (int)startIdx) return true;
|
|
80
|
+
|
|
81
|
+
// Named parameters via a plain object
|
|
82
|
+
if (info.Length() == startIdx + 1 && info[startIdx].IsObject()
|
|
83
|
+
&& !info[startIdx].IsBuffer() && !info[startIdx].IsArray()) {
|
|
84
|
+
auto obj = info[startIdx].As<Napi::Object>();
|
|
85
|
+
auto keys = obj.GetPropertyNames();
|
|
86
|
+
for (uint32_t i = 0; i < keys.Length(); i++) {
|
|
87
|
+
std::string key = keys.Get(i).As<Napi::String>().Utf8Value();
|
|
88
|
+
// Try $name, :name, @name prefixes, then bare if allowBare
|
|
89
|
+
int idx = 0;
|
|
90
|
+
for (const char* prefix : {"", "$", ":", "@"}) {
|
|
91
|
+
std::string k = std::string(prefix) + key;
|
|
92
|
+
idx = sqlite3_bind_parameter_index(stmt, k.c_str());
|
|
93
|
+
if (idx > 0) break;
|
|
94
|
+
}
|
|
95
|
+
if (idx == 0 && !allowBare) continue;
|
|
96
|
+
if (idx == 0) continue;
|
|
97
|
+
if (!BindNapi(env, stmt, idx, obj.Get(keys.Get(i)))) return false;
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Positional parameters
|
|
103
|
+
for (size_t i = startIdx; i < (size_t)info.Length(); i++) {
|
|
104
|
+
int pos = (int)(i - startIdx + 1);
|
|
105
|
+
if (info[i].IsArray()) {
|
|
106
|
+
// bind([v1, v2, ...])
|
|
107
|
+
auto arr = info[i].As<Napi::Array>();
|
|
108
|
+
for (uint32_t j = 0; j < arr.Length(); j++) {
|
|
109
|
+
if (!BindNapi(env, stmt, pos + (int)j, arr.Get(j))) return false;
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
if (!BindNapi(env, stmt, pos, info[i])) return false;
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Throws a SQLite error as a JS Error.
|
|
119
|
+
inline void ThrowSQLiteError(Napi::Env env, sqlite3* db, const char* context = nullptr) {
|
|
120
|
+
std::string msg;
|
|
121
|
+
if (context) { msg += context; msg += ": "; }
|
|
122
|
+
msg += sqlite3_errmsg(db);
|
|
123
|
+
Napi::Error::New(env, msg).ThrowAsJavaScriptException();
|
|
124
|
+
}
|