@@ -335,13 +335,19 @@ func (res ResultSet) Scan(v interface{}) error {
335335}
336336
337337// Scan scans the rows into the given value.
338- func (res ResultSet ) scanRow (row * nebula.Row , colNames []string , t reflect.Type ) (reflect.Value , error ) {
338+ func (res ResultSet ) scanRow (row * nebula.Row , colNames []string , rowType reflect.Type ) (reflect.Value , error ) {
339339 rowVals := row .GetValues ()
340340
341- val := reflect .New (t ).Elem ()
341+ var result reflect.Value
342+ if rowType .Kind () == reflect .Ptr {
343+ result = reflect .New (rowType .Elem ())
344+ } else {
345+ result = reflect .New (rowType ).Elem ()
346+ }
347+ structVal := reflect .Indirect (result )
342348
343- for fIdx := 0 ; fIdx < t .NumField (); fIdx ++ {
344- f := t .Field (fIdx )
349+ for fIdx := 0 ; fIdx < structVal . Type () .NumField (); fIdx ++ {
350+ f := structVal . Type () .Field (fIdx )
345351 tag := f .Tag .Get ("nebula" )
346352
347353 if tag == "" {
@@ -356,31 +362,147 @@ func (res ResultSet) scanRow(row *nebula.Row, colNames []string, t reflect.Type)
356362
357363 rowVal := rowVals [cIdx ]
358364
359- switch f .Type .Kind () {
360- case reflect .Bool :
361- val .Field (fIdx ).SetBool (rowVal .GetBVal ())
362- case reflect .Int :
363- val .Field (fIdx ).SetInt (rowVal .GetIVal ())
364- case reflect .Int8 :
365- val .Field (fIdx ).SetInt (rowVal .GetIVal ())
366- case reflect .Int16 :
367- val .Field (fIdx ).SetInt (rowVal .GetIVal ())
368- case reflect .Int32 :
369- val .Field (fIdx ).SetInt (rowVal .GetIVal ())
370- case reflect .Int64 :
371- val .Field (fIdx ).SetInt (rowVal .GetIVal ())
372- case reflect .Float32 :
373- val .Field (fIdx ).SetFloat (rowVal .GetFVal ())
374- case reflect .Float64 :
375- val .Field (fIdx ).SetFloat (rowVal .GetFVal ())
376- case reflect .String :
377- val .Field (fIdx ).SetString (string (rowVal .GetSVal ()))
378- default :
379- return val , errors .New ("scan: not support type" )
365+ if f .Type .Kind () == reflect .Slice {
366+ list := rowVal .GetLVal ()
367+ err := scanListCol (list .Values , structVal .Field (fIdx ), f .Type )
368+ if err != nil {
369+ return result , err
370+ }
371+ } else {
372+ err := scanPrimitiveCol (rowVal , structVal .Field (fIdx ), f .Type .Kind ())
373+ if err != nil {
374+ return result , err
375+ }
376+ }
377+ }
378+
379+ return result , nil
380+ }
381+
382+ func scanListCol (vals []* nebula.Value , listVal reflect.Value , sliceType reflect.Type ) error {
383+ switch sliceType .Elem ().Kind () {
384+ case reflect .Struct :
385+ var listCol = reflect .MakeSlice (sliceType , 0 , len (vals ))
386+ for _ , val := range vals {
387+ ele := reflect .New (sliceType .Elem ()).Elem ()
388+ err := scanStructField (val , ele , sliceType .Elem ())
389+ if err != nil {
390+ return err
391+ }
392+ listCol = reflect .Append (listCol , ele )
393+ }
394+ listVal .Set (listCol )
395+ case reflect .Ptr :
396+ var listCol = reflect .MakeSlice (sliceType , 0 , len (vals ))
397+ for _ , val := range vals {
398+ ele := reflect .New (sliceType .Elem ().Elem ())
399+ err := scanStructField (val , reflect .Indirect (ele ), sliceType .Elem ().Elem ())
400+ if err != nil {
401+ return err
402+ }
403+ listCol = reflect .Append (listCol , ele )
380404 }
405+ listVal .Set (listCol )
406+ default :
407+ return errors .New ("scan: not support list type" )
381408 }
382409
383- return val , nil
410+ return nil
411+ }
412+
413+ func scanStructField (val * nebula.Value , eleVal reflect.Value , eleType reflect.Type ) error {
414+ vertex := val .GetVVal ()
415+ if vertex != nil {
416+ tags := vertex .GetTags ()
417+ vid := vertex .GetVid ()
418+
419+ if len (tags ) != 0 {
420+ tag := tags [0 ]
421+
422+ props := tag .GetProps ()
423+ props ["_vid" ] = vid
424+ tagName := tag .GetName ()
425+ props ["_tag_name" ] = & nebula.Value {SVal : tagName }
426+
427+ err := scanValFromProps (props , eleVal , eleType )
428+ if err != nil {
429+ return err
430+ }
431+ return nil
432+ }
433+ // no tags, continue
434+ }
435+
436+ edge := val .GetEVal ()
437+ if edge != nil {
438+ props := edge .GetProps ()
439+
440+ src := edge .GetSrc ()
441+ dst := edge .GetDst ()
442+ name := edge .GetName ()
443+ props ["_src" ] = src
444+ props ["_dst" ] = dst
445+ props ["_name" ] = & nebula.Value {SVal : name }
446+
447+ err := scanValFromProps (props , eleVal , eleType )
448+ if err != nil {
449+ return err
450+ }
451+ return nil
452+ }
453+
454+ return nil
455+ }
456+
457+ func scanValFromProps (props map [string ]* nebula.Value , val reflect.Value , tpe reflect.Type ) error {
458+ for fIdx := 0 ; fIdx < tpe .NumField (); fIdx ++ {
459+ f := tpe .Field (fIdx )
460+ n := f .Tag .Get ("nebula" )
461+ v , ok := props [n ]
462+ if ! ok {
463+ continue
464+ }
465+ err := scanPrimitiveCol (v , val .Field (fIdx ), f .Type .Kind ())
466+ if err != nil {
467+ return err
468+ }
469+ }
470+
471+ return nil
472+ }
473+
474+ func scanPrimitiveCol (rowVal * nebula.Value , val reflect.Value , kind reflect.Kind ) error {
475+ w := ValueWrapper {value : rowVal }
476+ if w .IsNull () || w .IsEmpty () {
477+ // SetZero is introduced in go 1.20
478+ // val.SetZero()
479+ return nil
480+ }
481+
482+ switch kind {
483+ case reflect .Bool :
484+ val .SetBool (rowVal .GetBVal ())
485+ case reflect .Int :
486+ val .SetInt (rowVal .GetIVal ())
487+ case reflect .Int8 :
488+ val .SetInt (rowVal .GetIVal ())
489+ case reflect .Int16 :
490+ val .SetInt (rowVal .GetIVal ())
491+ case reflect .Int32 :
492+ val .SetInt (rowVal .GetIVal ())
493+ case reflect .Int64 :
494+ val .SetInt (rowVal .GetIVal ())
495+ case reflect .Float32 :
496+ val .SetFloat (rowVal .GetFVal ())
497+ case reflect .Float64 :
498+ val .SetFloat (rowVal .GetFVal ())
499+ case reflect .String :
500+ val .SetString (string (rowVal .GetSVal ()))
501+ default :
502+ return errors .New ("scan: not support primitive type" )
503+ }
504+
505+ return nil
384506}
385507
386508// Returns the number of total rows
0 commit comments