@@ -69,8 +69,8 @@ defmodule Ecto.Adapters.SQL do
6969 end
7070
7171 @ doc false
72- def stream ( repo , meta , query , params , process , opts ) do
73- Ecto.Adapters.SQL . stream ( repo , meta , query , params , process , opts )
72+ def stream ( repo , meta , query , params , process , flat_map , opts ) do
73+ Ecto.Adapters.SQL . stream ( repo , meta , query , params , process , flat_map , opts )
7474 end
7575
7676 @ doc false
@@ -136,8 +136,16 @@ defmodule Ecto.Adapters.SQL do
136136 :ok
137137 end
138138
139+ ## GenStage
140+
141+ @ doc false
142+ def stage_spec ( repo , meta , query , params , process , flat_map , opts ) do
143+ Ecto.Adapters.SQL . stage_spec ( repo , meta , query , params , process , flat_map , opts )
144+ end
145+
139146 defoverridable [ prepare: 2 , execute: 6 , insert: 6 , update: 6 , delete: 4 , insert_all: 7 ,
140- execute_ddl: 3 , loaders: 2 , dumpers: 2 , autogenerate: 1 , ensure_all_started: 2 ]
147+ execute_ddl: 3 , loaders: 2 , dumpers: 2 , autogenerate: 1 , ensure_all_started: 2 ,
148+ stage_spec: 7 ]
141149 end
142150 end
143151
@@ -477,55 +485,60 @@ defmodule Ecto.Adapters.SQL do
477485 """
478486 @ spec stream ( Ecto.Repo . t , String . t , [ term ] , Keyword . t ) :: Enum . t
479487 def stream ( repo , sql , params \\ [ ] , opts \\ [ ] ) do
480- Ecto.Adapters.SQL.Stream . __build__ ( repo , sql , params , fn x -> x end , opts )
488+ Ecto.Adapters.SQL.Stream . __build__ ( repo , sql , params , fn x -> x end , nil , opts )
481489 end
482490
483491 @ doc false
484- def stream ( repo , meta , prepared , params , mapper , opts ) do
485- do_stream ( repo , meta , prepared , params , mapper , put_source ( opts , meta ) )
492+ def stream ( repo , meta , prepared , params , mapper , flat_map , opts ) do
493+ do_stream ( repo , meta , prepared , params , mapper , flat_map , put_source ( opts , meta ) )
486494 end
487495
488- def do_stream ( repo , _meta , { :cache , _ , { _ , prepared } } , params , nil , opts ) do
489- prepare_stream ( repo , prepared , params , nil , opts )
496+ def do_stream ( repo , _meta , { :cache , _ , { _ , prepared } } , params , nil , flat_map , opts ) do
497+ prepare_stream ( repo , prepared , params , nil , flat_map , opts )
490498 end
491499
492- def do_stream ( repo , % { fields: fields , sources: sources } , { :cache , _ , { _ , prepared } } , params , process , opts ) do
500+ def do_stream ( repo , % { fields: fields , sources: sources } , { :cache , _ , { _ , prepared } } , params , process , flat_map , opts ) do
493501 mapper = & process_row ( & 1 , process , fields , sources )
494- prepare_stream ( repo , prepared , params , mapper , opts )
502+ prepare_stream ( repo , prepared , params , mapper , flat_map , opts )
495503 end
496504
497- def do_stream ( repo , _ , { :cached , _ , { _ , cached } } , params , nil , opts ) do
498- prepare_stream ( repo , String.Chars . to_string ( cached ) , params , nil , opts )
505+ def do_stream ( repo , _ , { :cached , _ , { _ , cached } } , params , nil , flat_map , opts ) do
506+ prepare_stream ( repo , String.Chars . to_string ( cached ) , params , nil , flat_map , opts )
499507 end
500508
501- def do_stream ( repo , % { fields: fields , sources: sources } , { :cached , _ , { _ , cached } } , params , process , opts ) do
509+ def do_stream ( repo , % { fields: fields , sources: sources } , { :cached , _ , { _ , cached } } , params , process , flat_map , opts ) do
502510 mapper = & process_row ( & 1 , process , fields , sources )
503- prepare_stream ( repo , String.Chars . to_string ( cached ) , params , mapper , opts )
511+ prepare_stream ( repo , String.Chars . to_string ( cached ) , params , mapper , flat_map , opts )
504512 end
505513
506- def do_stream ( repo , _meta , { :nocache , { _id , prepared } } , params , nil , opts ) do
507- prepare_stream ( repo , prepared , params , nil , opts )
514+ def do_stream ( repo , _meta , { :nocache , { _id , prepared } } , params , nil , flat_map , opts ) do
515+ prepare_stream ( repo , prepared , params , nil , flat_map , opts )
508516 end
509517
510- def do_stream ( repo , % { fields: fields , sources: sources } , { :nocache , { _id , prepared } } , params , process , opts ) do
518+ def do_stream ( repo , % { fields: fields , sources: sources } , { :nocache , { _id , prepared } } , params , process , flat_map , opts ) do
511519 mapper = & process_row ( & 1 , process , fields , sources )
512- prepare_stream ( repo , prepared , params , mapper , opts )
520+ prepare_stream ( repo , prepared , params , mapper , flat_map , opts )
513521 end
514522
515- defp prepare_stream ( repo , prepared , params , mapper , opts ) do
516- repo
517- |> Ecto.Adapters.SQL.Stream . __build__ ( prepared , params , mapper , opts )
518- |> Stream . map ( fn ( % { num_rows: nrows , rows: rows } ) -> { nrows , rows } end )
523+ defp prepare_stream ( repo , prepared , params , mapper , flat_map , opts ) do
524+ Ecto.Adapters.SQL.Stream . __build__ ( repo , prepared , params , mapper , flat_map , opts )
525+ end
526+
527+ @ doc false
528+ def stream_mapper ( conn , % { num_rows: nrows , rows: rows } , conn , flat_map ) do
529+ flat_map . ( { nrows , rows } )
519530 end
520531
521532 @ doc false
522- def reduce ( repo , statement , params , mapper , opts , acc , fun ) do
533+ def reduce ( repo , statement , params , mapper , flat_map , opts , acc , fun ) do
523534 { repo_mod , pool , default_opts } = lookup_pool ( repo )
524- opts = [ decode_mapper: mapper ] ++ with_log ( repo , params , opts ++ default_opts )
525535 case get_conn ( pool ) do
526536 nil ->
527537 raise "cannot reduce stream outside of transaction"
528538 conn ->
539+ stream_mapper = flat_map && { __MODULE__ , :stream_mapper , [ conn , flat_map ] }
540+ map_opts = [ decode_mapper: mapper , stream_mapper: stream_mapper ]
541+ opts = map_opts ++ with_log ( repo , params , opts ++ default_opts )
529542 apply ( repo_mod . __sql__ , :stream , [ conn , statement , params , opts ] )
530543 |> Enumerable . reduce ( acc , fun )
531544 end
@@ -627,29 +640,56 @@ defmodule Ecto.Adapters.SQL do
627640 end
628641 end
629642
643+ @ doc """
644+ Return child specification for `GenStage` process running query.
645+ """
646+ def stage_spec ( repo , statement , params , opts ) do
647+ stage_spec ( repo , statement , params , fn x -> x end , nil , opts )
648+ end
649+
650+ @ doc """
651+ Start link `GenStage` process running query.
652+ """
653+ def start_stage ( repo , statement , params , opts ) do
654+ case stage_spec ( repo , statement , params , opts ) do
655+ { _ , { mod , fun , args } , _ , _ , _ , _ } ->
656+ apply ( mod , fun , args )
657+ % { start: { mod , fun , args } } ->
658+ apply ( mod , fun , args )
659+ end
660+ end
661+
630662 @ doc false
631- def stage ( fun , repo , start , handle , stop , opts ) do
663+ def stage_spec ( repo , meta , prepared , params , mapper , flat_map , opts ) do
664+ stream = stream ( repo , meta , prepared , params , mapper , flat_map , opts )
665+ % Ecto.Adapters.SQL.Stream { repo: repo , statement: statement , params: params ,
666+ mapper: mapper , flat_map: flat_map , opts: opts } = stream
667+ stage_spec ( repo , statement , params , mapper , flat_map , opts )
668+ end
669+
670+ defp stage_spec ( repo , statement , params , mapper , flat_map , opts ) do
632671 { repo_mod , pool , default_opts } = lookup_pool ( repo )
633- default_opts =
634- default_opts
635- |> Keyword . delete ( :name )
636- |> Keyword . put_new ( :caller , self ( ) )
637- opts = with_log ( repo_mod , [ ] , opts ++ default_opts )
638- start =
639- fn ( conn ) ->
640- put_conn ( pool , conn )
641- start . ( )
642- end
643- handle = fn ( _ , arg , state ) -> handle . ( arg , state ) end
644- stop =
645- fn ( _ , reason , state ) ->
646- try do
647- stop . ( reason , state )
648- after
649- delete_conn ( pool )
650- end
672+ stage_opts = Keyword . delete ( default_opts , :name )
673+ stream_mapper = flat_map && { __MODULE__ , :stage_mapper , [ pool , flat_map ] }
674+ map_opts = [ decode_mapper: mapper , stream_mapper: stream_mapper ]
675+ opts = map_opts ++ with_log ( repo , params , opts ++ stage_opts )
676+ opts = Keyword . put_new ( opts , :caller , self ( ) )
677+ apply ( repo_mod . __sql__ , :stage_spec , [ pool , statement , params , opts ] )
678+ end
679+
680+ @ doc false
681+ def stage_mapper ( stream_conn , res , pool , flat_map ) do
682+ cur_conn = get_conn ( pool )
683+ try do
684+ put_conn ( pool , stream_conn )
685+ stream_mapper ( stream_conn , res , stream_conn , flat_map )
686+ after
687+ if cur_conn do
688+ put_conn ( pool , cur_conn )
689+ else
690+ delete_conn ( pool )
651691 end
652- fun . ( pool , start , handle , stop , opts )
692+ end
653693 end
654694
655695 ## Log
0 commit comments