I just recently started working on a database-heavy Clojure application and am attempting to get some unit tests in place. Ideally, I'd like to avoid actually hitting a real database by mocking things out.
Here's an example of a simple test:
test-core.clj
(deftest core-test
(is (> (count (fn-under-test "foo")) 0)))
core.clj
(defn fn-under-test [slug]
(db/query "select * from %1" slug))
db.clj
(defn query [q & args]
(sql/with-connection db
(sql/with-query-results res
[(clause q args)]
(doall res))))
My question: is there a way, from within test-core.clj, to bind a custom function to 'db/query' such that core.clj will use it, as opposed to the definition within db.clj?
Thanks!
You can use binding to try and override db/query, but you'll need to define the namespace and var first. The easiest way is to import the db.clj into the same namespace and then use bindings.
(ns test-core
(:use clojure.test)
(:require db))
(deftest core-test
(binding [db/query (fn [query & args] (comment return some value here))]
(is (> (count (fn-under-test "foo")) 0))))
Related
(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.
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.
I would like to use Google Closure UI components from ClojureScript with the Rum/React library.
I started with goog.ui.DatePicker, but still cannot wrap it correctly. The code underneath renders the DatePicker once on component mount and at the right place, the event listener works and all is fine, except it needs the statically set id ("here") at the dom node to work which would be acceptable for one time hack, but not when I need to have the component wrapped and use several times on the same page/app.
(ns redux.components
(:require [rum.core :as r]
[cljs-time.core :as time]
[cljs-time.format :as tf]
[goog.dom :as dom]
[goog.ui.DatePicker :as goog-picker]
[goog.events :as goog-events]]))
(r/defcs +published-at < { :did-mount (fn [state]
(let [target-node (:r/ref state "here")
dp (goog.ui.DatePicker. nil goog.i18n.DateTimeSymbols_cs)]
(.listen dp (.. goog.ui.DatePicker -Events -CHANGE) #(println "new date is: " (tf/unparse (tf/formatter "YYYY-MM-dd")(time/to-default-time-zone (.. % -target getDate)))))
(.render dp (goog.dom/getElement "here")))
state) }
[]
[:div#here])
(r/defc app
[]
[:div
[:h1 "title"
(+published-at)]])
My further unsuccessful research
React documentation suggests that for integration with third-party DOM libraries one might need refs. Rum documentation describes how to do react refs from Rum. But the trouble is that React doc states that string refs are legacy and might be removed in future releases while Rum documentation does not cover callback based refs. I tried to guess how to combine both frameworks with string refs as well as callback refs, but neither one seems to work:
String based legacy approach
(r/defcs +published-at < { :did-mount (fn [state]
(let [target-node (:r/ref state "here")
dp (goog.ui.DatePicker. nil goog.i18n.DateTimeSymbols_cs)]
(.listen dp (.. goog.ui.DatePicker -Events -CHANGE) #(println (tf/unparse (tf/formatter "YYYY-MM-dd")(time/to-default-time-zone (.. % -target getDate)))))
(.render dp target-node))
state) }
[]
[:div
[:div { :ref "here" } ]])
This fails with error and the DatePicker is not even displayed:
Uncaught TypeError: opt_parentElement.insertBefore is not a function
at goog.ui.DatePicker.goog.ui.Component.render_ (component.js:705)
at goog.ui.DatePicker.goog.ui.Component.render (component.js:659)
at Function.<anonymous> (components.cljs?rel=1493075625598:123)
at Function.cljs.core.apply.cljs$core$IFn$_invoke$arity$3 (core.cljs:3694)
at cljs$core$apply (core.cljs:3676)
at util.cljc?rel=1492772300984:17
at core.cljs:2314
at Function.cljs.core.seq_reduce.cljs$core$IFn$_invoke$arity$3 (core.cljs:2314)
at cljs.core.LazySeq.cljs$core$IReduce$_reduce$arity$3 (core.cljs:3287)
at Function.cljs.core.reduce.cljs$core$IFn$_invoke$arity$3 (core.cljs:2358)
Callback base approach
(r/defcs +published-at < { :did-mount (fn [state]
(let [dp (goog.ui.DatePicker. nil goog.i18n.DateTimeSymbols_cs)]
(.listen dp (.. goog.ui.DatePicker -Events -CHANGE) #(println (tf/unparse (tf/formatter "YYYY-MM-dd")(time/to-default-time-zone (.. % -target getDate)))))
(.render dp (::put-date-here state)))
state) }
[state]
[:div
[:div { :ref #(assoc state ::put-date-here %) }]])
This renders functional DatePicker, but out of the component, at the end of the page.
You don't need :did-mount here, just render it right in the callback. This works fine for me:
(defn show-datepicker
[d]
(let [dp (goog.ui.DatePicker. nil goog.i18n.DateTimeSymbols_cs)]
(.listen dp (.. goog.ui.DatePicker -Events -CHANGE)
#(js/console.info
(.. % -target getDate)))
(.render dp d)))
[:div {:ref show-datepicker}]
If you need to tear down the datepicker then just check for (nil? d) in your show-datepicker. React will pass nil when the component unmounts.
PS: I wound't use cljs-time unless you really like big js output files.
I am trying to use a React component from React Bootstrap in my rum app.
In my macros namespace I have some code that I found on the rum gitter :
(defn ->kebab [s]
(str/join "-" (map str/lower-case (re-seq #"\w[a-z]+" s))))
(defn gen-wrapper [component]
`(defmacro ~(symbol (->kebab (str component))) [& args#]
(let [[opts# & [children#]] (if (-> args# first map?)
[(first args#) (rest args#)]
[nil args#])]
`(js/React.createElement
~(symbol "js" (str "window.ReactBootstrap." (name '~component)))
(cljs.core/clj->js ~opts#)
~#children#))))
(def components '[Button
])
(defmacro gen-wrappers []
`(do
~#(clojure.core/map gen-wrapper components)))
Then in my devcard namespace I have:
(pm/gen-wrappers)
(rum/defc foo []
[:div (button nil "bggg")])
(defcard foo "" (foo))
The error is:
react.inc.js:18342 Uncaught Error: Invariant Violation: Objects are
not valid as a React child (found: js/React.createElement). If you
meant to render a collection of children, use an array instead or wrap
the object using createFragment(object) from the React add-ons. Check
the render method of foo.
This turned out to be an issue with clojurescript macros. Note that the macro gen-wrappers itself expands to a series of macros -- in this case the button macro. But in clojurescript, you can't call a macro that was defined in the same compilation stage, which I unfortunately tried to do by calling button right away.
The solution was to move the gen-wrappers call into the macros file along with the other macros:
(defmacro gen-wrappers []
`(do
~#(clojure.core/map gen-wrapper components)))
(gen-wrappers)
And then call the fully qualified pm/button from my devcard namespace.
(rum/defc foo []
[:div (pm/button nil "bggg")])
"But wait!" you say. "Aren't you making the same mistake here of calling one macro (gen-wrappers) from the same compilation stage it was defined in? Actually no, because in clojurescript, macros are defined in clojure files, in which that restriction does not apply.
Looking for solutions that push the envelope and:
Avoid
Manually writing SQL queries(Python can be more OO not passing DSL strings)
Using non-Python datatypes for a supposedly required model definition
Using a new class of types rather than perfectly good native Python types
Boast
Using Python objects
Using Object Oriented and key based retrieval and creation
Quick protoyping
No SQL table to make
Model /Type inference or no model
Less lines and characters to type
Easily output to and from JSON, maybe XML or even Protocol Buffers.
I do web, desktop and mobile software development so the more portable the better.
python
>> from someAmazingDB import *
>> db.taskList = []
>> db['taskList'].append({title:'Beat old sql interfaces','done':False})
>> db.taskList.append({title:'Illustrate different syntax modes','done':True})
#at this point it should autosave
#we should be able to reload the console and access like:
python
>> from someAmazingDB import *
>> print 'Done tasks'
>> for task in db.taskList:
>> if task.done:
>> print task
'Illustrate different syntax modes'
Here is the challenge: The above code should work with very little modification or thinking required. Like a different import statement and maybe a little more but Django Models and SQLAlchemy DO NOT CUT IT.
I'm looking for more interesting library suggestions than just "Try Shelve" or "use pickle"
I'm not opposed to Python classes being used for models but they should be really straight forward, unlike the stuff you see with Django and similar.
I've was actually working on something like this earlier today. There is no readme or sufficient tests yet, but... http://github.com/mikeboers/LiteMap/blob/master/litemap.py
The LiteMap class behaves much like the builtin dict, but it persists into a SQLite database. You did not indicate what particular database you were interested in, but this could be almost trivially modified to any back end.
It also does not track changes to mutable classes (e.g. like appending to the list in your example), but the API is really simple.
Database access doesn't get better than SQLAlchemy.
Care to explain what about Django's models you don't find straightforward? Here's how I'd do what you have in Django:
from django.db import models
class Task(models.Model):
title = models.CharField(max_length=...)
is_done = models.BooleanField()
def __unicode__(self):
return self.title
----
from mysite.tasks.models import Task
t = Task(title='Beat old sql interfaces', is_done=True)
t.save()
----
from mysite.tasks.models import Task
print 'Done tasks'
for task in Task.objects.filter(is_done=True):
print task
Seems pretty straightforward to me! Also, results in a slightly cleaner table/object naming scheme IMO. The trickier part is using Django's DB module separate from the rest of Django, if that's what you're after, but it can be done.
Using web2py:
>>> from gluon.sql import DAL, Field
>>> db=DAL('sqlite://stoarge.db')
>>> db.define_table('taskList',Field('title'),Field('done','boolean')) # creates the table
>>> db['taskList'].insert(title='Beat old sql interfaces',done=False)
>>> db.taskList.insert(title='Beat old sql interfaces',done=False)
>> for task in db(db.taskList.done==True).select():
>> print task.title
Supports 10 different database back-ends + google app engine.
Question looks strikingly similar to http://api.mongodb.org/python/1.9%2B/tutorial.html
So answer is pymongo, what else ;)
from pymongo import Connection
connection = Connection()
connection = Connection('localhost', 27017)
tasklist = db['test-tasklist']
tasklist.append({title:'Beat old sql interfaces','done':False})
db.tasklist.append({title:'Illustrate different syntax modes','done':True})
for task in db.tasklist.find({done:True}):
print task.title
I haven't tested the code but wont be very different than this
BTW Redish is also interesting and fun.