@@ -21,6 +21,7 @@ import (
21
21
"encoding/json"
22
22
"errors"
23
23
"fmt"
24
+ "strconv"
24
25
"strings"
25
26
"sync"
26
27
@@ -37,6 +38,11 @@ var compositeKeySep = []byte{0x00}
37
38
var lastKeyIndicator = byte (0x01 )
38
39
var savePointKey = []byte {0x00 }
39
40
41
+ var dataWrapper = "data"
42
+ var jsonQuerySort = "sort"
43
+ var jsonQueryFields = "fields"
44
+ var jsonQuerySelector = "selector"
45
+
40
46
// VersionedDBProvider implements interface VersionedDBProvider
41
47
type VersionedDBProvider struct {
42
48
couchInstance * couchdb.CouchInstance
@@ -135,9 +141,56 @@ func (vdb *VersionedDB) GetState(namespace string, key string) (*statedb.Version
135
141
}
136
142
}
137
143
138
- ver := version .NewHeight (1 , 1 ) //TODO - version hardcoded to 1 is a temporary value for the prototype
144
+ //remove the data wrapper and return the value and version
145
+ returnValue , returnVersion := removeDataWrapper (docBytes )
146
+
147
+ return & statedb.VersionedValue {Value : returnValue , Version : & returnVersion }, nil
148
+ }
149
+
150
+ func removeDataWrapper (wrappedValue []byte ) ([]byte , version.Height ) {
151
+
152
+ //initialize the return value
153
+ returnValue := []byte {}
154
+
155
+ //initialize a default return version
156
+ returnVersion := version .NewHeight (0 , 0 )
157
+
158
+ //if this is a JSON, then remove the data wrapper
159
+ if couchdb .IsJSON (string (wrappedValue )) {
160
+
161
+ //create a generic map for the json
162
+ jsonResult := make (map [string ]interface {})
163
+
164
+ //unmarshal the selected json into the generic map
165
+ json .Unmarshal (wrappedValue , & jsonResult )
166
+
167
+ //place the result json in the data key
168
+ returnMap := jsonResult [dataWrapper ]
169
+
170
+ //marshal the mapped data. this wrappers the result in a key named "data"
171
+ returnValue , _ = json .Marshal (returnMap )
172
+
173
+ //create an array containing the blockNum and txNum
174
+ versionArray := strings .Split (fmt .Sprintf ("%s" , jsonResult ["version" ]), ":" )
175
+
176
+ //convert the blockNum from String to unsigned int
177
+ blockNum , _ := strconv .ParseUint (versionArray [0 ], 10 , 64 )
178
+
179
+ //convert the txNum from String to unsigned int
180
+ txNum , _ := strconv .ParseUint (versionArray [1 ], 10 , 64 )
181
+
182
+ //create the version based on the blockNum and txNum
183
+ returnVersion = version .NewHeight (blockNum , txNum )
184
+
185
+ } else {
186
+
187
+ //this is a binary, so decode the value and version from the binary
188
+ returnValue , returnVersion = statedb .DecodeValue (wrappedValue )
189
+
190
+ }
191
+
192
+ return returnValue , * returnVersion
139
193
140
- return & statedb.VersionedValue {Value : docBytes , Version : ver }, nil
141
194
}
142
195
143
196
// GetStateMultipleKeys implements method in VersionedDB interface
@@ -181,7 +234,7 @@ func (vdb *VersionedDB) ExecuteQuery(query string) (statedb.ResultsIterator, err
181
234
//TODO - limit is currently set at 1000, eventually this will need to be changed
182
235
//to reflect a config option and potentially return an exception if the threshold is exceeded
183
236
// skip (paging) is not utilized by fabric
184
- queryResult , err := vdb .db .QueryDocuments (query , 1000 , 0 )
237
+ queryResult , err := vdb .db .QueryDocuments (string ( ApplyQueryWrapper ( query )) , 1000 , 0 )
185
238
if err != nil {
186
239
logger .Debugf ("Error calling QueryDocuments(): %s\n " , err .Error ())
187
240
return nil , err
@@ -219,7 +272,7 @@ func (vdb *VersionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version
219
272
if couchdb .IsJSON (string (vv .Value )) {
220
273
221
274
// SaveDoc using couchdb client and use JSON format
222
- rev , err := vdb .db .SaveDoc (string (compositeKey ), "" , vv .Value , nil )
275
+ rev , err := vdb .db .SaveDoc (string (compositeKey ), "" , addVersionAndChainCodeID ( vv .Value , ns , vv . Version ) , nil )
223
276
if err != nil {
224
277
logger .Errorf ("Error during Commit(): %s\n " , err .Error ())
225
278
return err
@@ -232,23 +285,22 @@ func (vdb *VersionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version
232
285
233
286
//Create an attachment structure and load the bytes
234
287
attachment := & couchdb.Attachment {}
235
- attachment .AttachmentBytes = vv .Value
288
+ attachment .AttachmentBytes = statedb . EncodeValue ( vv .Value , vv . Version )
236
289
attachment .ContentType = "application/octet-stream"
237
290
attachment .Name = "valueBytes"
238
291
239
292
attachments := []couchdb.Attachment {}
240
293
attachments = append (attachments , * attachment )
241
294
242
295
// SaveDoc using couchdb client and use attachment to persist the binary data
243
- rev , err := vdb .db .SaveDoc (string (compositeKey ), "" , nil , attachments )
296
+ rev , err := vdb .db .SaveDoc (string (compositeKey ), "" , addVersionAndChainCodeID ( nil , ns , vv . Version ) , attachments )
244
297
if err != nil {
245
298
logger .Errorf ("Error during Commit(): %s\n " , err .Error ())
246
299
return err
247
300
}
248
301
if rev != "" {
249
302
logger .Debugf ("Saved document revision number: %s\n " , rev )
250
303
}
251
-
252
304
}
253
305
}
254
306
}
@@ -263,6 +315,33 @@ func (vdb *VersionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version
263
315
return nil
264
316
}
265
317
318
+ //addVersionAndChainCodeID adds keys for version and chaincodeID to the JSON value
319
+ func addVersionAndChainCodeID (value []byte , chaincodeID string , version * version.Height ) []byte {
320
+
321
+ //create a version mapping
322
+ jsonMap := map [string ]interface {}{"version" : fmt .Sprintf ("%v:%v" , version .BlockNum , version .TxNum )}
323
+
324
+ //add the chaincodeID
325
+ jsonMap ["chaincodeid" ] = chaincodeID
326
+
327
+ //Add the wrapped data if the value is not null
328
+ if value != nil {
329
+
330
+ //create a new genericMap
331
+ rawJSON := (* json .RawMessage )(& value )
332
+
333
+ //add the rawJSON to the map
334
+ jsonMap [dataWrapper ] = rawJSON
335
+
336
+ }
337
+
338
+ //marshal the data to a byte array
339
+ returnJSON , _ := json .Marshal (jsonMap )
340
+
341
+ return returnJSON
342
+
343
+ }
344
+
266
345
// Savepoint docid (key) for couchdb
267
346
const savepointDocID = "statedb_savepoint"
268
347
@@ -379,10 +458,12 @@ func (scanner *kvScanner) Next() (statedb.QueryResult, error) {
379
458
380
459
_ , key := splitCompositeKey ([]byte (selectedKV .ID ))
381
460
382
- //TODO - change hardcoded version (1,1) when version header is available in CouchDB
461
+ //remove the data wrapper and return the value and version
462
+ returnValue , returnVersion := removeDataWrapper (selectedKV .Value )
463
+
383
464
return & statedb.VersionedKV {
384
465
CompositeKey : statedb.CompositeKey {Namespace : scanner .namespace , Key : key },
385
- VersionedValue : statedb.VersionedValue {Value : selectedKV . Value , Version : version . NewHeight ( 1 , 1 ) }}, nil
466
+ VersionedValue : statedb.VersionedValue {Value : returnValue , Version : & returnVersion }}, nil
386
467
}
387
468
388
469
func (scanner * kvScanner ) Close () {
@@ -410,12 +491,14 @@ func (scanner *queryScanner) Next() (statedb.QueryResult, error) {
410
491
411
492
namespace , key := splitCompositeKey ([]byte (selectedResultRecord .ID ))
412
493
413
- //TODO - change hardcoded version (1,1) when version support is available in CouchDB
494
+ //remove the data wrapper and return the value and version
495
+ returnValue , returnVersion := removeDataWrapper (selectedResultRecord .Value )
496
+
414
497
return & statedb.VersionedQueryRecord {
415
498
Namespace : namespace ,
416
499
Key : key ,
417
- Version : version . NewHeight ( 1 , 1 ) ,
418
- Record : selectedResultRecord . Value }, nil
500
+ Version : & returnVersion ,
501
+ Record : returnValue }, nil
419
502
}
420
503
421
504
func (scanner * queryScanner ) Close () {
0 commit comments