How do I set the refer-to column value in Lobos? - clojure

Using Lobos, my migrations look like:
(defmigration company-table
(up [] (create
(tbl :companies
(text name))))
(down [] (drop
(table :companies))))
(defmigration document-table
(up [] (create
(tbl :documents
(timestamp :date_of_event)
(text :title)
(text :name)
(refer-to :companies))))
(down [] (drop
(table :documents))))
I'd like to set the refer-to on documents s.t. the referring column name is company_id, e.g. (refer-to :companies as :company_id). How do I do this?

It doesn't look like the documentation is that great, but there are two ways to do this:
Using the foreign-key function
(defmigration document-table
(up [] (create
(table :documents
(timestamp :date_of_event)
(text :title)
(text :name)
(foreign-key :company-id :companies))))
;; or, if you need to specify options, you'd use something like this
(foreign-key :company-id :companies :on-delete :cascade))))
Using the [:refer tname & options] option.
(defmigration document-table
(up [] (create
(table :documents
(timestamp :date_of_event)
(text :title)
(text :name)
(integer :company-id [:refer companies]))))
;; or, if you need to specify options, you'd use something like this
(integer :company-id [:refer companies :on-delete :cascade]))))
Edit: Also, unless you defined your own function tbl, you probably mean table
Edit 2: It looks like the documentation here is much better.

Related

How to populate emacs completion collection when list items include spaces

New to Emacs:
I am trying to populate a completion collection from a sql query:
All goes according to plan except the completion list is ends up as individual words rather than the complete list item as a string with spaces.
(defun test_sql_interactive2()
(interactive)
(setq look (emacsql db2 [:select [Accounts:acc_name]:from Accounts]))
(setq var (completing-read
"Complete an Account Name: "
look
nil t ))
(insert var))
the variable look is the result of the sql query which returns:
((Collective Retirement Account) (Stocks and Shares) (Current Account) (Savings Account))
but the emacs completing-read function sees this as 8 words to use as the collection to complete from rather than 4 strings, so instead of "Collective Retirement Account" being offered as a completion, it is only "Collective".
How can I have the completion return the entire string with spaces?
Change the contents of the alist (value of look) that you pass to completing-read to be strings:
(("Collective Retirement Account")
("Stocks and Shares")
("Current Account")
("Savings Account"))
This does that:
(let ((look '((Collective Retirement Account)
(Stocks and Shares)
(Current Account)
(Savings Account))))
(mapcar (lambda (xx) (list (substring (format "%s" xx) 1 -1)))
look))

How to insert a whole fact in Clara without providing attribute values

