-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MONGOID-4913 Implement StringifiedSymbol type (#4906)
- Loading branch information
Showing
7 changed files
with
414 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# frozen_string_literal: true | ||
# encoding: utf-8 | ||
|
||
# A class which sends values to the database as Strings but returns them to the user as Symbols. | ||
module Mongoid | ||
class StringifiedSymbol | ||
|
||
class << self | ||
|
||
# Convert the object from its mongo friendly ruby type to this type. | ||
# | ||
# @example Demongoize the object. | ||
# Symbol.demongoize(object) | ||
# | ||
# @param [ Object ] object The object to demongoize. | ||
# | ||
# @return [ Symbol ] The object. | ||
# | ||
# @api private | ||
def demongoize(object) | ||
if object.nil? | ||
object | ||
else | ||
object.to_s.to_sym | ||
end | ||
end | ||
|
||
# Turn the object from the ruby type we deal with to a Mongo friendly | ||
# type. | ||
# | ||
# @example Mongoize the object. | ||
# Symbol.mongoize("123.11") | ||
# | ||
# @param [ Object ] object The object to mongoize. | ||
# | ||
# @return [ Symbol ] The object mongoized. | ||
# | ||
# @api private | ||
def mongoize(object) | ||
if object.nil? | ||
object | ||
else | ||
object.to_s | ||
end | ||
end | ||
|
||
# @api private | ||
def evolve(object) | ||
mongoize(object) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
require "spec_helper" | ||
|
||
describe "StringifiedSymbol fields" do | ||
|
||
before do | ||
Order.destroy_all | ||
end | ||
|
||
context "when querying the database" do | ||
|
||
let!(:document) do | ||
Order.create!(saved_status: :test) | ||
end | ||
|
||
let(:string_query) do | ||
{'saved_status' => {'$eq' => 'test'}} | ||
end | ||
|
||
let(:symbol_query) do | ||
{'saved_status' => {'$eq' => :test}} | ||
end | ||
|
||
it "can be queried with a string" do | ||
doc = Order.where(string_query).first | ||
expect(doc.saved_status).to eq(:test) | ||
end | ||
|
||
it "can be queried with a symbol" do | ||
doc = Order.where(symbol_query).first | ||
expect(doc.saved_status).to eq(:test) | ||
end | ||
end | ||
|
||
# Using command monitoring to test that StringifiedSymbol sends a string and returns a symbol | ||
let(:client) { Order.collection.client } | ||
|
||
before do | ||
client.subscribe(Mongo::Monitoring::COMMAND, subscriber) | ||
end | ||
|
||
after do | ||
client.unsubscribe(Mongo::Monitoring::COMMAND, subscriber) | ||
end | ||
|
||
let(:subscriber) do | ||
EventSubscriber.new | ||
end | ||
|
||
let(:find_events) do | ||
subscriber.started_events.select { |event| event.command_name.to_s == 'find' } | ||
end | ||
|
||
let(:insert_events) do | ||
subscriber.started_events.select { |event| event.command_name.to_s == 'insert' } | ||
end | ||
|
||
let(:update_events) do | ||
subscriber.started_events.select { |event| event.command_name.to_s == 'update' } | ||
end | ||
|
||
before do | ||
subscriber.clear_events! | ||
end | ||
|
||
let(:query) do | ||
{'saved_status' => {'$eq' => 'test'}} | ||
end | ||
|
||
let!(:document1) do | ||
Order.create!(saved_status: :test) | ||
end | ||
|
||
let!(:document2) do | ||
Order.where(query).first | ||
end | ||
|
||
context "when inserting document" do | ||
|
||
it "sends the value as a string" do | ||
Order.create!(saved_status: :test) | ||
event = insert_events.first | ||
doc = event.command["documents"].first | ||
expect(doc["saved_status"]).to eq("test") | ||
end | ||
|
||
it "sends the value as a string" do | ||
Order.create!(saved_status: 42) | ||
event = insert_events.second | ||
doc = event.command["documents"].first | ||
expect(doc["saved_status"]).to eq("42") | ||
end | ||
|
||
it "sends the value as a string" do | ||
Order.create(saved_status: [0, 1, 2]) | ||
event = insert_events.second | ||
doc = event.command["documents"].first | ||
expect(doc["saved_status"]).to eq("[0, 1, 2]") | ||
end | ||
end | ||
|
||
context "when finding document" do | ||
|
||
it "receives the value as a symbol" do | ||
event = find_events.first | ||
expect(document2.saved_status).to eq(:test) | ||
end | ||
end | ||
|
||
context "when reading a BSON Symbol field" do | ||
|
||
before do | ||
client["orders"].insert_one(saved_status: BSON::Symbol::Raw.new("test"), _id: 12) | ||
end | ||
|
||
it "receives the value as a symbol" do | ||
expect(Order.find(12).saved_status).to eq(:test) | ||
end | ||
|
||
it "saves the value as a string" do | ||
s = Order.find(12) | ||
s.saved_status = :other | ||
s.save! | ||
event = update_events.first | ||
expect(event.command["updates"].first["u"]["$set"]["saved_status"]).to eq("other") | ||
end | ||
end | ||
|
||
context "when value is nil" do | ||
|
||
before do | ||
client["orders"].insert_one(saved_status: nil, _id: 15) | ||
end | ||
|
||
it "returns nil" do | ||
expect(Order.find(15).saved_status).to be_nil | ||
end | ||
end | ||
|
||
context "when writing nil" do | ||
|
||
before do | ||
client["orders"].insert_one(saved_status: "hello", _id: 16) | ||
end | ||
|
||
it "saves the value as nil" do | ||
s = Order.find(16) | ||
s.saved_status = nil | ||
s.save! | ||
event = update_events.first | ||
expect(event.command["updates"].first["u"]["$set"]["saved_status"]).to be_nil | ||
end | ||
end | ||
|
||
context "when reading an integer" do | ||
|
||
before do | ||
client["orders"].insert_one(saved_status: 42, _id: 13) | ||
end | ||
|
||
it "receives the value as a symbol" do | ||
expect(Order.find(13).saved_status).to eq(:"42") | ||
end | ||
|
||
it "saves the value as a string" do | ||
s = Order.find(13) | ||
s.saved_status = 24 | ||
s.save! | ||
event = update_events.first | ||
expect(event.command["updates"].first["u"]["$set"]["saved_status"]).to eq("24") | ||
end | ||
end | ||
|
||
context "when reading an array" do | ||
before do | ||
client["orders"].insert_one(saved_status: [0, 1, 2], _id: 14) | ||
end | ||
|
||
it "receives the value as a symbol" do | ||
expect(Order.find(14).saved_status).to be(:"[0, 1, 2]") | ||
end | ||
|
||
it "saves the value as a string" do | ||
s = Order.find(14) | ||
s.saved_status = [3, 4, 5] | ||
s.save! | ||
event = update_events.first | ||
expect(event.command["updates"].first["u"]["$set"]["saved_status"]).to eq("[3, 4, 5]") | ||
end | ||
end | ||
end |
Oops, something went wrong.