1 | #ifndef NODE_SQLITE3_SRC_MACROS_H
|
2 | #define NODE_SQLITE3_SRC_MACROS_H
|
3 |
|
4 | const char* sqlite_code_string(int code);
|
5 | const char* sqlite_authorizer_string(int type);
|
6 | #include <vector>
|
7 |
|
8 |
|
9 | #include <napi.h>
|
10 | inline 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 |
|
16 | inline 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 |
|
124 |
|
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 |