The following Clara rule code inserts a fact by providing values for all the attributes of the fact type:
(defrule vips-200-promotion
"This rule creates a special promotion for VIPs that spend +$200"
[Customer (= true vip) (= ?customerId customerId)]
[Order (> total 200) (= ?customerId customerId)]
=>
(insert! (Promotion. "PROMO-XMAS" ?customerId)));;; Inserts a Promotion fact with promoId = PROMO-XMAS and customerId = value in ?customerId
(defquery get-promos
[]
[?promotion <- Promotion]).
But how can a fact, which has previously been bind, be inserted without providing values for its attributes (since you have the whole fact with values in the bind variable)?
Like here:
(defrule vips-promotion
"This rule creates a special promotion for VIPs"
[?customer <- Customer (= true vip) (= ?customerId customerId)]
=>
(insert! (Customer. ?customer)) ;;; This line fails since insert! is expecting values for all the fact's attribute, but I want to just pass ?customer, which contains the value of the matched Customer.
(defquery get-customers
[]
[?customerx <- customer])
Minor modification, adding <- to the binding:
(defrule vips-promotion
"This rule creates a special promotion for VIPs"
[?customer <- Customer (= true vip) (= ?customerId customerId)]
=>
(insert! (Customer. ?customer))
The simple answer here seems that you would have to add a Copy constructor to the Customer class.
On a side note, a rule like that mentioned above would loop forever as the rhs(Right Hand Side) insert would then trigger the lhs(Left Hand Side) which would then trigger the rhs and repeating forever due to the nature of forward chaining rules engines.

Google App Engine Query matches case [duplicate]

Using the google appengine datastore, is there a way to perform a gql query that specifies a WHERE clause on a StringProperty datatype that is case insensitive? I am not always sure what case the value will be in. The docs specify that the where is case sensitive for my values, is there a way to make this insensitive?
for instance the db Model would be this:
from google.appengine.ext import db
class Product(db.Model):
id = db.IntegerProperty()
category = db.StringProperty()
and the data looks like this:
id category
===================
1 cat1
2 cat2
3 Cat1
4 CAT1
5 CAT3
6 Cat4
7 CaT1
8 CAT5
i would like to say
gqlstring = "WHERE category = '{0}'".format('cat1')
returnvalue = Product.gql(gqlstring)
and have returnvalue contain
id category
===================
1 cat1
3 Cat1
4 CAT1
7 CaT1
I don't think there is an operator like that in the datastore.
Do you control the input of the category data? If so, you should choose a canonical form to store it in (all lowercase or all uppercase). If you need to store the original case for some reason, then you could just store two columns - one with the original, one with the standardized one. That way you can do a normal WHERE clause.
The datastore doesn't support case insensitive comparisons, because you can't index queries that use them (barring an index that transforms values). The solution is to store a normalized version of your string in addition to the standard one, as Peter suggests. The property classes in the AETycoon library may prove helpful, in particular, DerivedProperty.
This thread was helpful and makes me want to contribute with similar approach to make partial search match possible. I add one more field on datastore kind and save each word on normalized phrase as a set and then use IN filter to collide. This is an example with a Clojure. Normalize part should easy translate to java at least (thanks to #raek on #clojure), while database interaction should be convertable to any language:
(use '[clojure.contrib.string :only [split lower-case]])
(use '[appengine-magic.services.datastore :as ds])
; initialize datastore kind entity
(ds/defentity AnswerTextfield [value, nvalue, avalue])
; normalize and lowercase a string
(defn normalize [string-to-normalize]
(lower-case
(apply str
(remove #(= (Character/getType %) Character/NON_SPACING_MARK)
(java.text.Normalizer/normalize string-to-normalize java.text.Normalizer$Form/NFKD)))))
; save original value, normalized value and splitted normalized value
(defn textfield-save! [value]
(ds/save!
(let [nvalue (normalize value)]
(ds/new* AnswerTextfield [value nvalue (split #" " nvalue)]))))
; normalized search
(defn search-normalized [value]
(ds/query :kind AnswerTextfield
:filter [(= :nvalue (normalize value))]))
; partial normalized word search
(defn search-partial [value]
(flatten
(let [coll []]
(for [splitted-value (split #" " (normalize value))]
(merge coll
(ds/query :kind AnswerTextfield
:filter [(in :avalue [splitted-value])]))))))

clojure - add item to nested set

Say I have a set like this:
#{#{"a"} #{"b"} #{"c"}}
Say I wanted to updated the middle set to make s become:
#{#{"a"} #{"be"} #{"c"}}
How would I achieve this?
(-> #{#{"a"} #{"b"} #{"c"}} (disj #{"b"}) (conj #{"be"}))
=> #{#{"a"} #{"be"} #{"c"}}
(of course there's no ordering in sets, it could well be shown in any order).

Lisp, add new list to db in "for" loop, why returning NIL?

I wonder, how can I print in LISP each new value from loop "for" in new list, which each time creates by calling the function.
I have created the func:
(defun make (id name surname) (list :id id :name name :surname surname) )
Here I created the global variable:
(defvar *db* nil)
And here I defined the func for adding each new value to store it in db:
(defun add (cd) (push cd *db*))
So, I'm able to add each new data to db, like that:
(add (make 0 "Oleg" "Orlov" ) )
To look the content of my db , I can use:
*db*
So, I wonder how to put each new record-list to db using "for" loop, I print values in "for" loop in lisp like this:
(loop for i from 1 to 10 do ( ... ))
If , I use:
(loop for i from 0 to 10 do (add (make i "Oleg" "Orlov") ) )
If you read db using *db* you will see, that all evelen records were added, but after calling the last line, you will get NIL result in return.
Why do I catch NIL result, not T and what does it mean?
Thanks, best regards!
Every form in Lisp evaluates to something.
If a form you type in doesn't return a value, it will evaluate to NIL by default (otherwise, it evaluates to the value(s) it returns). Your loop doesn't actually return a value itself; it just performs 10 assignments (each of the intermediate expressions do return a value, but you don't collect and return them). Therefore, that code will return NIL.
If you haven't done so already, check out chapter 3 of Practical Common Lisp, in which Peter Seibel goes step-by-step through creating a simple database. It might give you some insights into the basics of how Lisp works. The specific question you ask (why forms return NIL by default, and what it means specifically in the context of Common Lisp) is answered in chapter 2 of the same book
As for how you would explicitly cause your loop to emit the list of items it added to *db*, try the following
(loop for i from 1 to 10
for elem = (make i "Oleg" "Orlov")
do (add elem)
collect elem)