How can a document claim it's persisted, when a count on the class returns 0? - mongodb

How can a document claim foo.persisted? == true, when foo.class.count == 0?
More importantly, how can I get the document to truly persist?
Update: calling Mongo::Foo.create() from the controller does increment the count. That is expected. Calling create, or new and save, from within a separate module/class does not increment the count.
Update: I have tried changing new/save calls to create
Update: I have also tried #foo_class.with(collection: "mongo_foos").create
[42] pry(#<FoosController>)> foo.class
=> Mongo::Foo
[43] pry(#<FoosController>)> foo.persisted?
=> true
[44] pry(#<FoosController>)> Mongo::Foo.count
=> 0
[47] pry(#<FoosController>)> foo.id
=> "5081a1a786ddc8e035000021"
[48] pry(#<FoosController>)> foo
=> #<Mongo::Foo _id: 5081a1a786ddc8e035000021, _type: nil, foo_daddy_id: nil, old_foo_daddy_id: 219, member_id: "F008AR", unix_time: nil, date_time: 2012-10-19 13:50:54 UTC, submitted: nil, json: nil>
Here's how the document class is defined:
module Mongo
class Foo
include Mongoid::Document
field :foo_daddy_id
field :old_foo_daddy_id, type: Integer
field :member_id, type: String
field :unix_time, type: Integer
field :date_time, type: DateTime
field :submitted, type: Integer
field :json, type: Hash
belongs_to :foo_daddy, class_name: "Mongo::FooDaddy"
embeds_many :foo_dumplings, class_name: "Mongo::FooDumpling"
end
end
The doc is being created with foo.new(params); foo.save:
module FooThingy
module Foo
class Create < ::FooThingy::Base
def initialize(options)
# Sets instance variables used below
end
def execute!
#foo = #foo_class.new({
date_time: DateTime.strptime(#params["submitted_timestamp"], "%m-%d-%Y %H:%M:%S"),
member_id: (#params[:member_id].present? ? #params[:member_id] : nil),
old_foo_daddy_id: #params[:old_foo_daddy_id]
})
embed_foo_dumplings
if #foo.save
return FooThingy::Result.new(success: true, data: { foo: #foo })
else
return FooThingy::Result.new(success: false, data: { foo: #foo })
end
end
private
def embed_foo_dumplings
# Embeds foo_dumplings
end
end
end
end
Here's where I call that module to create the document:
class FoosController < ApplicationController
def create
foo_creator = FooThingy::Foo::Create.new(params: params, foo_class: Mongo::Foo)
foo = foo_creator.execute!
foo = foo.data[:foo]
binding.pry
end
end

This problem, I think, is less interesting than it appears. I've modified my config/mongoid.yml to specify a new database, and everything behaves as expected. Problem was likely due to limitations on 32-bit MongoDB installations.

Related

Adding and triggering a transition within on_enter state callback

I want to store a previous state A when entering state B using a state history. Later 'on_enter' of another state X, add a transition X->A, trigger it and return to state A.
A -> B (store A) -> C -> X (add transition from X to A) -> A
from transitions.extensions import HierarchicalGraphMachine
class Matter(HierarchicalGraphMachine):
def __init__(self, states):
# self.separator = '/'
self.history = []
self.stored = []
HierarchicalGraphMachine.__init__(
self,
states=states,
initial='root',
show_state_attributes=True
)
#property
def state(self):
return self.history[-1]
#state.setter
def state(self, value):
self.history.append(value)
def store_last(self):
self.stored.append(self.history[-2])
def to_stored(self):
stored = self.stored.pop()
temp_transition = {
'trigger': 'jump',
'source': self.state,
'dest': stored
}
self.add_transition(**temp_transition)
self.trigger('jump')
self.remove_transition(**temp_transition)
TRANSITIONS = [
['walk', 'standing', 'walking'],
['stop', 'walking', 'standing'],
['drink', '*', 'caffeinated'],
['walk',
['caffeinated', 'caffeinated_dithering'],
'caffeinated_running'],
['relax', 'caffeinated', 'standing']
]
STATES = [{
'name': 'root',
'initial': 'standing',
'transitions': TRANSITIONS,
'children': [
{
'name': 'standing',
},
{
'name': 'walking',
'on_enter': 'store_last',
},
{
'name': 'caffeinated',
'children': [
'dithering',
{
'name': 'running',
'on_enter': 'to_stored'
}
]
}
]
}]
If I run the code skipping on_enter the transition is added, triggered and removed as expected.
# this works
lump = Matter(states=STATES)
lump.trigger('walk')
assert lump.history == ['root', 'root_standing', 'root_walking']
assert lump.stored == ['root_standing']
lump.trigger('drink')
# set state manually to skip on_enter
lump.state = 'root_caffeinated_running'
# run on_enter method manually works
lump.to_stored()
assert lump.state == 'root_standing'
assert lump.stored == []
assert lump.get_nested_transitions(trigger='jump') == []
lump.get_graph().draw('my_state_diagram.pdf', prog='dot')
If I run it within on_enter I get an error "MachineError: "Can't trigger event 'jump' from state(s) root_caffeinated_running!"
# cannot do the jump using on_enter
lump = Matter(states=STATES)
lump.trigger('walk')
lump.trigger('drink')
lump.trigger('walk')
# Can't trigger event 'jump' from state(s) root_caffeinated_running!
lump.get_graph().draw('my_state_diagram.pdf', prog='dot')
By default transitions will add auto transitions which can be used to reach every state directly without the need to add transitions temporarily. In combination with Machine.trigger that can be used to call events by their name, your to_stored method could be simplified to:
def to_stored(self):
stored = self.stored.pop()
self.trigger(f"to_{stored}")

How natural sorting a varchar column with Doctrine

I have a table with a column that contains names (varchar) but some names have numbers inside and the ordering is not the expected.
I have something like:
Courlis
D11 Espadon
D13 Balbuzard
D1 empacher
D2
But I expect:
Courlis
D1 empacher
D2
D11 Espadon
D13 Balbuzard
I've found lot of tips about it, but it's always on ordering numbers only stored as string: add a 0 to convert it in numbers, check the length of the string to place 1 before 10, etc... But in my case it can't work.
I can't use SQL query, because I use it in a form of a Symfony application that need a QueryBuilder.
Here is a way to do this with ICU collations in PostgreSQL (available from v10 on):
CREATE COLLATION en_natural (
LOCALE = 'en-US-u-kn-true',
PROVIDER = 'icu'
);
CREATE TABLE atable (textcol text COLLATE en_natural);
COPY atable FROM STDIN;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself, or an EOF signal.
>> Courlis
>> D11 Espadon
>> D13 Balbuzard
>> D1 empacher
>> D2
>> \.
test=# SELECT textcol FROM atable ORDER BY textcol;
textcol
---------------
Courlis
D1 empacher
D2
D11 Espadon
D13 Balbuzard
(5 rows)
Thanks to Laurentz Albe for your answer,for a Step by step in a Symfony application:
Create a Migration file that create the custom collation
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20200221215657 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('CREATE COLLATION fr_natural (provider = "icu", locale = "fr-u-kn-true");');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('DROP COLLATION fr_natural');
}
}
Create a Doctrine Custom Function (Collate DQL)
<?php
namespace App\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Collate extends FunctionNode
{
public $expressionToCollate = null;
public $collation = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->expressionToCollate = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(Lexer::T_IDENTIFIER);
$lexer = $parser->getLexer();
$this->collation = $lexer->token['value'];
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return sprintf( '%s COLLATE %s', $sqlWalker->walkStringPrimary($this->expressionToCollate), $this->collation );
}
}
Register the new Function in the Doctrine config
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
server_version: '12'
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
dql:
string_functions:
collate: App\DQL\Collate
And finally juste use it in the query when needed
$query = $this->createQueryBuilder('shell')
->orderBy('COLLATE(shell.name, fr_natural)', 'ASC')
->getQuery();
return $query->getResult();

django rest framework - return custom data for a model serializer field

I have the following model:
class ServerSimpleConfigSerializer(mixins.GetCSConfigMixin, serializers.ModelSerializer):
mp_autoteambalance = serializers.BooleanField(label='Auto Team Balance', default=True, required=False)
mp_friendlyfire = serializers.BooleanField(label='Friendly Fire', default=False, required=False)
mp_autokick = serializers.BooleanField(label='Auto team-killer banning and idle client kicking', default=True, required=False)
# hostname = serializers.CharField(label='Hostname', max_length=75, required=True)
rcon_password = serializers.CharField(label='RCON Password', max_length=75, required=True)
sv_password = serializers.CharField(label='Server Password', max_length=75, required=False)
mp_startmoney = serializers.IntegerField(label='Start Money', required=False, validators=[MinValueValidator(800), MaxValueValidator(16000)])
mp_roundtime = serializers.FloatField(label='Round Time', required=False)
mp_timelimit = serializers.IntegerField(label='Map Time Limit', required=False)
fpath = os.path.join(settings.ROOT_DIR, "cs16/tmp/server.json")
class Meta:
model = CS16Server
fields = ('name', 'game_config', 'mp_autoteambalance', 'mp_friendlyfire',
'mp_autokick', 'hostname', 'rcon_password', 'sv_password',
'mp_startmoney', 'mp_roundtime', 'mp_timelimit')
read_only_fields = ('name', 'game_config',)
The model has the following fields:
name, game_config (big text) and hostname
How can I return the above defined fields for the serializer, although they are not present on the model ?
I would like to set some custom values for each field & return them as a JSON.
Is that possible ?
Actually the values for the above defined fields are found in "game_config" field.
I would like to parse those values & return them & I would not want to put them as separate fields in the model.
Parse game_config, obtain a pair of: (field0, val0) ... (fieldN, valN) and in the serializer,
set those values for the serializer fields.
For now I only get the following response:
{
"name": "Chronos",
"game_config": "hostname \"A New Gameservers.com Server is Born\"\nrcon_password \"\"\nsv_password \"1410271\"\nsv_contact email#domain.com\nsv_region 255\nsv_filterban 1\nsv_logbans 0\nsv_unlag 1\nmp_startmoney 800\nmp_chattime 30\nmp_footsteps 1\nsv_footsteps 1\nmp_logdetail 0\nmp_logmessages 0\nmp_timelimit 30\nmp_autokick 1\nmp_autoteambalance 1\nmp_flashlight 0\nmp_forcerespawn 0\nmp_forcechasecam 0\nmp_freezetime 0\nmp_friendlyfire 0\nmp_hostagepenalty 0\nmp_limitteams 0\nmp_roundtime 5\nmp_tkpunish 1\nsv_voiceenable 1\nsv_voicecodec voice_speex\nsv_voicequality 3\nsv_alltalk 0\nsv_restartround 1\nsv_maxspeed 320\nsv_proxies 1\nallow_spectators 1\nsv_allowupload 1\npausable 0\ndecalfrequency 40\nmp_falldamage 0\nsv_cheats 0\nsv_lan 0\nsv_maxrate 20000\nsv_minrate 4000\nexec listip.cfg",
"mp_autoteambalance": true,
"mp_friendlyfire": false,
"mp_autokick": true,
"hostname": "none"
}

Having both object.property and object.property.method() available in coffeescript

[update]
My question may not be clear enough...
Further clarification of what I would like to accomplish :
I retrieve objects like this one:
p =
name:
first: 'alan'
last: 'smith'
and want to create a structure (one class, multiple classes ?) to be able to write things like this ultimately:
person.name # alan smith
person.name.toCap() #Alan Smith
person.name.first # alan
person.name.first.toCap() # Alan
person.name.last # smith
person.name.last.toCap() # Smith
...
so :
Is there a way to have both person.name and person.name.first ?
Is there a better way to extend object properties with methods rather than extending native types like String ?
[original]
Looking for the right way to do this in coffee :
console.log person.name.last #smith
console.log person.name.last.capitalize() # SMITH
console.log person.name.last.initial() # S
I have come up with the following solution, but would like to make sure this is the way to go...
String::toCap = (remainingToLower=false) ->
#[0].toUpperCase() + if remainingToLower then #[1..-1].toLowerCase()
else #[1..-1]
Number::random = (percent) ->
offset = # * percent / 100
parseInt(Math.floor(Math.random() * 2 * offset) + # - offset)
class Name
constructor: (#first, #last) ->
class Person
constructor: (#name, #age) ->
toString: () => "#{#name.first.toCap(true)} #{#name.last.toCap(true)}
(#{#age.random(25)})"
# GO --------------------------->
p = new Person(new Name, 18)
p.name.first = 'alaN'
p.name.last = 'smith'
console.log "#{p.toString()}"
Thanks for your feedback.
Plunk Here
Context
I have this raw data:
data =
name:
first: 'alan'
last: 'smith'
age: 18
address: [
{
name: 'work'
street: '1600 amphitheatre parkway'
city: 'mountain view'
zip: 'CA 94043'
},{
name: 'home'
street: '1 infinite loop'
city: 'cupertino'
zip: 'CA 95014'
}]
And want to create a structure to manipulate my data like this :
p = New Person(data)
console.log """
#{p} # alan smith (18), 2 address lines
#{p.name}, # alan smith
#{p.name.first}, # alan
#{p.address} # 2 address lines
#{p.address.work} # 1600 amphitheatre parkway, mountain view, CA 94043
#{p.address.work.street} # 1600 amphitheatre parkway
"""
Additionally, I want to be able to apply custom methods to any member.
For instance, assuming toCap() is a method that capitalises each word of a String :
console.log """
#{p.name.toCap()}, # Alan Smith
#{p.name.first.toCap()} # Alan
#{p.address.work.toCap()} # 1600 Amphitheatre Parkway, Moutain View, CA 94043
#{p.address.work.street.toCap()} # 1600 Amphitheatre Parkway
"""
Solution (see this Plunk for the full code)
use nested classes
class Person
constructor: (data) ->
#name = new Name(data.name)
#address = new AddressList(data.address)
create members dynamically
class AddressList
constructor: (list) ->
#[addr.name] = new Address(addr) for addr in list
wrap your properties or use base classes rather than extending native objects
class StringProperty
constructor: (#_value) ->
toString: =>
#_value
toCap: (remainingToLower=false) =>
_words = #_value.split ' '
(#_toCap(w,remainingToLower) for w in _words).join ' '
_toCap : (s, r) ->
s[0].toUpperCase() + if r then s[1..-1].toLowerCase() else s[1..-1]
... and use them directly ...
class Name
constructor: (name) ->
#first = new StringProperty(name.first)
#last = new StringProperty(name.last)
toString: =>
"#{#first} #{#last}"
toCap: =>
"#{#first.toCap()} #{#last.toCap()}"
... or create members dynamically :
#[k] = new StringProperty(data[k]) for k of data when k in Address.fields
don't forget to override toString() as above

undefined method 'map' for nil class

I'm a newbie and I got some trouble when run rails 3 server with mongodb (using mongoid) in production mode. Everything is ok in development mode, and I cannot figure out what am I missing. Please help me, thank you very much. This is the error:
ActionView::Template::Error (undefined method `map' for nil:NilClass):
2: #control{:style => "float: left;"}
3: %h3= t(:manage_shop)
4: =# debugger
=###### Already checking #shops variable but still got error ######
5: = hidden_field_tag :shop_list, #shops.blank? ? "test" : #shops.to_json
6: = form_tag("/shop", :method => "POST", :id => "frm_create_shop") do
7: %table
8: %tr
app/views/shop/index.html.haml:5:in`_app_views_shop_index_html_haml___1855911541554609468_28040500'
this is my action:
def index
#shops = Shop.all
respond_to do |format|
format.html
end
end
my model:
class Shop
include Mongoid::Document
include Mongoid::Geospatial
field :id, type: Integer
field :name, type: String
field :position, type: Point, :spatial => true, :delegate => true
spatial_scope :position
end
and my production.rb configuration:
Trunk::Application.configure do
config.cache_classes = true
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.serve_static_assets = false
config.assets.compress = true
config.assets.compile = false
config.assets.digest = true
config.i18n.fallbacks = true
config.active_support.deprecation = :notify
end
And the second thing is I cannot get anything from db although everything is work well in development mode. If you have any suggestion, please help, thanks.