@@ -280,7 +280,17 @@ static int xConflict(void* pCtx, int eConflict, sqlite3_changeset_iter* pIter) {
280280 return SQLITE_CHANGESET_ABORT;
281281}
282282
283+ static std::function<bool (std::string)> filterCallback;
284+
285+ static int xFilter (void * pCtx, const char * zTab) {
286+ if (!filterCallback) return 1 ;
287+
288+ return filterCallback (zTab) ? 1 : 0 ;
289+ }
290+
283291void DatabaseSync::ApplyChangeset (const FunctionCallbackInfo<Value>& args) {
292+ filterCallback = nullptr ;
293+
284294 DatabaseSync* db;
285295 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
286296 Environment* env = Environment::GetCurrent (args);
@@ -293,12 +303,54 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
293303 " The \" changeset\" argument must be a Uint8Array." );
294304 return ;
295305 }
306+
307+ if (args.Length () > 1 && !args[1 ]->IsUndefined ()) {
308+ if (!args[1 ]->IsObject ()) {
309+ node::THROW_ERR_INVALID_ARG_TYPE (
310+ env->isolate (),
311+ " The second argument, if provided, must be an options object." );
312+ return ;
313+ }
314+
315+ Local<Object> options = args[1 ].As <Object>();
316+ Local<String> filterKey = String::NewFromUtf8 (
317+ env->isolate (),
318+ " filter" ,
319+ v8::NewStringType::kNormal ).ToLocalChecked ();
320+
321+ if (options->HasOwnProperty (env->context (),
322+ filterKey).FromJust ()) {
323+ Local<Value> filterValue = options->Get (env->context (),
324+ filterKey).ToLocalChecked ();
325+
326+ if (!filterValue->IsFunction ()) {
327+ node::THROW_ERR_INVALID_ARG_TYPE (
328+ env->isolate (),
329+ " The \" options.filter\" argument must be a function." );
330+ return ;
331+ }
332+
333+ Local<v8::Function> filterFunc = filterValue.As <v8::Function>();
334+
335+ filterCallback = [env, filterFunc](std::string item) -> bool {
336+ Local<Value> argv[] = {
337+ String::NewFromUtf8 (env->isolate (),
338+ item.c_str (),
339+ v8::NewStringType::kNormal ).ToLocalChecked ()
340+ };
341+ Local<Value> result = filterFunc->Call (
342+ env->context (),
343+ Null (env->isolate ()), 1 , argv).ToLocalChecked ();
344+ return result->BooleanValue (env->isolate ());
345+ };
346+ }
347+ }
348+
296349 ArrayBufferViewContents<uint8_t > buf (args[0 ]);
297350 int r = sqlite3changeset_apply (db->connection_ ,
298351 buf.length (),
299352 const_cast <void *>(static_cast <const void *>(buf.data ())),
300- // TODO(louwers): allow passing filter callback
301- nullptr ,
353+ xFilter,
302354 // TODO(louwers): allow custom conflict handler
303355 xConflict,
304356 nullptr );
@@ -851,6 +903,10 @@ static void Initialize(Local<Object> target,
851903 target,
852904 " StatementSync" ,
853905 StatementSync::GetConstructorTemplate (env));
906+
907+ NODE_DEFINE_CONSTANT (target, SQLITE_CHANGESET_OMIT);
908+ NODE_DEFINE_CONSTANT (target, SQLITE_CHANGESET_REPLACE);
909+ NODE_DEFINE_CONSTANT (target, SQLITE_CHANGESET_ABORT);
854910}
855911
856912} // namespace sqlite
0 commit comments