geopolitical 3.2.0 → 3.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6eab76b546c1fe68a2b74c24193504f349c650ef97a5982cc87ee5fb74769d4e
4
- data.tar.gz: 3301e6d264d6446a0663941819b76b64f956e83f89a16e5bcf70f87644abe616
3
+ metadata.gz: 29f0c0d286b916e4998c96f873a2ca71309cebdb24b5237d0d2a9983fb6a0b78
4
+ data.tar.gz: dc3f5db9a230f9ce51716fd93d41b47f36435bc8a319028399d9980dacd74616
5
5
  SHA512:
6
- metadata.gz: e4b582dacaf75fe5584450b61ee55d05bab5e15565ee7ee31c0104a852fcd1d28853fef45aa11c5de67bc48d9be8f18997789032fed639dd4deba8a5cd8e45ad
7
- data.tar.gz: 1461b8bf452628a21c708f7c884d72301d0ac421079671b554e1aa2d4816064adafde8595c95c988936b52f85b5996c37bd27e08c00ee8e1d31461f88c200e68
6
+ metadata.gz: 5d5bf693346187061b119960d60de605a1eca32b8a56fd29d9b18273292d826c99b8c06d778b070db3a6dcbc0966263626aa5cfe64de35cee09f0573438a58ed
7
+ data.tar.gz: 547960a20a10bdba9e01af25e1ed8c9809c2a7f5e25330ff3cea774fc051a2f00380dc574eaff71ad4fde17b95a4a70f6f1be4203e33069f93e6c366da3d578d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.2.1
4
+
5
+ - Every uniqueness validation now has a unique index behind it, so concurrent writes can't slip a duplicate past the check:
6
+ - `Nation` abbr: unique (the writer upcases, so it is case-insensitive).
7
+ - `City` name: unique on `{nation_id, region_id, name}`, the validation's own scope.
8
+ - `Region` abbr within a nation: partial on `abbr > ""` instead of sparse. Sparse did nothing on a compound index whose `nation_id` is always set, so the second abbr-less region in a nation failed to save.
9
+ - The concern no longer declares `{abbr: 1}`. Mongoid keys a declaration on its fields alone, so the concern's copy silently swallowed `Nation`'s unique one. `Region` keeps its own.
10
+ - `spec/models/indexes_spec.rb` inserts straight into the collection, past the validations, and expects the index to refuse.
11
+
3
12
  ## 3.2.0
4
13
 
5
14
  - Slugs work in every script: `東京` → `東京`, `Санкт-Петербург` → `санкт-петербург`. Non-Latin names were previously invalid (blank slug). Accents are stripped via NFKD (`Hà Nội` → `ha-noi`). Underscores now become hyphens.
@@ -25,4 +34,4 @@
25
34
  - `Nation#lang=` keeps the nations other languages instead of wiping `langs` to a single entry.
26
35
  - `Nation[]` returns `nil` for an unknown abbr instead of raising `DocumentNotFound`.
27
36
 
28
- **Upgrading:** stored slugs are not rewritten until a document is saved again, so existing data is untouched � but region-less cities will pick up a nation suffix the next time they are saved, and `City.create_indexes` will now fail on a database that already holds duplicate city slugs. `geonames_local` depends on `geopolitical > 0.8.4` (no upper bound) and will pick this up on its next bundle.
37
+ **Upgrading:** stored slugs are not rewritten until a document is saved again, so existing data is untouched � but region-less cities will pick up a nation suffix the next time they are saved, and `City.create_indexes` will now fail on a database that already holds duplicate city slugs. `geonames_local` depends on `geopolitical > 0.8.4` (no upper bound) and will pick this up on its next bundle.
data/app/models/city.rb CHANGED
@@ -61,6 +61,7 @@ class City
61
61
 
62
62
  index({ slug: 1 }, unique: true)
63
63
  index({ name: 1, nation_id: 1 }) # For lookups by name within a nation
64
+ index({ nation_id: 1, region_id: 1, name: 1 }, { unique: true }) # Backs the name uniqueness validation
64
65
  index({ nation_id: 1 }) # For finding all cities in a nation
65
66
  index({ region_id: 1 }, sparse: true) # For finding cities in a region, sparse if region is optional
66
67
  index({ souls: -1 }) # For sorting by population count
@@ -77,10 +77,10 @@ module Geopolitocracy
77
77
  # @!endgroup
78
78
 
79
79
  # @!group Indexes
80
- # NOTE: no plain slug index here — each model declares its own (unique where it
81
- # can be), and a duplicate key declaration would silently shadow theirs.
80
+ # NOTE: no slug or abbr index here — each model declares its own (unique where
81
+ # it can be). Mongoid keys a declaration on the fields alone, so a second
82
+ # `index({ abbr: 1 }, unique: true)` in a model would be silently ignored.
82
83
  index({ name: 1 }) # For sorting and lookups by name
83
- index({ abbr: 1 }, { sparse: true }) # Sparse as abbr can be nil
84
84
  index({ code: 1 }, { sparse: true }) # Sparse as code can be nil
85
85
  # @!endgroup
86
86
 
data/app/models/nation.rb CHANGED
@@ -61,6 +61,7 @@ class Nation
61
61
 
62
62
  index({ name: 1 }) # Index for sorting by name, common operation
63
63
  index({ slug: 1 }, { unique: true }) # Slugs must be globally unique for nations
64
+ index({ abbr: 1 }, { unique: true }) # abbr is upcased by its writer, so plain unique is case-insensitive
64
65
 
65
66
  # Nation['br'] => the Nation with abbr BR (the abbr is the _id), nil if unknown.
66
67
  # @param abbr [String, Symbol]
data/app/models/region.rb CHANGED
@@ -30,14 +30,16 @@ class Region
30
30
  validates :name, uniqueness: { scope: :nation_id, message: 'must be unique within its nation' }
31
31
  # `abbr` (from Geopolitocracy) should also be unique within its nation if present.
32
32
  validates :abbr,
33
- uniqueness: { scope: :nation_id, allow_nil: true, message: 'must be unique within its nation if provided' }
33
+ uniqueness: { scope: :nation_id, allow_blank: true, message: 'must be unique within its nation if provided' }
34
34
  # Slug (from Geopolitocracy) should be unique within its nation. Presence is already validated by Geopolitocracy.
35
35
  validates :slug, uniqueness: { scope: :nation_id, message: 'must be unique within its nation' }
36
36
 
37
37
  index({ slug: 1 }) # For .search; global uniqueness is not required, see the compound index below
38
38
  index({ abbr: 1 }, { sparse: true }) # Sparse index as abbr can be nil
39
39
  index({ nation_id: 1, name: 1 }, { unique: true }) # Enforce uniqueness of name within nation
40
- index({ nation_id: 1, abbr: 1 }, { unique: true, sparse: true }) # Enforce uniqueness of abbr within nation
40
+ # Partial, not sparse: nation_id is always set, so a sparse compound index
41
+ # still indexes every abbr-less region and the second one collides.
42
+ index({ nation_id: 1, abbr: 1 }, { unique: true, partial_filter_expression: { abbr: { '$gt' => '' } } })
41
43
  index({ nation_id: 1, slug: 1 }, { unique: true }) # Enforce uniqueness of slug within nation
42
44
 
43
45
  # Retrieves the phone dialing code for the region.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geopolitical
4
- VERSION = '3.2.0'
4
+ VERSION = '3.2.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geopolitical
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcos Piccinini