Simpler way of giving a new value to an attribute - datomic

There is an attribute :organisation/ord. This is how I'm getting the data structure to pass to d/transact:
(assoc (d/pull db [:db/id] (:db/id organisation)) :organisation/ord new-org-ord)
;; => {:db/id 17592186045432, :organisation/ord 4198}
Here organisation is of type datomic.query.EntityMap and new-org-ord is an integer. This works fine but seems unwieldy. Is there simpler code that does the same job?
Thinking all I need do was turn EntityMap into a real map I tried this:
(assoc (into {} organisation) :organisation/last-invoice-ordinal new-org-ord)
But got:
:db.error/not-an-entity Unable to resolve entity: #:db{:id 17592186045433} in datom [-9223301668109597772 :organisation/timespan #:db{:id 17592186045433}]

This is simpler:
{:db/id (:db/id organisation), :organisation/ord new-org-ord}
And here's another alternative that also works:
(assoc (select-keys organisation [:db/id]) :organisation/ord new-org-ord)
It doesn't really make sense to be transacting with a map that has anything in it apart from a map-entry to identify the entity id you want to assert some new facts against, together with map-entries that represent those facts.

Related

Clojure assoc/assoc-in

(def db-sample
{
:person [{:person/id 9 :name "rich" :surname "hickey" :join-date "04.04.2016" :experience :experience/lead :loyality-level :loyality-level/more-than-seven-years :work-type :work-type/tenure :work-time :work-time/part-time}]
:employees/developer-team [{:frontend [[:person/id 1] [:person/id 2] [:person/id 3] [:person/id 4]]
}
hello everyone, I making practice on assoc functions so I wanted to create a sample database just using assoc functions to do the practice.
I checked it's quick docs but there is no explanation about how can I create a vector and put data into it. I left an example on top, my question is how can I create db-sample data by using assoc functions? (or maybe easier better options)
In practice if you wanted to simulate a db it would first have to be an atom so you can update in place. And your "adding a person" would be something like:
(def db-sample (atom {:person [] :employees/developer-team []})
(swap! db-sample update :person #(conj % new-person))
Things can get tricky when your database is too nested - there are libraries for this such as specter. But keeping databases relatively flat is also good practice IMHO.

Rails update remove number from an array attribute?

Is there a way to remove a number from an attibute array in an update? For example, if I want to update all of an alchy's booze stashes if he runs out of a particular type of booze:
Alchy has_many :stashes
Stash.available_booze_types = [] (filled with booze.ids)
Booze is also a class
#booze.id = 7
if #booze.is_all_gone
#alchy.stashes.update(available_booze_types: "remove #booze.id")
end
update: #booze.id may or may not be present in the available_booze_types array
... so if #booze.id was in any of the Alchy.stash instances (in the available_booze_types attribute array), it would be removed.
I think you can do what you want in the following way:
if #booze.is_all_gone
#alchy.stashes.each do |stash|
stash.available_booze_types.delete(#booze.id)
end
end
However, it looks to me like there are better ways to do what you are trying to do. Rails gives you something like that array by using relations. Also, the data in the array will be lost if you reset the app (if as I understand available_booze_types is an attribute which is not stored in a database). If your application is correctly set up (an stash has many boozes), an scope like the following in Stash class seems to me like the correct approach:
scope :available_boozes, -> { joins(:boozes).where("number > ?", 0) }
You can use it in the following way:
#alchy.stashes.available_boozes
which would only return the ones that are available.

filter with dynamic dict peewee ORM

Using peewee as my ORM, is there a way to directly filter with a dict?
For example, if I have a model
class User(BaseModel):
username = CharField(unique=True)
password = CharField()
email = CharField()
join_date = DateTimeField()
How can I filter all results with username Bob, with something like
params = {'username':'Bob'}
User.select().where(**params)
update
I found a solution, but I'm wondering if there's a better way ...
params = {'username':'Bob'}
User.select().where(*[getattr(User, k) == v for k, v in params.items()])
First of all, where are you getting this "dynamic dict" from? Presumably you would want to do some field validation and things before just hucking shit at the database -- and during that time you could move it into a better data-structure.
Also note that the only operation you would be able to do with the above is equality testing.
To answer your question, Peewee has a .filter() method which behaves like the one in Django. So you can throw your dictionary of data at it. docs are sparse because this method is really not recommended:
http://docs.peewee-orm.com/en/latest/peewee/api.html#Model.filter

EasyMock - expect anyObject except some

Let's say I have a method like this:
foo (A a, B b)
I want to set expectation so that anyObject is expected except some, like the imaginary code below:
expect(mockedObject).foo(anyObject(A.class), anyObject(B.class)).andReturn(something).anyTimes();
expect(mockedObject).foo(new A("1"), new B("1")).andReturn(something).times(0);
expect(mockedObject).foo(new A("2"), new B("2")).andReturn(something).times(0);
expect(mockedObject).foo(new A("3"), new B("3")).andReturn(something).times(0);
However there is no times(0) in EasyMock. I can create a chain of EasyMock.or() and EasyMock.not() but it's going to be dirty when there are a lot of unexpected objects.
On Mockito I can easily specify
verify(mockedObject, never()).foo(new A("1"), new B("1"));
What's the easiest way on EasyMock to do the same thing as above?
It is something missing indeed.
Right now, the easier is to capture() all your parameters and then check that no invalid permutation was used.

Idiomatic List Wrapper

In Google App Engine, I make lists of referenced properties much like this:
class Referenced(BaseModel):
name = db.StringProperty()
class Thing(BaseModel):
foo_keys = db.ListProperty(db.Key)
def __getattr__(self, attrname):
if attrname == 'foos':
return Referenced.get(self.foo_keys)
else:
return BaseModel.__getattr__(self, attrname)
This way, someone can have a Thing and say thing.foos and get something legitimate out of it. The problem comes when somebody says thing.foos.append(x). This will not save the added property because the underlying list of keys remains unchanged. So I quickly wrote this solution to make it easy to append keys to a list:
class KeyBackedList(list):
def __init__(self, key_class, key_list):
list.__init__(self, key_class.get(key_list))
self.key_class = key_class
self.key_list = key_list
def append(self, value):
self.key_list.append(value.key())
list.append(self, value)
class Thing(BaseModel):
foo_keys = db.ListProperty(db.Key)
def __getattr__(self, attrname):
if attrname == 'foos':
return KeyBackedList(Thing, self.foo_keys)
else:
return BaseModel.__getattr__(self, attrname)
This is great for proof-of-concept, in that it works exactly as expected when calling append. However, I would never give this to other people, since they might mutate the list in other ways (thing[1:9] = whatevs or thing.sort()). Sure, I could go define all the __setslice__ and whatnot, but that seems to leave me open for obnoxious bugs. However, that is the best solution I can come up with.
Is there a better way to do what I am trying to do (something in the Python library perhaps)? Or am I going about this the wrong way and trying to make things too smooth?
If you want to modify things like this, you shouldn't be changing __getattr__ on the model; instead, you should write a custom Property class.
As you've observed, though, creating a workable 'ReferenceListProperty' is difficult and involved, and there are many subtle edge cases. I would recommend sticking with the list of keys, and fetching the referenced entities in your code when needed.

Resources