// // The link map allow to have as key the types: // STRING,SHORT,INTEGER,LONG,BYTE,DATE,DECIMAL,DATETIME,DATA,FLOAT,DOUBLE // the serialization of the linkmap is a list of entry // // +----------------------------+ // | values:link_map_entry[] | // +----------------------------+ // // link_map_entry structure // // +--------------+------------------+------------+ // | keyType:byte | keyValue:byte[] | link:LINK | // +--------------+------------------+------------+ // // keyType - is the type of the key, can be only one of the listed type. // keyValue - the value of the key serialized with the serializer of the type // link - the link value stored with the formant of a LINK // // TODO: right now only supporting string keys, but need to support the // datatypes listed above (also for EmbeddedMaps) // func (serde ORecordSerializerV0) writeLinkMap(buf *obuf.WriteBuf, m map[string]*oschema.OLink) error { // number of entries in the map err := varint.EncodeAndWriteVarInt32(buf, int32(len(m))) if err != nil { return oerror.NewTrace(err) } for k, v := range m { // keyType err = rw.WriteByte(buf, byte(oschema.STRING)) if err != nil { return oerror.NewTrace(err) } // keyValue err = varint.WriteString(buf, k) if err != nil { return oerror.NewTrace(err) } // link err = serde.writeLink(buf, v) if err != nil { return oerror.NewTrace(err) } } return nil }
// // writeEmbeddedMap serializes the EMBEDDEDMAP type. Currently, OrientDB only uses string // types for the map keys, so that is an assumption of this method as well. // func (serde ORecordSerializerV0) writeEmbeddedMap(buf *obuf.WriteBuf, m oschema.OEmbeddedMap) error { // number of entries in the map err := varint.EncodeAndWriteVarInt32(buf, int32(m.Len())) if err != nil { return oerror.NewTrace(err) } ptrPos := make([]int, 0, m.Len()) // position in buf where data ptr int needs to be written // TODO: do the map entries have to be written in any particular order? I will assume no for now keys, vals, types := m.All() /* ---[ write embedded map header ]--- */ for i, k := range keys { // key type err = rw.WriteByte(buf, byte(oschema.STRING)) if err != nil { return oerror.NewTrace(err) } // write the key value err = varint.WriteString(buf, k) if err != nil { return oerror.NewTrace(err) } ptrPos = append(ptrPos, buf.Len()) buf.Skip(4) // placeholder integer for data ptr dataType := types[i] if dataType == oschema.UNKNOWN { dataType = getDataType(vals[i]) // TODO: not sure this is necessary } // write data type of the data err = rw.WriteByte(buf, byte(dataType)) if err != nil { return oerror.NewTrace(err) } } /* ---[ write embedded map data values ]--- */ for i := 0; i < len(vals); i++ { currPos := buf.Len() buf.Seek(uint(ptrPos[i])) err = rw.WriteInt(buf, int32(currPos)) if err != nil { return oerror.NewTrace(err) } buf.Seek(uint(currPos)) err = serde.writeDataValue(buf, vals[i], types[i]) if err != nil { return oerror.NewTrace(err) } } return nil }
// // serializeDocument writes the classname and the serialized record // (header and data sections) of the ODocument to the obuf.WriteBuf. // // Because this method writes the classname but NOT the serialization // version, this method is safe for recursive calls for EMBEDDED types. // func (serde ORecordSerializerV0) serializeDocument(wbuf *obuf.WriteBuf, doc *oschema.ODocument) error { err := varint.WriteString(wbuf, doc.Classname) if err != nil { return oerror.NewTrace(err) } ogl.Debugf("serdebuf A: %v\n", wbuf.Bytes()) // DEBUG ogl.Debugf("doc A: %v\n", doc) // DEBUG return serde.writeSerializedRecord(wbuf, doc) }
// // writeDataValue is part of the Serialize functionality // TODO: change name to writeSingleValue ? // func (serde ORecordSerializerV0) writeDataValue(buf *obuf.WriteBuf, value interface{}, datatype oschema.ODataType) (err error) { switch datatype { case oschema.STRING: err = varint.WriteString(buf, value.(string)) ogl.Debugf("DEBUG STR: -writeDataVal val: %v\n", value.(string)) // DEBUG case oschema.BOOLEAN: err = rw.WriteBool(buf, value.(bool)) ogl.Debugf("DEBUG BOOL: -writeDataVal val: %v\n", value.(bool)) // DEBUG case oschema.INTEGER: var i32val int32 i32val, err = toInt32(value) if err == nil { err = varint.EncodeAndWriteVarInt32(buf, i32val) // TODO: are serialized integers ALWAYS varint encoded? ogl.Debugf("DEBUG INT: -writeDataVal val: %v\n", i32val) // DEBUG } case oschema.SHORT: // TODO: needs toInt16 conversion fn err = varint.EncodeAndWriteVarInt32(buf, int32(value.(int16))) ogl.Debugf("DEBUG SHORT: -writeDataVal val: %v\n", value.(int16)) // DEBUG case oschema.LONG: var i64val int64 i64val, err = toInt64(value) if err == nil { err = varint.EncodeAndWriteVarInt64(buf, i64val) // TODO: are serialized longs ALWAYS varint encoded? ogl.Debugf("DEBUG LONG: -writeDataVal val: %v\n", i64val) // DEBUG } case oschema.FLOAT: var f32 float32 f32, err = toFloat32(value) if err == nil { err = rw.WriteFloat(buf, f32) } ogl.Debugf("DEBUG FLOAT: -writeDataVal val: %v\n", value) // DEBUG case oschema.DOUBLE: var f64 float64 f64, err = toFloat64(value) if err == nil { err = rw.WriteDouble(buf, f64) } ogl.Debugf("DEBUG DOUBLE: -writeDataVal val: %v\n", value.(float64)) // DEBUG case oschema.DATETIME: err = writeDateTime(buf, value) ogl.Debugf("DEBUG DATETIME: -writeDataVal val: %v\n", value) // DEBUG case oschema.DATE: err = writeDate(buf, value) ogl.Debugf("DEBUG DATE: -writeDataVal val: %v\n", value) // DEBUG case oschema.BINARY: err = varint.WriteBytes(buf, value.([]byte)) ogl.Debugf("DEBUG BINARY: -writeDataVal val: %v\n", value.([]byte)) // DEBUG case oschema.EMBEDDED: err = serde.serializeDocument(buf, value.(*oschema.ODocument)) ogl.Debugf("DEBUG EMBEDDED: -writeDataVal val: %v\n", value) // DEBUG case oschema.EMBEDDEDLIST: err = serde.serializeEmbeddedCollection(buf, value.(oschema.OEmbeddedList)) ogl.Debugf("DEBUG EMBD-LIST: -writeDataVal val: %v\n", value) // DEBUG case oschema.EMBEDDEDSET: err = serde.serializeEmbeddedCollection(buf, value.(oschema.OEmbeddedList)) ogl.Debugf("DEBUG EMBD-SET: -writeDataVal val: %v\n", value) // DEBUG case oschema.EMBEDDEDMAP: err = serde.writeEmbeddedMap(buf, value.(oschema.OEmbeddedMap)) ogl.Debugf("DEBUG EMBEDDEDMAP: val %v\n", value.(oschema.OEmbeddedMap)) case oschema.LINK: err = serde.writeLink(buf, value.(*oschema.OLink)) ogl.Debugf("DEBUG LINK: val %v\n", value) // DEBUG case oschema.LINKLIST: err = serde.writeLinkList(buf, value.([]*oschema.OLink)) ogl.Debugf("DEBUG LINKLIST: val %v\n", value) // DEBUG case oschema.LINKSET: err = serde.writeLinkList(buf, value.([]*oschema.OLink)) ogl.Debugf("DEBUG LINKSET: val %v\n", value) // DEBUG case oschema.LINKMAP: err = serde.writeLinkMap(buf, value.(map[string]*oschema.OLink)) ogl.Debugf("DEBUG LINKMAP: val %v\n", value) // DEBUG case oschema.BYTE: err = rw.WriteByte(buf, value.(byte)) ogl.Debugf("DEBUG BYTE: -writeDataVal val: %v\n", value.(byte)) // DEBUG case oschema.DECIMAL: // TODO: impl me -> Java client uses BigDecimal for this panic("ORecordSerializerV0#writeDataValue DECIMAL NOT YET IMPLEMENTED") case oschema.CUSTOM: // TODO: impl me panic("ORecordSerializerV0#writeDataValue CUSTOM NOT YET IMPLEMENTED") case oschema.LINKBAG: panic("ORecordSerializerV0#writeDataValue LINKBAG NOT YET IMPLEMENTED") default: // ANY and TRANSIENT are do nothing ops } return err }
// // In Progress attempt to rewrite writeSerializedRecord and related fns // using a seekable/skipping WriteBuf // func (serde ORecordSerializerV0) writeSerializedRecord(wbuf *obuf.WriteBuf, doc *oschema.ODocument) (err error) { nfields := len(doc.FieldNames()) ptrPos := make([]int, 0, nfields) // position in buf where data ptr int needs to be written currDB := serde.dbc.GetCurrDB() oclass, ok := currDB.Classes[doc.Classname] docFields := doc.GetFields() for _, fld := range docFields { var oprop *oschema.OProperty if ok { oprop = oclass.Properties[fld.Name] } // FROM THE JAVA CLIENT: // if (properties[i] != null) { // OVarIntSerializer.write(bytes, (properties[i].getId() + 1) * -1); // if (properties[i].getType() != OType.ANY) // pos[i] = bytes.alloc(OIntegerSerializer.INT_SIZE); // else // pos[i] = bytes.alloc(OIntegerSerializer.INT_SIZE + 1); // TODO: why does ANY required an additional byte? // } else { // writeString(bytes, entry.getKey()); // pos[i] = bytes.alloc(OIntegerSerializer.INT_SIZE + 1); if oprop != nil { // if property is known in the global properties, then // just write its encoded id varint.EncodeAndWriteVarInt32(wbuf, encodeFieldIDForHeader(oprop.ID)) ptrPos = append(ptrPos, wbuf.Len()) wbuf.Skip(4) // Note: no need to write property type when writing property ID } else { // property Name err = varint.WriteString(wbuf, fld.Name) if err != nil { return oerror.NewTrace(err) } ptrPos = append(ptrPos, wbuf.Len()) wbuf.Skip(4) // property Type err = rw.WriteByte(wbuf, byte(fld.Type)) if err != nil { return oerror.NewTrace(err) } } } wbuf.WriteByte(0) // End of Header sentinel // now write out the data values for i, fld := range docFields { currPos := wbuf.Len() wbuf.Seek(uint(ptrPos[i])) err = rw.WriteInt(wbuf, int32(currPos)) if err != nil { return oerror.NewTrace(err) } wbuf.Seek(uint(currPos)) err = serde.writeDataValue(wbuf, fld.Value, fld.Type) if err != nil { return oerror.NewTrace(err) } } return nil }