avro-builder 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +52 -0
- data/lib/avro/builder/dsl.rb +7 -5
- data/lib/avro/builder/field.rb +12 -7
- data/lib/avro/builder/types/named_type.rb +15 -4
- data/lib/avro/builder/types/record_type.rb +91 -0
- data/lib/avro/builder/types.rb +1 -0
- data/lib/avro/builder/version.rb +1 -1
- metadata +3 -3
- data/lib/avro/builder/record.rb +0 -84
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28daf07aca9de6893dcd2ca08f78448e2a6df151
|
4
|
+
data.tar.gz: 0e3024fb6bf1caeaa24f65e79dc601802b663164
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5b7073dd2493279f98724a1c8fc96fadaee310e80109978754e461f4475966f0fdade6137d08055de80f7e9a2a945123937a4fd15f76b683a948b9d91dbb413
|
7
|
+
data.tar.gz: e577b679d984e96cb849b478306b08527f0c831fcdbede83292e760d53ac125d7c622304f80b5d2a190e867ca7a2d34f6bae3e3c27e67f97c713351eefb98dbe
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# avro-builder changelog
|
2
2
|
|
3
|
+
## v0.3.0
|
4
|
+
- Add support for nested records. This includes the ability to reference a
|
5
|
+
previously defined record as a type.
|
6
|
+
|
3
7
|
## v0.2.0
|
4
8
|
- Add support for `:union` type.
|
5
9
|
- Make `fixed` syntax more flexible. Both `fixed :f, 7` and `fixed :f, size: 7`
|
data/README.md
CHANGED
@@ -141,6 +141,58 @@ record :my_record_with_named do
|
|
141
141
|
end
|
142
142
|
```
|
143
143
|
|
144
|
+
### Nested Records
|
145
|
+
|
146
|
+
Nested records may be created by referring to the name of the previously
|
147
|
+
defined record or using the field type `:record`.
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
record :sub_rec do
|
151
|
+
required :i, :int
|
152
|
+
end
|
153
|
+
|
154
|
+
record :top_rec do
|
155
|
+
required :sub, :sub_rec
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
Definining a subrecord inline:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
record :my_rec do
|
163
|
+
required :nested, :record do
|
164
|
+
required :s, :string
|
165
|
+
end
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
Nested record types defined without an explicit name are given a generated
|
170
|
+
name based on the name of the field and record that they are nested within.
|
171
|
+
In the example above, the nested record type would have the generated name
|
172
|
+
`__my_rec_nested_record`:
|
173
|
+
|
174
|
+
```json
|
175
|
+
{
|
176
|
+
"type": "record",
|
177
|
+
"name": "my_rec",
|
178
|
+
"fields": [
|
179
|
+
{
|
180
|
+
"name": "nested",
|
181
|
+
"type": {
|
182
|
+
"type": "record",
|
183
|
+
"name": "__my_rec_nested_record",
|
184
|
+
"fields": [
|
185
|
+
{
|
186
|
+
"name": "s",
|
187
|
+
"type": "string"
|
188
|
+
}
|
189
|
+
]
|
190
|
+
}
|
191
|
+
}
|
192
|
+
]
|
193
|
+
}
|
194
|
+
```
|
195
|
+
|
144
196
|
### Unions
|
145
197
|
|
146
198
|
A union may be specified within a record using `required` and `optional` with
|
data/lib/avro/builder/dsl.rb
CHANGED
@@ -4,7 +4,6 @@ require 'avro/builder/namespaceable'
|
|
4
4
|
require 'avro/builder/type_factory'
|
5
5
|
require 'avro/builder/types'
|
6
6
|
require 'avro/builder/field'
|
7
|
-
require 'avro/builder/record'
|
8
7
|
require 'avro/builder/file_handler'
|
9
8
|
require 'avro/builder/schema_serializer_reference_state'
|
10
9
|
|
@@ -85,6 +84,8 @@ module Avro
|
|
85
84
|
def to_json(validate: true, pretty: true)
|
86
85
|
hash = to_h
|
87
86
|
(pretty ? JSON.pretty_generate(hash) : hash.to_json).tap do |json|
|
87
|
+
# Uncomment the next line to debug:
|
88
|
+
# puts json
|
88
89
|
# Parse the schema to validate before returning
|
89
90
|
::Avro::Schema.parse(json) if validate
|
90
91
|
end
|
@@ -111,10 +112,11 @@ module Avro
|
|
111
112
|
end
|
112
113
|
|
113
114
|
def build_record(name, options, &block)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
115
|
+
Avro::Builder::Types::RecordType
|
116
|
+
.new(name, options.merge(namespace: namespace)).tap do |record|
|
117
|
+
record.builder = builder
|
118
|
+
record.instance_eval(&block)
|
119
|
+
end
|
118
120
|
end
|
119
121
|
|
120
122
|
def eval_file(name)
|
data/lib/avro/builder/field.rb
CHANGED
@@ -10,15 +10,16 @@ module Avro
|
|
10
10
|
include Avro::Builder::Namespaceable
|
11
11
|
include Avro::Builder::TypeFactory
|
12
12
|
|
13
|
-
INTERNAL_ATTRIBUTES = Set.new(%i(
|
13
|
+
INTERNAL_ATTRIBUTES = Set.new(%i(optional_field)).freeze
|
14
14
|
|
15
|
-
attr_accessor :type, :
|
15
|
+
attr_accessor :type, :optional_field, :builder, :record
|
16
16
|
|
17
17
|
# These attributes may be set as options or via a block in the DSL
|
18
18
|
dsl_attributes :doc, :aliases, :default, :order
|
19
19
|
|
20
|
-
def initialize(name:, type_name:, builder:, internal: {}, options: {}, &block)
|
20
|
+
def initialize(name:, type_name:, record:, builder:, internal: {}, options: {}, &block)
|
21
21
|
@builder = builder
|
22
|
+
@record = record
|
22
23
|
@name = name.to_s
|
23
24
|
|
24
25
|
internal.each do |key, value|
|
@@ -42,8 +43,12 @@ module Avro
|
|
42
43
|
super || type.respond_to?(id, include_all)
|
43
44
|
end
|
44
45
|
|
45
|
-
def method_missing(id, *args)
|
46
|
-
type.respond_to?(id) ? type.send(id, *args) : super
|
46
|
+
def method_missing(id, *args, &block)
|
47
|
+
type.respond_to?(id) ? type.send(id, *args, &block) : super
|
48
|
+
end
|
49
|
+
|
50
|
+
def name_fragment
|
51
|
+
record.name_fragment
|
47
52
|
end
|
48
53
|
|
49
54
|
# Delegate setting name explicitly via DSL to type
|
@@ -68,10 +73,10 @@ module Avro
|
|
68
73
|
|
69
74
|
private
|
70
75
|
|
71
|
-
# Optional
|
76
|
+
# Optional fields must be serialized as a union -- an array of types.
|
72
77
|
def serialized_type(reference_state)
|
73
78
|
result = type.serialize(reference_state)
|
74
|
-
|
79
|
+
optional_field ? type.class.union_with_null(result) : result
|
75
80
|
end
|
76
81
|
end
|
77
82
|
end
|
@@ -12,10 +12,21 @@ module Avro
|
|
12
12
|
include Avro::Builder::Namespaceable
|
13
13
|
include Avro::Builder::Types::ConfigurableType
|
14
14
|
|
15
|
-
dsl_attributes :
|
15
|
+
dsl_attributes :namespace, :aliases
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
dsl_attribute :name do |value = nil|
|
18
|
+
if value
|
19
|
+
@name = value
|
20
|
+
else
|
21
|
+
@name || "__#{name_fragment}_#{type_name}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Named types that do not have an explicit name are assigned
|
26
|
+
# a named based on the field and its nesting.
|
27
|
+
def name_fragment
|
28
|
+
[field && field.name_fragment,
|
29
|
+
@name || (field && field.name)].compact.join('_')
|
19
30
|
end
|
20
31
|
|
21
32
|
# As a type for a field
|
@@ -24,7 +35,7 @@ module Avro
|
|
24
35
|
def serialize(reference_state, overrides: {})
|
25
36
|
reference_state.definition_or_reference(fullname) do
|
26
37
|
{
|
27
|
-
name:
|
38
|
+
name: name,
|
28
39
|
type: type_name,
|
29
40
|
namespace: namespace
|
30
41
|
}.merge(overrides).reject { |_, v| v.nil? }
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
module Types
|
4
|
+
# This class represents a record in an Avro schema. Records may be defined
|
5
|
+
# at the top-level or as the type for a field in a record.
|
6
|
+
class RecordType < Avro::Builder::Types::NamedType
|
7
|
+
|
8
|
+
dsl_attributes :doc
|
9
|
+
|
10
|
+
def initialize(name = nil, options = {})
|
11
|
+
@name = name
|
12
|
+
options.each do |key, value|
|
13
|
+
send(key, value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add a required field to the record
|
18
|
+
def required(name, type_name, options = {}, &block)
|
19
|
+
new_field = Avro::Builder::Field.new(name: name,
|
20
|
+
type_name: type_name,
|
21
|
+
record: self,
|
22
|
+
builder: builder,
|
23
|
+
internal: { namespace: namespace },
|
24
|
+
options: options,
|
25
|
+
&block)
|
26
|
+
add_field(new_field)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Add an optional field to the record. In Avro this is represented
|
30
|
+
# as a union of null and the type specified here.
|
31
|
+
def optional(name, type_name, options = {}, &block)
|
32
|
+
new_field = Avro::Builder::Field.new(name: name,
|
33
|
+
type_name: type_name,
|
34
|
+
record: self,
|
35
|
+
builder: builder,
|
36
|
+
internal: { namespace: namespace,
|
37
|
+
optional_field: true },
|
38
|
+
options: options,
|
39
|
+
&block)
|
40
|
+
add_field(new_field)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Adds fields from the record with the specified name to the current
|
44
|
+
# record.
|
45
|
+
def extends(name)
|
46
|
+
fields.merge!(builder.lookup(name).duplicated_fields)
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_h(reference_state = SchemaSerializerReferenceState.new)
|
50
|
+
reference_state.definition_or_reference(fullname) do
|
51
|
+
{
|
52
|
+
type: :record,
|
53
|
+
name: name,
|
54
|
+
namespace: namespace,
|
55
|
+
doc: doc,
|
56
|
+
aliases: aliases,
|
57
|
+
fields: fields.values.map { |field| field.serialize(reference_state) }
|
58
|
+
}.reject { |_, v| v.nil? }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
alias_method :serialize, :to_h
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def duplicated_fields
|
66
|
+
fields.each_with_object(Hash.new) do |(name, field), result|
|
67
|
+
field_copy = field.dup
|
68
|
+
result[name] = field_copy
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Add field, replacing any existing field with the same name.
|
75
|
+
def add_field(field)
|
76
|
+
fields[field.name] = field
|
77
|
+
end
|
78
|
+
|
79
|
+
def fields
|
80
|
+
@fields ||= {}
|
81
|
+
end
|
82
|
+
|
83
|
+
# A record may be defined as a top-level schema or as the
|
84
|
+
# type for a field.
|
85
|
+
def builder
|
86
|
+
super || field.builder
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/avro/builder/types.rb
CHANGED
@@ -3,6 +3,7 @@ require 'avro/builder/types/specific_type'
|
|
3
3
|
require 'avro/builder/types/configurable_type'
|
4
4
|
require 'avro/builder/types/type_referencer'
|
5
5
|
require 'avro/builder/types/named_type'
|
6
|
+
require 'avro/builder/types/record_type'
|
6
7
|
require 'avro/builder/types/enum_type'
|
7
8
|
require 'avro/builder/types/fixed_type'
|
8
9
|
require 'avro/builder/types/array_type'
|
data/lib/avro/builder/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: avro-builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Salsify Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro
|
@@ -117,7 +117,6 @@ files:
|
|
117
117
|
- lib/avro/builder/field.rb
|
118
118
|
- lib/avro/builder/file_handler.rb
|
119
119
|
- lib/avro/builder/namespaceable.rb
|
120
|
-
- lib/avro/builder/record.rb
|
121
120
|
- lib/avro/builder/schema_serializer_reference_state.rb
|
122
121
|
- lib/avro/builder/type_factory.rb
|
123
122
|
- lib/avro/builder/types.rb
|
@@ -127,6 +126,7 @@ files:
|
|
127
126
|
- lib/avro/builder/types/fixed_type.rb
|
128
127
|
- lib/avro/builder/types/map_type.rb
|
129
128
|
- lib/avro/builder/types/named_type.rb
|
129
|
+
- lib/avro/builder/types/record_type.rb
|
130
130
|
- lib/avro/builder/types/specific_type.rb
|
131
131
|
- lib/avro/builder/types/type.rb
|
132
132
|
- lib/avro/builder/types/type_referencer.rb
|
data/lib/avro/builder/record.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
module Avro
|
2
|
-
module Builder
|
3
|
-
# This class represents a record in an Avro schema.
|
4
|
-
class Record
|
5
|
-
include Avro::Builder::DslAttributes
|
6
|
-
include Avro::Builder::Namespaceable
|
7
|
-
|
8
|
-
attr_accessor :builder
|
9
|
-
attr_reader :name
|
10
|
-
|
11
|
-
dsl_attributes :doc, :aliases, :namespace
|
12
|
-
|
13
|
-
def initialize(name, options = {})
|
14
|
-
@name = name
|
15
|
-
options.each do |key, value|
|
16
|
-
send(key, value)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Add a required field to the record
|
21
|
-
def required(name, type_name, options = {}, &block)
|
22
|
-
new_field = Avro::Builder::Field.new(name: name,
|
23
|
-
type_name: type_name,
|
24
|
-
builder: builder,
|
25
|
-
internal: { namespace: namespace },
|
26
|
-
options: options,
|
27
|
-
&block)
|
28
|
-
add_field(new_field)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Add an optional field to the record. In Avro this is represented
|
32
|
-
# as a union of null and the type specified here.
|
33
|
-
def optional(name, type_name, options = {}, &block)
|
34
|
-
new_field = Avro::Builder::Field.new(name: name,
|
35
|
-
type_name: type_name,
|
36
|
-
builder: builder,
|
37
|
-
internal: { namespace: namespace,
|
38
|
-
optional: true },
|
39
|
-
options: options,
|
40
|
-
&block)
|
41
|
-
add_field(new_field)
|
42
|
-
end
|
43
|
-
|
44
|
-
# Adds fields from the record with the specified name to the current
|
45
|
-
# record.
|
46
|
-
def extends(name)
|
47
|
-
fields.merge!(builder.lookup(name).duplicated_fields)
|
48
|
-
end
|
49
|
-
|
50
|
-
def to_h(reference_state = SchemaSerializerReferenceState.new)
|
51
|
-
reference_state.definition_or_reference(fullname) do
|
52
|
-
{
|
53
|
-
type: :record,
|
54
|
-
name: name,
|
55
|
-
namespace: namespace,
|
56
|
-
doc: doc,
|
57
|
-
aliases: aliases,
|
58
|
-
fields: fields.values.map { |field| field.serialize(reference_state) }
|
59
|
-
}.reject { |_, v| v.nil? }
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
protected
|
64
|
-
|
65
|
-
def duplicated_fields
|
66
|
-
fields.each_with_object(Hash.new) do |(name, field), result|
|
67
|
-
field_copy = field.dup
|
68
|
-
result[name] = field_copy
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
# Add field, replacing any existing field with the same name.
|
75
|
-
def add_field(field)
|
76
|
-
fields[field.name] = field
|
77
|
-
end
|
78
|
-
|
79
|
-
def fields
|
80
|
-
@fields ||= {}
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|