@@ -22,6 +22,7 @@ using v8::ConstructorBehavior;
22
22
using v8::Context;
23
23
using v8::DontDelete;
24
24
using v8::Exception;
25
+ using v8::External;
25
26
using v8::Function;
26
27
using v8::FunctionCallback;
27
28
using v8::FunctionCallbackInfo;
@@ -790,6 +791,180 @@ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
790
791
args.GetReturnValue ().Set (Array::New (isolate, rows.data (), rows.size ()));
791
792
}
792
793
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
+
793
968
void StatementSync::Get (const FunctionCallbackInfo<Value>& args) {
794
969
StatementSync* stmt;
795
970
ASSIGN_OR_RETURN_UNWRAP (&stmt, args.This ());
@@ -987,6 +1162,7 @@ Local<FunctionTemplate> StatementSync::GetConstructorTemplate(
987
1162
tmpl->SetClassName (FIXED_ONE_BYTE_STRING (isolate, " StatementSync" ));
988
1163
tmpl->InstanceTemplate ()->SetInternalFieldCount (
989
1164
StatementSync::kInternalFieldCount );
1165
+ SetProtoMethod (isolate, tmpl, " iterate" , StatementSync::Iterate);
990
1166
SetProtoMethod (isolate, tmpl, " all" , StatementSync::All);
991
1167
SetProtoMethod (isolate, tmpl, " get" , StatementSync::Get);
992
1168
SetProtoMethod (isolate, tmpl, " run" , StatementSync::Run);
0 commit comments