aboutsummaryrefslogtreecommitdiffstats
path: root/document/src/vespa/document/update/assignvalueupdate.cpp
blob: 32bded8cfd739133283a25dfa70a2914431aac35 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "assignvalueupdate.h"
#include <vespa/document/base/field.h>
#include <vespa/document/fieldvalue/fieldvalues.h>
#include <vespa/document/serialization/vespadocumentdeserializer.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/xmlstream.h>
#include <ostream>

using vespalib::IllegalArgumentException;
using vespalib::IllegalStateException;
using vespalib::nbostream;
using namespace vespalib::xml;

namespace document {

AssignValueUpdate::AssignValueUpdate()
    : ValueUpdate(Assign),
      _value()
{}

AssignValueUpdate::AssignValueUpdate(std::unique_ptr<FieldValue> value)
    : ValueUpdate(Assign),
      _value(std::move(value))
{
}
AssignValueUpdate::~AssignValueUpdate() = default;

// Declare content bits.
static const unsigned char CONTENT_HASVALUE = 0x01;

bool
AssignValueUpdate::operator==(const ValueUpdate& other) const
{
    if (other.getType() != Assign) return false;
    const AssignValueUpdate& o(static_cast<const AssignValueUpdate&>(other));
    if (_value && o._value) {
        return *_value == *o._value;
    } else {
        return bool(_value) == bool(o._value);
    }
}

// Ensure that this update is compatible with given field.
void
AssignValueUpdate::checkCompatibility(const Field& field) const
{
        // If equal datatype we know it is ok.
    if (!_value || field.getDataType().isValueType(*_value)) {
        return;
    }
        // Deny all assignments to non-equal types
    throw IllegalArgumentException(vespalib::make_string(
            "Failed to assign field value of type %s to value of type %s.",
            _value->getDataType()->toString().c_str(),
            field.getDataType().toString().c_str()), VESPA_STRLOC);
}

// Print this update as a human readable string.
void
AssignValueUpdate::print(std::ostream& out, bool verbose, const std::string& indent) const
{
    out << indent << "AssignValueUpdate(";
    if (_value) _value->print(out, verbose, indent);
    out << ")";
}

// Apply this update to the given document.
bool
AssignValueUpdate::applyTo(FieldValue& value) const
{
    if (_value && (_value->getDataType() != value.getDataType()) &&
        ((value.getDataType() == nullptr) ||
         !value.getDataType()->isValueType(*_value))) {
        vespalib::string err = vespalib::make_string(
                "Unable to assign a \"%s\" value to a \"%s\" field value.",
                _value->className(), value.className());
        throw IllegalStateException(err, VESPA_STRLOC);	
    }
    if (_value) {
        value.assign(*_value);
    }
    return bool(_value);
}

void
AssignValueUpdate::printXml(XmlOutputStream& xos) const
{
    xos << XmlTag("assign");
    if (_value) {
        _value->printXml(xos);
    }
    xos << XmlEndTag();
}

// Deserialize this update from the given buffer.
void
AssignValueUpdate::deserialize(const DocumentTypeRepo& repo, const DataType& type, nbostream & stream)
{
    // Read content bit vector.
    uint8_t content = 0x00;
    stream >> content;

    // Read field value, if any.
    if (content & CONTENT_HASVALUE) {
        _value.reset(type.createFieldValue().release());
        VespaDocumentDeserializer deserializer(repo, stream, Document::getNewestSerializationVersion());
        deserializer.read(*_value);
    }
}

}  // namespace document