-
Notifications
You must be signed in to change notification settings - Fork 1
/
json_patch.cr
131 lines (124 loc) · 3.66 KB
/
json_patch.cr
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
require "json"
# Patch to be able to serialize bson from parsed json
struct JSON::Any
def to_bson(bson = BSON.new)
obj = @raw
case obj
when Array
obj.each_with_index do |item, i|
case item.raw
when Array
bson.append_array(i.to_s) do |appender, child|
item.to_bson(child)
end
when Hash
bson.append_document(i.to_s) do |child|
item.to_bson(child)
end
else
bson[i.to_s] = item
end
end
when Hash
obj.each do |k, v|
case v.raw
when Array
bson.append_array(k) do |appender, child|
v.to_bson(child)
end
when Hash
bson.append_document(k) do |child|
v.to_bson(child)
end
else
bson[k] = v
end
end
end
bson
end
end
class BSON
def []=(key, value : JSON::Any)
raw = value.raw
case raw
when Array
self[key] = value.to_bson
when Hash
self[key] = value.to_bson
else
self[key] = raw
end
end
end
# Just to fix Time::Location::UTC, to remove once merged
class BSON
class Value
@handle : LibBSON::Value
getter handle
def initialize(src : LibBSON::BSONValue)
LibBSON.bson_value_copy(src, out dst)
@handle = dst
end
def finalize
LibBSON.bson_value_destroy(pointerof(@handle))
end
def value
v = @handle.value
case @handle.v_type
when LibBSON::Type::BSON_TYPE_EOD
nil
when LibBSON::Type::BSON_TYPE_DOUBLE
v.v_double
when LibBSON::Type::BSON_TYPE_UTF8
String.new(v.v_utf8.cstr, v.v_utf8.len.to_i32)
when LibBSON::Type::BSON_TYPE_DOCUMENT
BSON.from_data(Slice.new(v.v_doc.data, v.v_doc.len.to_i32))
when LibBSON::Type::BSON_TYPE_ARRAY
BSON.from_data(Slice.new(v.v_doc.data, v.v_doc.len.to_i32))
when LibBSON::Type::BSON_TYPE_UNDEFINED
raise "Deprecated BSON_TYPE_UNDEFINED must not be used"
when LibBSON::Type::BSON_TYPE_OID
oid = Pointer(LibBSON::Oid).malloc(1)
LibBSON.bson_oid_copy(pointerof(v).as(Pointer(LibBSON::Oid)), oid)
ObjectId.new(oid)
when LibBSON::Type::BSON_TYPE_BOOL
v.v_bool
when LibBSON::Type::BSON_TYPE_DATE_TIME
spec = LibC::Timespec.new
spec.tv_sec = v.v_datetime / 1000
Time.new(spec, Time::Location::UTC)
when LibBSON::Type::BSON_TYPE_NULL
nil
when LibBSON::Type::BSON_TYPE_REGEX
opts = String.new(v.v_regex.options)
modifiers = Regex::Options::None
modifiers |= Regex::Options::IGNORE_CASE if opts.index('i')
modifiers |= Regex::Options::MULTILINE if opts.index('m')
modifiers |= Regex::Options::EXTENDED if opts.index('x')
modifiers |= Regex::Options::UTF_8 if opts.index('u')
Regex.new(String.new(v.v_regex.regex), modifiers)
when LibBSON::Type::BSON_TYPE_DBPOINTER
raise "Deprecated BSON_TYPE_DBPOINTER type must not be used"
when LibBSON::Type::BSON_TYPE_CODE
Code.new(v.v_code)
when LibBSON::Type::BSON_TYPE_SYMBOL
Symbol.new String.new(v.v_symbol.symbol, v.v_symbol.len)
when LibBSON::Type::BSON_TYPE_CODEWSCOPE
Code.new(v.v_codewscope)
when LibBSON::Type::BSON_TYPE_INT32
v.v_int32
when LibBSON::Type::BSON_TYPE_TIMESTAMP
Timestamp.new v.v_timestamp
when LibBSON::Type::BSON_TYPE_INT64
v.v_int64
when LibBSON::Type::BSON_TYPE_MAXKEY
MaxKey.new
when LibBSON::Type::BSON_TYPE_MINKEY
MinKey.new
else
raise "Invalid BSON Value type #{@handle.v_type}"
end
end
end
end