github.com/RevenueMonster/sqlike@v1.0.6/jsonb/object.go (about) 1 package jsonb 2 3 import ( 4 "strings" 5 ) 6 7 // ReadObject : 8 func (r *Reader) ReadObject(cb func(*Reader, string) error) error { 9 c := r.nextToken() 10 if c != '{' { 11 return ErrInvalidJSON{ 12 callback: "ReadObject", 13 message: "expect start with { for object", 14 } 15 } 16 17 var ( 18 k string 19 err error 20 ) 21 22 for { 23 c = r.nextToken() 24 if c == '}' { 25 break 26 } 27 28 if c != '"' { 29 return ErrInvalidJSON{ 30 callback: "ReadObject", 31 message: "expect \" for object key", 32 } 33 } 34 35 k, err = r.unreadByte().ReadString() 36 if err != nil { 37 return err 38 } 39 40 c = r.nextToken() 41 if c != ':' { 42 return ErrInvalidJSON{ 43 callback: "ReadObject", 44 message: "expect : after object key", 45 } 46 } 47 48 v, err := r.ReadBytes() 49 if err != nil { 50 return err 51 } 52 53 it := NewReader(v) 54 if err := cb(it, k); err != nil { 55 return err 56 } 57 58 c = r.nextToken() 59 if c != ',' { 60 break 61 } 62 } 63 64 if c != '}' { 65 return ErrInvalidJSON{ 66 callback: "ReadObject", 67 message: "expect end with } for object", 68 } 69 } 70 return nil 71 } 72 73 // ReadFlattenObject : 74 func (r *Reader) ReadFlattenObject(cb func(*Reader, string) error) error { 75 level := 1 76 c := r.nextToken() 77 if c != '{' { 78 return ErrInvalidJSON{ 79 callback: "ReadFlattenObject", 80 message: "expect start with { for object", 81 } 82 } 83 84 var ( 85 paths []string 86 key string 87 err error 88 ) 89 90 keyLoop: 91 for { 92 c = r.nextToken() 93 if c == '}' { 94 r.unreadByte() 95 goto valueLoop 96 } 97 98 if c != '"' { 99 return ErrInvalidJSON{ 100 callback: "ReadObject", 101 message: "expect \" for object key", 102 } 103 } 104 105 key, err = r.unreadByte().ReadString() 106 if err != nil { 107 return err 108 } 109 110 paths = append(paths, key) 111 112 c = r.nextToken() 113 if c != ':' { 114 return ErrInvalidJSON{ 115 callback: "ReadObject", 116 message: "expect : after object key", 117 } 118 } 119 120 c = r.nextToken() 121 switch c { 122 case '{': 123 level++ 124 goto keyLoop 125 126 default: 127 v, err := r.unreadByte().ReadBytes() 128 if err != nil { 129 return err 130 } 131 132 k := strings.Join(paths, ".") 133 it := NewReader(v) 134 if err := cb(it, k); err != nil { 135 return err 136 } 137 } 138 139 valueLoop: 140 c = r.nextToken() 141 switch c { 142 case '}': 143 level-- 144 if level < 1 { 145 break keyLoop 146 } 147 paths = paths[:level-1] 148 c = r.nextToken() 149 if c != ',' { 150 r.unreadByte() 151 } 152 153 case ',': 154 paths = append([]string{}, paths[:len(paths)-1]...) 155 156 default: 157 break 158 159 } 160 } 161 162 if c != '}' { 163 return ErrInvalidJSON{ 164 callback: "ReadFlattenObject", 165 message: "expect end with } for object", 166 } 167 } 168 return nil 169 }