@@ -22,6 +22,7 @@ using v8::ConstructorBehavior;
2222using v8::Context;
2323using v8::DontDelete;
2424using v8::Exception;
25+ using v8::External;
2526using v8::Function;
2627using v8::FunctionCallback;
2728using v8::FunctionCallbackInfo;
@@ -790,6 +791,180 @@ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
790791 args.GetReturnValue ().Set (Array::New (isolate, rows.data (), rows.size ()));
791792}
792793
794+ void StatementSync::IterateReturnCallback (
795+ const FunctionCallbackInfo<Value>& args) {
796+ Environment* env = Environment::GetCurrent (args);
797+ auto isolate = env->isolate ();
798+ auto context = isolate->GetCurrentContext ();
799+
800+ auto self = args.This ();
801+ // iterator has fetch all result or break, prevent next func to return result
802+ self->Set (context, env->isfinished_string (), Boolean::New (isolate, true ))
803+ .ToChecked ();
804+
805+ auto external_stmt = Local<External>::Cast (
806+ self->Get (context, env->statement_string ()).ToLocalChecked ());
807+ auto stmt = static_cast <StatementSync*>(external_stmt->Value ());
808+ if (!stmt->IsFinalized ()) {
809+ sqlite3_reset (stmt->statement_ );
810+ }
811+
812+ LocalVector<Name> keys (isolate, {env->done_string (), env->value_string ()});
813+ LocalVector<Value> values (isolate,
814+ {Boolean::New (isolate, true ), Null (isolate)});
815+
816+ DCHECK_EQ (keys.size (), values.size ());
817+ Local<Object> result = Object::New (
818+ isolate, Null (isolate), keys.data (), values.data (), keys.size ());
819+ args.GetReturnValue ().Set (result);
820+ }
821+
822+ void StatementSync::IterateNextCallback (
823+ const FunctionCallbackInfo<Value>& args) {
824+ Environment* env = Environment::GetCurrent (args);
825+ auto isolate = env->isolate ();
826+ auto context = isolate->GetCurrentContext ();
827+
828+ auto self = args.This ();
829+
830+ // skip iteration if is_finished
831+ auto is_finished = Local<Boolean>::Cast (
832+ self->Get (context, env->isfinished_string ()).ToLocalChecked ());
833+ if (is_finished->Value ()) {
834+ LocalVector<Name> keys (isolate, {env->done_string (), env->value_string ()});
835+ LocalVector<Value> values (isolate,
836+ {Boolean::New (isolate, true ), Null (isolate)});
837+
838+ DCHECK_EQ (keys.size (), values.size ());
839+ Local<Object> result = Object::New (
840+ isolate, Null (isolate), keys.data (), values.data (), keys.size ());
841+ args.GetReturnValue ().Set (result);
842+ return ;
843+ }
844+
845+ auto external_stmt = Local<External>::Cast (
846+ self->Get (context, env->statement_string ()).ToLocalChecked ());
847+ auto stmt = static_cast <StatementSync*>(external_stmt->Value ());
848+ auto num_cols =
849+ Local<Integer>::Cast (
850+ self->Get (context, env->num_cols_string ()).ToLocalChecked ())
851+ ->Value ();
852+
853+ THROW_AND_RETURN_ON_BAD_STATE (
854+ env, stmt->IsFinalized (), " statement has been finalized" );
855+
856+ int r = sqlite3_step (stmt->statement_ );
857+ if (r != SQLITE_ROW) {
858+ CHECK_ERROR_OR_THROW (
859+ env->isolate (), stmt->db_ ->Connection (), r, SQLITE_DONE, void ());
860+
861+ // cleanup when no more rows to fetch
862+ sqlite3_reset (stmt->statement_ );
863+ self->Set (context, env->isfinished_string (), Boolean::New (isolate, true ))
864+ .ToChecked ();
865+
866+ LocalVector<Name> keys (isolate, {env->done_string (), env->value_string ()});
867+ LocalVector<Value> values (isolate,
868+ {Boolean::New (isolate, true ), Null (isolate)});
869+
870+ DCHECK_EQ (keys.size (), values.size ());
871+ Local<Object> result = Object::New (
872+ isolate, Null (isolate), keys.data (), values.data (), keys.size ());
873+ args.GetReturnValue ().Set (result);
874+ return ;
875+ }
876+
877+ LocalVector<Name> row_keys (isolate);
878+ row_keys.reserve (num_cols);
879+ LocalVector<Value> row_values (isolate);
880+ row_values.reserve (num_cols);
881+ for (int i = 0 ; i < num_cols; ++i) {
882+ Local<Name> key;
883+ if (!stmt->ColumnNameToName (i).ToLocal (&key)) return ;
884+ Local<Value> val;
885+ if (!stmt->ColumnToValue (i).ToLocal (&val)) return ;
886+ row_keys.emplace_back (key);
887+ row_values.emplace_back (val);
888+ }
889+
890+ Local<Object> row = Object::New (
891+ isolate, Null (isolate), row_keys.data (), row_values.data (), num_cols);
892+
893+ LocalVector<Name> keys (isolate, {env->done_string (), env->value_string ()});
894+ LocalVector<Value> values (isolate, {Boolean::New (isolate, false ), row});
895+
896+ DCHECK_EQ (keys.size (), values.size ());
897+ Local<Object> result = Object::New (
898+ isolate, Null (isolate), keys.data (), values.data (), keys.size ());
899+ args.GetReturnValue ().Set (result);
900+ }
901+
902+ void StatementSync::Iterate (const FunctionCallbackInfo<Value>& args) {
903+ StatementSync* stmt;
904+ ASSIGN_OR_RETURN_UNWRAP (&stmt, args.This ());
905+ Environment* env = Environment::GetCurrent (args);
906+ THROW_AND_RETURN_ON_BAD_STATE (
907+ env, stmt->IsFinalized (), " statement has been finalized" );
908+ auto isolate = env->isolate ();
909+ auto context = env->context ();
910+ int r = sqlite3_reset (stmt->statement_ );
911+ CHECK_ERROR_OR_THROW (
912+ env->isolate (), stmt->db_ ->Connection (), r, SQLITE_OK, void ());
913+
914+ if (!stmt->BindParams (args)) {
915+ return ;
916+ }
917+
918+ Local<Function> next_func =
919+ Function::New (context, StatementSync::IterateNextCallback)
920+ .ToLocalChecked ();
921+ Local<Function> return_func =
922+ Function::New (context, StatementSync::IterateReturnCallback)
923+ .ToLocalChecked ();
924+
925+ LocalVector<Name> keys (isolate, {env->next_string (), env->return_string ()});
926+ LocalVector<Value> values (isolate, {next_func, return_func});
927+
928+ Local<Object> global = context->Global ();
929+ Local<Value> js_iterator;
930+ Local<Value> js_iterator_prototype;
931+ if (!global->Get (context, env->iterator_string ()).ToLocal (&js_iterator))
932+ return ;
933+ if (!js_iterator.As <Object>()
934+ ->Get (context, env->prototype_string ())
935+ .ToLocal (&js_iterator_prototype))
936+ return ;
937+
938+ DCHECK_EQ (keys.size (), values.size ());
939+ Local<Object> iterable_iterator = Object::New (
940+ isolate, js_iterator_prototype, keys.data (), values.data (), keys.size ());
941+
942+ auto num_cols_pd = v8::PropertyDescriptor (
943+ v8::Integer::New (isolate, sqlite3_column_count (stmt->statement_ )), false );
944+ num_cols_pd.set_enumerable (false );
945+ num_cols_pd.set_configurable (false );
946+ iterable_iterator
947+ ->DefineProperty (context, env->num_cols_string (), num_cols_pd)
948+ .ToChecked ();
949+
950+ auto stmt_pd =
951+ v8::PropertyDescriptor (v8::External::New (isolate, stmt), false );
952+ stmt_pd.set_enumerable (false );
953+ stmt_pd.set_configurable (false );
954+ iterable_iterator->DefineProperty (context, env->statement_string (), stmt_pd)
955+ .ToChecked ();
956+
957+ auto is_finished_pd =
958+ v8::PropertyDescriptor (v8::Boolean::New (isolate, false ), true );
959+ stmt_pd.set_enumerable (false );
960+ stmt_pd.set_configurable (false );
961+ iterable_iterator
962+ ->DefineProperty (context, env->isfinished_string (), is_finished_pd)
963+ .ToChecked ();
964+
965+ args.GetReturnValue ().Set (iterable_iterator);
966+ }
967+
793968void StatementSync::Get (const FunctionCallbackInfo<Value>& args) {
794969 StatementSync* stmt;
795970 ASSIGN_OR_RETURN_UNWRAP (&stmt, args.This ());
@@ -987,6 +1162,7 @@ Local<FunctionTemplate> StatementSync::GetConstructorTemplate(
9871162 tmpl->SetClassName (FIXED_ONE_BYTE_STRING (isolate, " StatementSync" ));
9881163 tmpl->InstanceTemplate ()->SetInternalFieldCount (
9891164 StatementSync::kInternalFieldCount );
1165+ SetProtoMethod (isolate, tmpl, " iterate" , StatementSync::Iterate);
9901166 SetProtoMethod (isolate, tmpl, " all" , StatementSync::All);
9911167 SetProtoMethod (isolate, tmpl, " get" , StatementSync::Get);
9921168 SetProtoMethod (isolate, tmpl, " run" , StatementSync::Run);
0 commit comments