avro_turf 0.11.0 → 1.0.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/.github/workflows/ruby.yml +1 -1
- data/.github/workflows/stale.yml +19 -0
- data/CHANGELOG.md +5 -1
- data/README.md +42 -0
- data/avro_turf.gemspec +1 -1
- data/lib/avro_turf/schema_store.rb +25 -6
- data/lib/avro_turf/version.rb +1 -1
- data/spec/schema_store_spec.rb +98 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 692b0814cd5b8fcaaf55e6d607687714ae9bc496461fe0b838253d5fbeb2d218
|
4
|
+
data.tar.gz: 506a5d9bbe91a9386b1b92eb5c7e0366ad06856615442424725a82d4834cc6a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0db4e3e78577224cdb07ca4747c759bcdaae620dc03bbcac03194941a3bdf52bc69871cfad88dc14fc8ee6fd798a34d5acab289f8c841a97581290f258213f06
|
7
|
+
data.tar.gz: 672aec874705185e68dce6c8806ccf93b18ec8c3d0f34eda074e8fca6c372d4761d682ff316d3ba3d08c4b69b61a853bdb3c31ff68d4da2f0e37463a407ca656
|
data/.github/workflows/ruby.yml
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
name: Mark stale issues and pull requests
|
2
|
+
|
3
|
+
on:
|
4
|
+
schedule:
|
5
|
+
- cron: "0 0 * * *"
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
stale:
|
9
|
+
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
|
12
|
+
steps:
|
13
|
+
- uses: actions/stale@v1
|
14
|
+
with:
|
15
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
16
|
+
stale-issue-message: 'Stale issue message'
|
17
|
+
stale-pr-message: 'Stale pull request message'
|
18
|
+
stale-issue-label: 'no-issue-activity'
|
19
|
+
stale-pr-label: 'no-pr-activity'
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -16,6 +16,48 @@ These classes have been renamed to `AvroTurf::ConfluentSchemaRegistry`,
|
|
16
16
|
|
17
17
|
The aliases for the original names will be removed in a future release.
|
18
18
|
|
19
|
+
## Note about finding nested schemas
|
20
|
+
|
21
|
+
As of AvroTurf version 0.12.0, only top-level schemas that have their own .avsc file will be loaded and resolvable by the `AvroTurf::SchemaStore#find` method. This change will likely not affect most users. However, if you use `AvroTurf::SchemaStore#load_schemas!` to pre-cache all your schemas and then rely on `AvroTurf::SchemaStore#find` to access nested schemas that are not defined by their own .avsc files, your code may stop working when you upgrade to v0.12.0.
|
22
|
+
|
23
|
+
As an example, if you have a `person` schema (defined in `my/schemas/contacts/person.avsc`) that defines a nested `address` schema like this:
|
24
|
+
|
25
|
+
```json
|
26
|
+
{
|
27
|
+
"name": "person",
|
28
|
+
"namespace": "contacts",
|
29
|
+
"type": "record",
|
30
|
+
"fields": [
|
31
|
+
{
|
32
|
+
"name": "address",
|
33
|
+
"type": {
|
34
|
+
"name": "address",
|
35
|
+
"type": "record",
|
36
|
+
"fields": [
|
37
|
+
{ "name": "addr1", "type": "string" },
|
38
|
+
{ "name": "addr2", "type": "string" },
|
39
|
+
{ "name": "city", "type": "string" },
|
40
|
+
{ "name": "zip", "type": "string" }
|
41
|
+
]
|
42
|
+
}
|
43
|
+
}
|
44
|
+
]
|
45
|
+
}
|
46
|
+
```
|
47
|
+
...this will no longer work in v0.12.0:
|
48
|
+
```ruby
|
49
|
+
store = AvroTurf::SchemaStore.new(path: 'my/schemas')
|
50
|
+
store.load_schemas!
|
51
|
+
|
52
|
+
# Accessing 'person' is correct and works fine.
|
53
|
+
person = store.find('person', 'contacts') # my/schemas/contacts/person.avsc exists
|
54
|
+
|
55
|
+
# Trying to access 'address' raises AvroTurf::SchemaNotFoundError
|
56
|
+
address = store.find('address', 'contacts') # my/schemas/contacts/address.avsc is not found
|
57
|
+
```
|
58
|
+
|
59
|
+
For details and context, see [this pull request](https://github.com/dasch/avro_turf/pull/111).
|
60
|
+
|
19
61
|
## Installation
|
20
62
|
|
21
63
|
Add this line to your application's Gemfile:
|
data/avro_turf.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
20
|
spec.add_dependency "avro", ">= 1.7.7", "< 1.10"
|
21
|
-
spec.add_dependency "excon", "~> 0.
|
21
|
+
spec.add_dependency "excon", "~> 0.71"
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 2.0"
|
24
24
|
spec.add_development_dependency "rake", "~> 13.0"
|
@@ -46,26 +46,45 @@ class AvroTurf::SchemaStore
|
|
46
46
|
|
47
47
|
# Loads single schema
|
48
48
|
# Such method is not thread-safe, do not call it of from mutex synchronization routine
|
49
|
-
def load_schema!(fullname, namespace = nil)
|
49
|
+
def load_schema!(fullname, namespace = nil, local_schemas_cache = {})
|
50
50
|
*namespace, schema_name = fullname.split(".")
|
51
51
|
schema_path = File.join(@path, *namespace, schema_name + ".avsc")
|
52
52
|
schema_json = JSON.parse(File.read(schema_path))
|
53
|
-
schema = Avro::Schema.real_parse(schema_json, @schemas)
|
54
53
|
|
54
|
+
schema = Avro::Schema.real_parse(schema_json, local_schemas_cache)
|
55
|
+
|
56
|
+
# Don't cache the parsed schema until after its fullname is validated
|
55
57
|
if schema.respond_to?(:fullname) && schema.fullname != fullname
|
56
58
|
raise AvroTurf::SchemaError, "expected schema `#{schema_path}' to define type `#{fullname}'"
|
57
59
|
end
|
58
60
|
|
61
|
+
# Cache only this new top-level schema by its fullname. It's critical
|
62
|
+
# not to make every sub-schema resolvable at the top level here because
|
63
|
+
# multiple different avsc files may define the same sub-schema, and
|
64
|
+
# if we share the @schemas cache across all parsing contexts, the Avro
|
65
|
+
# gem will raise an Avro::SchemaParseError when parsing another avsc
|
66
|
+
# file that contains a subschema with the same fullname as one
|
67
|
+
# encountered previously in a different file:
|
68
|
+
# <Avro::SchemaParseError: The name "foo.bar" is already in use.>
|
69
|
+
# Essentially, the only schemas that should be resolvable in @schemas
|
70
|
+
# are those that have their own .avsc files on disk.
|
71
|
+
@schemas[fullname] = schema
|
72
|
+
|
59
73
|
schema
|
60
74
|
rescue ::Avro::SchemaParseError => e
|
61
75
|
# This is a hack in order to figure out exactly which type was missing. The
|
62
76
|
# Avro gem ought to provide this data directly.
|
63
77
|
if e.to_s =~ /"([\w\.]+)" is not a schema we know about/
|
64
|
-
|
78
|
+
# Try to first resolve a referenced schema from disk.
|
79
|
+
# If this is successful, the Avro gem will have mutated the
|
80
|
+
# local_schemas_cache, adding all the new schemas it found.
|
81
|
+
load_schema!($1, nil, local_schemas_cache)
|
65
82
|
|
66
|
-
#
|
67
|
-
|
68
|
-
|
83
|
+
# Attempt to re-parse the original schema now that the dependency
|
84
|
+
# has been resolved and use the now-updated local_schemas_cache to
|
85
|
+
# pick up where we left off.
|
86
|
+
local_schemas_cache.delete(fullname)
|
87
|
+
load_schema!(fullname, nil, local_schemas_cache)
|
69
88
|
else
|
70
89
|
raise
|
71
90
|
end
|
data/lib/avro_turf/version.rb
CHANGED
data/spec/schema_store_spec.rb
CHANGED
@@ -198,6 +198,104 @@ describe AvroTurf::SchemaStore do
|
|
198
198
|
expect(schema.fullname).to eq "person"
|
199
199
|
end
|
200
200
|
|
201
|
+
# This test would fail under avro_turf <= v0.11.0
|
202
|
+
it "does NOT cache *nested* schemas in memory" do
|
203
|
+
FileUtils.mkdir_p("spec/schemas/test")
|
204
|
+
|
205
|
+
define_schema "test/person.avsc", <<-AVSC
|
206
|
+
{
|
207
|
+
"name": "person",
|
208
|
+
"namespace": "test",
|
209
|
+
"type": "record",
|
210
|
+
"fields": [
|
211
|
+
{
|
212
|
+
"name": "address",
|
213
|
+
"type": {
|
214
|
+
"name": "address",
|
215
|
+
"type": "record",
|
216
|
+
"fields": [
|
217
|
+
{ "name": "addr1", "type": "string" },
|
218
|
+
{ "name": "addr2", "type": "string" },
|
219
|
+
{ "name": "city", "type": "string" },
|
220
|
+
{ "name": "zip", "type": "string" }
|
221
|
+
]
|
222
|
+
}
|
223
|
+
}
|
224
|
+
]
|
225
|
+
}
|
226
|
+
AVSC
|
227
|
+
|
228
|
+
schema = store.find('person', 'test')
|
229
|
+
expect(schema.fullname).to eq "test.person"
|
230
|
+
|
231
|
+
expect { store.find('address', 'test') }.
|
232
|
+
to raise_error(AvroTurf::SchemaNotFoundError)
|
233
|
+
end
|
234
|
+
|
235
|
+
# This test would fail under avro_turf <= v0.11.0
|
236
|
+
it "allows two different avsc files to define nested sub-schemas with the same fullname" do
|
237
|
+
FileUtils.mkdir_p("spec/schemas/test")
|
238
|
+
|
239
|
+
define_schema "test/person.avsc", <<-AVSC
|
240
|
+
{
|
241
|
+
"name": "person",
|
242
|
+
"namespace": "test",
|
243
|
+
"type": "record",
|
244
|
+
"fields": [
|
245
|
+
{
|
246
|
+
"name": "location",
|
247
|
+
"type": {
|
248
|
+
"name": "location",
|
249
|
+
"type": "record",
|
250
|
+
"fields": [
|
251
|
+
{ "name": "city", "type": "string" },
|
252
|
+
{ "name": "zipcode", "type": "string" }
|
253
|
+
]
|
254
|
+
}
|
255
|
+
}
|
256
|
+
]
|
257
|
+
}
|
258
|
+
AVSC
|
259
|
+
|
260
|
+
define_schema "test/company.avsc", <<-AVSC
|
261
|
+
{
|
262
|
+
"name": "company",
|
263
|
+
"namespace": "test",
|
264
|
+
"type": "record",
|
265
|
+
"fields": [
|
266
|
+
{
|
267
|
+
"name": "headquarters",
|
268
|
+
"type": {
|
269
|
+
"name": "location",
|
270
|
+
"type": "record",
|
271
|
+
"fields": [
|
272
|
+
{ "name": "city", "type": "string" },
|
273
|
+
{ "name": "postcode", "type": "string" }
|
274
|
+
]
|
275
|
+
}
|
276
|
+
}
|
277
|
+
]
|
278
|
+
}
|
279
|
+
AVSC
|
280
|
+
|
281
|
+
company = nil
|
282
|
+
person = store.find('person', 'test')
|
283
|
+
|
284
|
+
# This should *NOT* raise the error:
|
285
|
+
# #<Avro::SchemaParseError: The name "test.location" is already in use.>
|
286
|
+
expect { company = store.find('company', 'test') }.not_to raise_error
|
287
|
+
|
288
|
+
person_location_field = person.fields_hash['location']
|
289
|
+
expect(person_location_field.type.name).to eq('location')
|
290
|
+
expect(person_location_field.type.fields_hash).to include('zipcode')
|
291
|
+
expect(person_location_field.type.fields_hash).not_to include('postcode')
|
292
|
+
|
293
|
+
company_headquarters_field = company.fields_hash['headquarters']
|
294
|
+
expect(company_headquarters_field.type.name).to eq('location')
|
295
|
+
expect(company_headquarters_field.type.fields_hash).to include('postcode')
|
296
|
+
expect(company_headquarters_field.type.fields_hash).not_to include('zipcode')
|
297
|
+
end
|
298
|
+
|
201
299
|
it "is thread safe" do
|
202
300
|
define_schema "address.avsc", <<-AVSC
|
203
301
|
{
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: avro_turf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Schierbeck
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '0.
|
39
|
+
version: '0.71'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '0.
|
46
|
+
version: '0.71'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: bundler
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -165,6 +165,7 @@ extra_rdoc_files: []
|
|
165
165
|
files:
|
166
166
|
- ".circleci/config.yml"
|
167
167
|
- ".github/workflows/ruby.yml"
|
168
|
+
- ".github/workflows/stale.yml"
|
168
169
|
- ".gitignore"
|
169
170
|
- ".rspec"
|
170
171
|
- CHANGELOG.md
|