aboutsummaryrefslogtreecommitdiffstats
path: root/document/src/vespa/document/datatype/structureddatatype.cpp
blob: ffd36a82cdde8c4d88ab64efada1f35b5f037ada (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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "structureddatatype.h"
#include <vespa/document/base/fieldpath.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/document/base/exceptions.h>

using vespalib::make_string;

namespace document {

StructuredDataType::StructuredDataType(vespalib::stringref name)
    : DataType(name, createId(name))
{
}

StructuredDataType::StructuredDataType(vespalib::stringref name, int dataTypeId)
    : DataType(name, dataTypeId)
{
}

bool StructuredDataType::equals(const DataType &other) const noexcept {
    return DataType::equals(other) && other.isStructured();
}

namespace {
uint32_t crappyJavaStringHash(vespalib::stringref value) {
    uint32_t h = 0;
    for (uint32_t i = 0; i < value.size(); ++i) {
        h = 31 * h + value[i];
    }
    return h;
}
}  // namespace

int32_t StructuredDataType::createId(vespalib::stringref name)
{
    if (name == "document") {
        return 8;
    }
    // This should be equal to java implementation if name only has 7-bit
    // ASCII characters. Probably screwed up otherwise, but generated ids
    // should only be used in testing anyways. In production this will be
    // set from the document manager config.
    constexpr size_t BUFFER_SIZE = 1024;
    if ((name.size() + 2) < BUFFER_SIZE) {
        char buf[BUFFER_SIZE];
        memcpy(buf, name.data(), name.size());
        buf[name.size()] = '.';
        buf[name.size() + 1] = '0';
        return crappyJavaStringHash(vespalib::stringref(buf, name.size() + 2));
    } else {
        vespalib::asciistream ost;
        ost << name << ".0";  // Hardcode version 0 (version is not supported).
        return crappyJavaStringHash(ost.str());
    }
}

void
StructuredDataType::onBuildFieldPath(FieldPath & path, vespalib::stringref remainFieldName) const
{
    vespalib::stringref currFieldName(remainFieldName);
    vespalib::stringref subFieldName;

    for (uint32_t i = 0; i < remainFieldName.size(); i++) {
        if (remainFieldName[i] == '.') {
            currFieldName = remainFieldName.substr(0, i);
            subFieldName = remainFieldName.substr(i + 1);
            break;
        } else if (remainFieldName[i] == '{' || remainFieldName[i] == '[') {
            currFieldName = remainFieldName.substr(0, i);
            subFieldName = remainFieldName.substr(i);
            break;
        }
    }

    // LOG(debug, "Field %s of datatype %s split into %s and %s",
    //     remainFieldName.c_str(), getName().c_str(), currFieldName.c_str(), subFieldName.c_str());
    if (hasField(currFieldName)) {
        const document::Field &fp = getField(currFieldName);
        fp.getDataType().buildFieldPath(path, subFieldName);

        path.insert(path.begin(), std::make_unique<FieldPathEntry>(fp));
    } else {
        throw FieldNotFoundException(currFieldName, make_string("Invalid field path '%s', no field named '%s'",
                                                                vespalib::string(remainFieldName).c_str(),
                                                                vespalib::string(currFieldName).c_str()));
    }
}

} // document