UNPKG

11.2 kBtext/x-cView Raw
1#ifndef NODE_SQLITE3_SRC_MACROS_H
2#define NODE_SQLITE3_SRC_MACROS_H
3
4const char* sqlite_code_string(int code);
5const char* sqlite_authorizer_string(int type);
6#include <vector>
7
8// TODO: better way to work around StringConcat?
9#include <napi.h>
10inline Napi::String StringConcat(Napi::Value str1, Napi::Value str2) {
11 return Napi::String::New(str1.Env(), str1.As<Napi::String>().Utf8Value() +
12 str2.As<Napi::String>().Utf8Value() );
13}
14
15// A Napi substitute IsInt32()
16inline bool OtherIsInt(Napi::Number source) {
17 double orig_val = source.DoubleValue();
18 double int_val = static_cast<double>(source.Int32Value());
19 if (orig_val == int_val) {
20 return true;
21 } else {
22 return false;
23 }
24}
25
26#define IS_FUNCTION(cb) \
27 !cb.IsUndefined() && cb.IsFunction()
28
29#define REQUIRE_ARGUMENTS(n) \
30 if (info.Length() < (n)) { \
31 Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \
32 return env.Null(); \
33 }
34
35
36#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \
37 if (info.Length() <= (i) || !info[i].IsExternal()) { \
38 Napi::TypeError::New(env, "Argument " #i " invalid").ThrowAsJavaScriptException(); \
39 return env.Null(); \
40 } \
41 Napi::External var = info[i].As<Napi::External>();
42
43
44#define REQUIRE_ARGUMENT_FUNCTION(i, var) \
45 if (info.Length() <= (i) || !info[i].IsFunction()) { \
46 Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \
47 return env.Null(); \
48 } \
49 Napi::Function var = info[i].As<Napi::Function>();
50
51
52#define REQUIRE_ARGUMENT_STRING(i, var) \
53 if (info.Length() <= (i) || !info[i].IsString()) { \
54 Napi::TypeError::New(env, "Argument " #i " must be a string").ThrowAsJavaScriptException(); \
55 return env.Null(); \
56 } \
57 std::string var = info[i].As<Napi::String>();
58
59#define REQUIRE_ARGUMENT_INTEGER(i, var) \
60 if (info.Length() <= (i) || !info[i].IsNumber()) { \
61 Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \
62 return env.Null(); \
63 } \
64 int var(info[i].As<Napi::Number>().Int32Value());
65
66#define OPTIONAL_ARGUMENT_FUNCTION(i, var) \
67 Napi::Function var; \
68 if (info.Length() > i && !info[i].IsUndefined()) { \
69 if (!info[i].IsFunction()) { \
70 Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \
71 return env.Null(); \
72 } \
73 var = info[i].As<Napi::Function>(); \
74 }
75
76
77#define OPTIONAL_ARGUMENT_INTEGER(i, var, default) \
78 int var; \
79 if (info.Length() <= (i)) { \
80 var = (default); \
81 } \
82 else if (info[i].IsNumber()) { \
83 if (OtherIsInt(info[i].As<Number>())) { \
84 var = info[i].As<Napi::Number>().Int32Value(); \
85 } \
86 } \
87 else { \
88 Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \
89 return env.Null(); \
90 }
91
92
93#define DEFINE_CONSTANT_INTEGER(target, constant, name) \
94 Napi::PropertyDescriptor::Value(#name, Napi::Number::New(env, constant), \
95 static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)),
96
97#define DEFINE_CONSTANT_STRING(target, constant, name) \
98 Napi::PropertyDescriptor::Value(#name, Napi::String::New(env, constant), \
99 static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)),
100
101#define EXCEPTION(msg, errno, name) \
102 Napi::Value name = Napi::Error::New(env, \
103 StringConcat( \
104 StringConcat( \
105 Napi::String::New(env, sqlite_code_string(errno)), \
106 Napi::String::New(env, ": ") \
107 ), \
108 (msg) \
109 ).Utf8Value() \
110 ).Value(); \
111 Napi::Object name ##_obj = name.As<Napi::Object>(); \
112 (name ##_obj).Set( Napi::String::New(env, "errno"), Napi::Number::New(env, errno)); \
113 (name ##_obj).Set( Napi::String::New(env, "code"), \
114 Napi::String::New(env, sqlite_code_string(errno)));
115
116
117#define EMIT_EVENT(obj, argc, argv) \
118 TRY_CATCH_CALL((obj), \
119 (obj).Get("emit").As<Napi::Function>(),\
120 argc, argv \
121 );
122
123// The Mac OS compiler complains when argv is NULL unless we
124// first assign it to a locally defined variable.
125#define TRY_CATCH_CALL(context, callback, argc, argv, ...) \
126 Napi::Value* passed_argv = argv;\
127 std::vector<napi_value> args;\
128 if ((argc != 0) && (passed_argv != NULL)) {\
129 args.assign(passed_argv, passed_argv + argc);\
130 }\
131 Napi::Value res = (callback).Call(Napi::Value(context), args); \
132 if (res.IsEmpty()) return __VA_ARGS__;
133
134#define WORK_DEFINITION(name) \
135 Napi::Value name(const Napi::CallbackInfo& info); \
136 static void Work_Begin##name(Baton* baton); \
137 static void Work_##name(napi_env env, void* data); \
138 static void Work_After##name(napi_env env, napi_status status, void* data);
139
140#ifdef DEBUG
141 #define ASSERT_STATUS() assert(status == 0);
142#else
143 #define ASSERT_STATUS() (void)status;
144#endif
145
146#define CREATE_WORK(name, workerFn, afterFn) \
147 int status = napi_create_async_work(env, NULL, Napi::String::New(env, name),\
148 workerFn, afterFn, baton, &baton->request); \
149 \
150 ASSERT_STATUS(); \
151 napi_queue_async_work(env, baton->request);
152
153#define STATEMENT_BEGIN(type) \
154 assert(baton); \
155 assert(baton->stmt); \
156 assert(!baton->stmt->locked); \
157 assert(!baton->stmt->finalized); \
158 assert(baton->stmt->prepared); \
159 baton->stmt->locked = true; \
160 baton->stmt->db->pending++; \
161 auto env = baton->stmt->Env(); \
162 CREATE_WORK("sqlite3.Statement."#type, Work_##type, Work_After##type);
163
164#define STATEMENT_INIT(type) \
165 type* baton = static_cast<type*>(data); \
166 Statement* stmt = baton->stmt;
167
168#define STATEMENT_MUTEX(name) \
169 if (!stmt->db->_handle) { \
170 stmt->status = SQLITE_MISUSE; \
171 stmt->message = "Database handle is closed"; \
172 return; \
173 } \
174 sqlite3_mutex* name = sqlite3_db_mutex(stmt->db->_handle);
175
176#define STATEMENT_END() \
177 assert(stmt->locked); \
178 assert(stmt->db->pending); \
179 stmt->locked = false; \
180 stmt->db->pending--; \
181 stmt->Process(); \
182 stmt->db->Process();
183
184#define BACKUP_BEGIN(type) \
185 assert(baton); \
186 assert(baton->backup); \
187 assert(!baton->backup->locked); \
188 assert(!baton->backup->finished); \
189 assert(baton->backup->inited); \
190 baton->backup->locked = true; \
191 baton->backup->db->pending++; \
192 auto env = baton->backup->Env(); \
193 CREATE_WORK("sqlite3.Backup."#type, Work_##type, Work_After##type);
194
195#define BACKUP_INIT(type) \
196 type* baton = static_cast<type*>(data); \
197 Backup* backup = baton->backup;
198
199#define BACKUP_END() \
200 assert(backup->locked); \
201 assert(backup->db->pending); \
202 backup->locked = false; \
203 backup->db->pending--; \
204 backup->Process(); \
205 backup->db->Process();
206
207#endif
\No newline at end of file