| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 4e4ffea commit b68524e
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -408,13 +408,23 @@ Opens the database specified in the `path` argument of the `DatabaseSync` | |||
| 408 | 408 | constructor. This method should only be used when the database is not opened via | |
| 409 | 409 | the constructor. An exception is thrown if the database is already open. | |
| 410 | 410 | ||
| 411 | - ### `database.prepare(sql)` | ||
| 411 | + ### `database.prepare(sql[, options])` | ||
| 412 | 412 | ||
| 413 | 413 | <!-- YAML | |
| 414 | 414 | added: v22.5.0 | |
| 415 | 415 | --> | |
| 416 | 416 | ||
| 417 | 417 | * `sql` {string} A SQL string to compile to a prepared statement. | |
| 418 | + * `options` {Object} Optional configuration for the prepared statement. | ||
| 419 | + * `readBigInts` {boolean} If `true`, integer fields are read as `BigInt`s. | ||
| 420 | + **Default:** inherited from database options or `false`. | ||
| 421 | + * `returnArrays` {boolean} If `true`, results are returned as arrays. | ||
| 422 | + **Default:** inherited from database options or `false`. | ||
| 423 | + * `allowBareNamedParameters` {boolean} If `true`, allows binding named | ||
| 424 | + parameters without the prefix character. **Default:** inherited from | ||
| 425 | + database options or `true`. | ||
| 426 | + * `allowUnknownNamedParameters` {boolean} If `true`, unknown named parameters | ||
| 427 | + are ignored. **Default:** inherited from database options or `false`. | ||
| 418 | 428 | * Returns: {StatementSync} The prepared statement. | |
| 419 | 429 | ||
| 420 | 430 | Compiles a SQL statement into a [prepared statement][]. This method is a wrapper | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1075,6 +1075,92 @@ void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) { | |||
| 1075 | 1075 | return; | |
| 1076 | 1076 | } | |
| 1077 | 1077 | ||
| 1078 | + std::optional<bool> return_arrays; | ||
| 1079 | + std::optional<bool> use_big_ints; | ||
| 1080 | + std::optional<bool> allow_bare_named_params; | ||
| 1081 | + std::optional<bool> allow_unknown_named_params; | ||
| 1082 | + | ||
| 1083 | + if (args.Length() > 1 && !args[1]->IsUndefined()) { | ||
| 1084 | + if (!args[1]->IsObject()) { | ||
| 1085 | + THROW_ERR_INVALID_ARG_TYPE(env->isolate(), | ||
| 1086 | + "The \"options\" argument must be an object."); | ||
| 1087 | + return; | ||
| 1088 | + } | ||
| 1089 | + Local<Object> options = args[1].As<Object>(); | ||
| 1090 | + | ||
| 1091 | + Local<Value> return_arrays_v; | ||
| 1092 | + if (!options | ||
| 1093 | + ->Get(env->context(), | ||
| 1094 | + FIXED_ONE_BYTE_STRING(env->isolate(), "returnArrays")) | ||
| 1095 | + .ToLocal(&return_arrays_v)) { | ||
| 1096 | + return; | ||
| 1097 | + } | ||
| 1098 | + if (!return_arrays_v->IsUndefined()) { | ||
| 1099 | + if (!return_arrays_v->IsBoolean()) { | ||
| 1100 | + THROW_ERR_INVALID_ARG_TYPE( | ||
| 1101 | + env->isolate(), | ||
| 1102 | + "The \"options.returnArrays\" argument must be a boolean."); | ||
| 1103 | + return; | ||
| 1104 | + } | ||
| 1105 | + return_arrays = return_arrays_v->IsTrue(); | ||
| 1106 | + } | ||
| 1107 | + | ||
| 1108 | + Local<Value> read_big_ints_v; | ||
| 1109 | + if (!options | ||
| 1110 | + ->Get(env->context(), | ||
| 1111 | + FIXED_ONE_BYTE_STRING(env->isolate(), "readBigInts")) | ||
| 1112 | + .ToLocal(&read_big_ints_v)) { | ||
| 1113 | + return; | ||
| 1114 | + } | ||
| 1115 | + if (!read_big_ints_v->IsUndefined()) { | ||
| 1116 | + if (!read_big_ints_v->IsBoolean()) { | ||
| 1117 | + THROW_ERR_INVALID_ARG_TYPE( | ||
| 1118 | + env->isolate(), | ||
| 1119 | + "The \"options.readBigInts\" argument must be a boolean."); | ||
| 1120 | + return; | ||
| 1121 | + } | ||
| 1122 | + use_big_ints = read_big_ints_v->IsTrue(); | ||
| 1123 | + } | ||
| 1124 | + | ||
| 1125 | + Local<Value> allow_bare_named_params_v; | ||
| 1126 | + if (!options | ||
| 1127 | + ->Get(env->context(), | ||
| 1128 | + FIXED_ONE_BYTE_STRING(env->isolate(), | ||
| 1129 | + "allowBareNamedParameters")) | ||
| 1130 | + .ToLocal(&allow_bare_named_params_v)) { | ||
| 1131 | + return; | ||
| 1132 | + } | ||
| 1133 | + if (!allow_bare_named_params_v->IsUndefined()) { | ||
| 1134 | + if (!allow_bare_named_params_v->IsBoolean()) { | ||
| 1135 | + THROW_ERR_INVALID_ARG_TYPE( | ||
| 1136 | + env->isolate(), | ||
| 1137 | + "The \"options.allowBareNamedParameters\" argument must be a " | ||
| 1138 | + "boolean."); | ||
| 1139 | + return; | ||
| 1140 | + } | ||
| 1141 | + allow_bare_named_params = allow_bare_named_params_v->IsTrue(); | ||
| 1142 | + } | ||
| 1143 | + | ||
| 1144 | + Local<Value> allow_unknown_named_params_v; | ||
| 1145 | + if (!options | ||
| 1146 | + ->Get(env->context(), | ||
| 1147 | + FIXED_ONE_BYTE_STRING(env->isolate(), | ||
| 1148 | + "allowUnknownNamedParameters")) | ||
| 1149 | + .ToLocal(&allow_unknown_named_params_v)) { | ||
| 1150 | + return; | ||
| 1151 | + } | ||
| 1152 | + if (!allow_unknown_named_params_v->IsUndefined()) { | ||
| 1153 | + if (!allow_unknown_named_params_v->IsBoolean()) { | ||
| 1154 | + THROW_ERR_INVALID_ARG_TYPE( | ||
| 1155 | + env->isolate(), | ||
| 1156 | + "The \"options.allowUnknownNamedParameters\" argument must be a " | ||
| 1157 | + "boolean."); | ||
| 1158 | + return; | ||
| 1159 | + } | ||
| 1160 | + allow_unknown_named_params = allow_unknown_named_params_v->IsTrue(); | ||
| 1161 | + } | ||
| 1162 | + } | ||
| 1163 | + | ||
| 1078 | 1164 | Utf8Value sql(env->isolate(), args[0].As<String>()); | |
| 1079 | 1165 | sqlite3_stmt* s = nullptr; | |
| 1080 | 1166 | int r = sqlite3_prepare_v2(db->connection_, *sql, -1, &s, 0); | |
@@ -1083,6 +1169,20 @@ void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) { | |||
| 1083 | 1169 | BaseObjectPtr<StatementSync> stmt = | |
| 1084 | 1170 | StatementSync::Create(env, BaseObjectPtr<DatabaseSync>(db), s); | |
| 1085 | 1171 | db->statements_.insert(stmt.get()); | |
| 1172 | + | ||
| 1173 | + if (return_arrays.has_value()) { | ||
| 1174 | + stmt->return_arrays_ = return_arrays.value(); | ||
| 1175 | + } | ||
| 1176 | + if (use_big_ints.has_value()) { | ||
| 1177 | + stmt->use_big_ints_ = use_big_ints.value(); | ||
| 1178 | + } | ||
| 1179 | + if (allow_bare_named_params.has_value()) { | ||
| 1180 | + stmt->allow_bare_named_params_ = allow_bare_named_params.value(); | ||
| 1181 | + } | ||
| 1182 | + if (allow_unknown_named_params.has_value()) { | ||
| 1183 | + stmt->allow_unknown_named_params_ = allow_unknown_named_params.value(); | ||
| 1184 | + } | ||
| 1185 | + | ||
| 1086 | 1186 | args.GetReturnValue().Set(stmt->object()); | |
| 1087 | 1187 | } | |
| 1088 | 1188 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -205,6 +205,7 @@ class StatementSync : public BaseObject { | |||
| 205 | 205 | bool BindParams(const v8::FunctionCallbackInfo<v8::Value>& args); | |
| 206 | 206 | bool BindValue(const v8::Local<v8::Value>& value, const int index); | |
| 207 | 207 | ||
| 208 | + friend class DatabaseSync; | ||
| 208 | 209 | friend class StatementSyncIterator; | |
| 209 | 210 | }; | |
| 210 | 211 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -119,3 +119,103 @@ suite('StatementSync.prototype.setAllowUnknownNamedParameters()', () => { | |||
| 119 | 119 | }); | |
| 120 | 120 | }); | |
| 121 | 121 | }); | |
| 122 | + | ||
| 123 | + suite('options.allowUnknownNamedParameters', () => { | ||
| 124 | + test('unknown named parameters are allowed when input is true', (t) => { | ||
| 125 | + const db = new DatabaseSync(':memory:'); | ||
| 126 | + t.after(() => { db.close(); }); | ||
| 127 | + const setup = db.exec( | ||
| 128 | + 'CREATE TABLE data(key INTEGER, val INTEGER) STRICT;' | ||
| 129 | + ); | ||
| 130 | + t.assert.strictEqual(setup, undefined); | ||
| 131 | + const stmt = db.prepare( | ||
| 132 | + 'INSERT INTO data (key, val) VALUES ($k, $v)', | ||
| 133 | + { allowUnknownNamedParameters: true } | ||
| 134 | + ); | ||
| 135 | + const params = { $a: 1, $b: 2, $k: 42, $y: 25, $v: 84, $z: 99 }; | ||
| 136 | + t.assert.deepStrictEqual( | ||
| 137 | + stmt.run(params), | ||
| 138 | + { changes: 1, lastInsertRowid: 1 }, | ||
| 139 | + ); | ||
| 140 | + }); | ||
| 141 | + | ||
| 142 | + test('unknown named parameters throw when input is false', (t) => { | ||
| 143 | + const db = new DatabaseSync(':memory:'); | ||
| 144 | + t.after(() => { db.close(); }); | ||
| 145 | + const setup = db.exec( | ||
| 146 | + 'CREATE TABLE data(key INTEGER, val INTEGER) STRICT;' | ||
| 147 | + ); | ||
| 148 | + t.assert.strictEqual(setup, undefined); | ||
| 149 | + const stmt = db.prepare( | ||
| 150 | + 'INSERT INTO data (key, val) VALUES ($k, $v)', | ||
| 151 | + { allowUnknownNamedParameters: false } | ||
| 152 | + ); | ||
| 153 | + const params = { $a: 1, $b: 2, $k: 42, $y: 25, $v: 84, $z: 99 }; | ||
| 154 | + t.assert.throws(() => { | ||
| 155 | + stmt.run(params); | ||
| 156 | + }, { | ||
| 157 | + code: 'ERR_INVALID_STATE', | ||
| 158 | + message: /Unknown named parameter '\$a'/, | ||
| 159 | + }); | ||
| 160 | + }); | ||
| 161 | + | ||
| 162 | + test('unknown named parameters throws error by default', (t) => { | ||
| 163 | + const db = new DatabaseSync(':memory:'); | ||
| 164 | + t.after(() => { db.close(); }); | ||
| 165 | + const setup = db.exec( | ||
| 166 | + 'CREATE TABLE data(key INTEGER, val INTEGER) STRICT;' | ||
| 167 | + ); | ||
| 168 | + t.assert.strictEqual(setup, undefined); | ||
| 169 | + const stmt = db.prepare('INSERT INTO data (key, val) VALUES ($k, $v)'); | ||
| 170 | + const params = { $a: 1, $b: 2, $k: 42, $y: 25, $v: 84, $z: 99 }; | ||
| 171 | + t.assert.throws(() => { | ||
| 172 | + stmt.run(params); | ||
| 173 | + }, { | ||
| 174 | + code: 'ERR_INVALID_STATE', | ||
| 175 | + message: /Unknown named parameter '\$a'/, | ||
| 176 | + }); | ||
| 177 | + }); | ||
| 178 | + | ||
| 179 | + test('throws when option is not a boolean', (t) => { | ||
| 180 | + const db = new DatabaseSync(':memory:'); | ||
| 181 | + t.after(() => { db.close(); }); | ||
| 182 | + const setup = db.exec( | ||
| 183 | + 'CREATE TABLE data(key INTEGER PRIMARY KEY, val INTEGER) STRICT;' | ||
| 184 | + ); | ||
| 185 | + t.assert.strictEqual(setup, undefined); | ||
| 186 | + t.assert.throws(() => { | ||
| 187 | + db.prepare( | ||
| 188 | + 'INSERT INTO data (key, val) VALUES ($k, $v)', | ||
| 189 | + { allowUnknownNamedParameters: 'true' } | ||
| 190 | + ); | ||
| 191 | + }, { | ||
| 192 | + code: 'ERR_INVALID_ARG_TYPE', | ||
| 193 | + message: /The "options\.allowUnknownNamedParameters" argument must be a boolean/, | ||
| 194 | + }); | ||
| 195 | + }); | ||
| 196 | + | ||
| 197 | + test('setAllowUnknownNamedParameters can override prepare option', (t) => { | ||
| 198 | + const db = new DatabaseSync(':memory:'); | ||
| 199 | + t.after(() => { db.close(); }); | ||
| 200 | + const setup = db.exec( | ||
| 201 | + 'CREATE TABLE data(key INTEGER, val INTEGER) STRICT;' | ||
| 202 | + ); | ||
| 203 | + t.assert.strictEqual(setup, undefined); | ||
| 204 | + const stmt = db.prepare( | ||
| 205 | + 'INSERT INTO data (key, val) VALUES ($k, $v)', | ||
| 206 | + { allowUnknownNamedParameters: true } | ||
| 207 | + ); | ||
| 208 | + const params = { $a: 1, $b: 2, $k: 42, $y: 25, $v: 84, $z: 99 }; | ||
| 209 | + t.assert.deepStrictEqual( | ||
| 210 | + stmt.run(params), | ||
| 211 | + { changes: 1, lastInsertRowid: 1 }, | ||
| 212 | + ); | ||
| 213 | + t.assert.strictEqual(stmt.setAllowUnknownNamedParameters(false), undefined); | ||
| 214 | + t.assert.throws(() => { | ||
| 215 | + stmt.run(params); | ||
| 216 | + }, { | ||
| 217 | + code: 'ERR_INVALID_STATE', | ||
| 218 | + message: /Unknown named parameter '\$a'/, | ||
| 219 | + }); | ||
| 220 | + }); | ||
| 221 | + }); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments