Nested namespaced keys in HugSQL Query - clojure

I have a nested map with namespaced keys like this:
{
:model.person/primary {:model.person/name "John Smith"}
}
Instead of simpliying this into a flat map I'd like to pass it straight through to a HugSQL function. The docs say HugSQL supports a deep parameter get and namespaced keys but I'm not sure how to combine them.
(hugsql/def-sqlvec-fns-from-string
"-- :name get_person :? :1
-- :doc Get a person
SELECT * FROM person WHERE name = :value:model.person/primary:model.person/name")
Now if I execute the function it generates with my original map I get this:
(get_person-sqlvec {:model.person/primary {:model.person/name "John Smith"}})
Execution error (ExceptionInfo) at hugsql.core/validate-parameters! (core.clj:83).
Parameter Mismatch: :model.person/name parameter data not found.
I would imagine the variable naming convention in the SQL is the source of the problem:
:value:model.person/primary:model.person/name
But I'm not sure what the correct value should be.

First off, the deep parameter get uses . between keys, not :, so that is part of your problem.
However, right now HugSQL only supports one level of qualified keywords -- because there is an inherent ambiguity between . for separating deep parameter get keys and the . that can be part of (qualified) keywords.
You could have where name = :value:model.person/primary.name and then a hash map like {:model.person/primary {:name "John Smith"}}
Or you could have where name = :value:model.person/name and pass {:model.person/name "John Smith"}
HugSQL will need a different syntax to support nested qualified keys (to resolve the . ambiguity). I mentioned Selmer's approach to Curtis Summers, HugSQL's maintainer: using .. to indicate the dot that is part of a keyword, so you could have:
where name = :value:model..person/primary.model..person/name
(that's how Selmer indicates nested qualified keys) but there are backward compatibility issues to consider as well as whether that's a good syntax in the first place (I'm a heavy user of Selmer and I don't like that, but I understand why they did it).

Related

How can I use datomic's pull method to grab an entity by its entity id?

How can I retrieve an entity using the pull method by its entity id? I've used transact to add some datoms/facts (right phrasing?) to my db. I can see the entity id's if I do a simple query like:
[:find ?e
:where
[?e :arb/value]
]
The result being:
{[17592186045418] [17592186045420] [17592186045423]}
Now I'd like to retrieve one of these using pull. The examples in the docs for pull, however, use examples where the entity in question is associated with an id.
Specifically, the docs refer to an example from the musicbrainz sample data set, and the sample they suggest is:
(pull db '[*] led-zeppelin)
where (although the docs don't show this) led-zeppelin has been defined like so (as can be seen here:
(def led-zeppelin [:artist/gid #uuid "678d88b2-87b0-403b-b63d-5da7465aecc3"])
The docs say that the pull command takes three things: a db, a selector pattern determining I think what attributes are pulled for each entity, and the "eid" of the entity. So the above led-zeppelin var is somehow the eid.
I don't really follow totally what's going on there. The :artist/gid is a id attribute defined in the schema for musicbrainz it seems, and the third item looks like the the specific id. I'm not sure what #uuid is.
But, in my case, I have defined no id attribute for my entities. I was hoping to be able to use the unique entity id that I think is assigned by default to each entity. Is this possible? If so, how would this be done?
The solution here is simple. Just drop in the entity id number directly:
(d/pull db '[*] 17592186045418)
The mistake I'd made was to use the eid as a string, i.e. by double-quoting it.
Pulls third argument is a reference to an entity. You can either use one of the IDs that your query returned, or a lookup ref, like in the led-zepplin example, where you refer to an entity using a unique attribute value.
The purpose of a query is to find the EID of something given one or more of it's properties. If you already know the EID, you don't need a query, you just want to retrieve the attr/val pairs for that entity. So use the entity function:
(let [eid 12345
result (into {} (d/entity db eid)) ]
(println result))
Note that the result of (d/entity ...) is lazy and you need to force it into a clojure map to see all of the items.
Besides Datomic's own documentation, you can find more examples and unit tests in the Tupelo Datomic library. Besides containing many convenience functions, the James Bond example helps to clarify some of the Datomic concepts.

Variable dump shows data but returns as undefined

Hopefully this is a "DOH" moment but I can't figure out why this is happening. I am using a service object to get the members of a group in Google's Directory API. After creating the service object I used the following lines to test
<cfset themembers = groupservice.members().list("[My Group Key]").execute()>
<cfdump var="#themembers#">
<cfoutput>
Isnull? #isNull(themembers.etag)#<br />
SKExists? #structKeyExists(themembers,"etag")#<br />
Is Defined? #isDefined("themembers.etag")#
</cfoutput>
The resulting output of the code looks like this
Looking at the dump I can see there is data in the etag field as well as an array of members. However, when I tried to output the key value I was getting an undefined error. I wrote a test output line and it's showing as NULL and not defined while the key DOES exist.
How is this possible when the dump of the variable clearly shows data? What am I missing here?
#Leigh
<cfdump var="#groupservice.members()#">
<cfdump var="#groupservice.members().list('[groupkey]')#">
Here are the dumps from the 2 lines above. The list method simply returns the groupkey name that i'm passing in - it's only after I run the execute method do I actually get the list of members (output in first image) but just like with the etag - it tells me members is undefined.
Short answer:
Apparently this falls under the general rule of "Never trust CFDump. Sometimes it lies." Case in point, the variable themembers is not really a structure. It is an instance of the Members class. Instead of using dot notation, try invoking the relevant methods of the class:
<cfset eTag = themembers.getETag()>
<cfset membersArray = themembers.getMembers()>
..
Longer Answer:
While CFDump is a good debugging tool, it tends to favor "pretty presentation" over accuracy, so you cannot always trust what you see. The reason it displays themembers as a "struct" is because ColdFusion automatically matches Java types to ColdFusion types. If you take a look at the class hierarchy of Members, you can see it implements java.util.Map (via AbstractMap), which is automatically matched to a CF structure. Hence why CFDump (misleadingly) displays it as one.
- com.google.api.services.admin.directory.model.Members
- com.google.api.client.json.GenericJson
- com.google.api.client.util.GenericData
- java.util.AbstractMap
- java.lang.Object
Although java objects are similar to structures, in some respects, they are not the same thing. So the results from certain functions may differ from what you would normally expect for structures, which is what happened here. i.e. You can view some of the property names, like you can with structure keys, but you cannot access the key/property values directly.
That said, technically you should have been able to access the "eTag" and "members" properties with dot notation. The reason being that CF applies a bit of syntactic sugar to certain java objects to allow direct access of properties using dot notation. Just as if they were regular structure keys.
ColdFusion can automatically invoke get_PropertyName_() and
set_PropertyName_(value) methods if a Java class conforms to the
JavaBeans pattern. As a result, you can set or get the property by
referencing it directly, without having to explicitly invoke a method.
However, as the docs note later on, there are some exceptions. This class appears to be one of them. So you will need to call the appropriate getPropertyName() methods explicitly. Ultimately, that is probably the best practice anyway, given that direct access does not always work.
Example:
// Simulate Members object
obj = createObject("java", "com.google.api.services.admin.directory.model.Members").init();
// Initialize property values
obj.setEtag("If you are seeing this text, it worked.");
obj.setMembers( [] );
writeOutput("<br>IsNull? "& isNull(obj.etag));
writeOutput("<br>Key List: "& structKeyList(obj));
writeOutput("<br>Exists? "& structKeyExists(obj, "etag"));
writeOutput("<br>IsDefined? "& IsDefined("obj.etag"));
writeOutput("<br>getETag(): "& obj.getETag());
writeDump(var=obj.getMembers(), label="getMembers()");
Results:
IsNull? YES
Key List: etag,members
Exists? YES
IsDefined? NO
getETag(): If you are seeing this text, it worked.
getMembers(): (empty array)
The way I get around the undefined structure values is to use structKeyArray to make an array of the keys in the struct. Then, loop over the array to check if the struct key exists. Example:
//result is a structure which can have undefined values
myAry = structKeyArray(result);
myLen = arrayLen(myAry);
for (i=1; i <= myLen;i=i+1){
if(!structKeyExists(result, "#myAry[i]#")){
result[myAry[i]] = "";
}
}
Of course, you might not want blank strings, but in my circumstance, that is what I was looking for if it didn't exist.

"operator does not exist character varying = bigint" in GnuHealth project

We are developing the module in tryton based on GNU Health.We got the following error :
ProgrammingError: operator does not exist character varying = bigint
Hint: No opreator matches the given name and argument type(s). You might need to add explicit type casts
As best as I can vaguely guess from the limited information provided, in this query:
"SELECT name,age,dob,address FROM TABLENAME WHERE pmrn=%s" % (self.pmrn)
you appear to be doing a string substitution of a value into a query.
First, this is dangerously wrong, and you should never ever do it without an extremely good reason. Always use parameterized queries. psycopg2 supports these, so there's no excuse not to. So do all the other Python interfaces for PostgreSQL, but I'm assuming you're using psycopg2 because basically everyone does, so go read the usage documentation to see how to pass query parameters.
Second, as a result of failing to use parameterized queries, you aren't getting any help from the database driver with datatype handling. You mentioned that pmrn is of type char - for which I assume you really meant varchar; if it's actually char then the database designers need to be taken aside for a firm talking-to. Anyway, if you substitute an unquoted number in there your query is going to look like:
pmrn = 201401270001
and if pmrn is varchar that'll be an error, because you can't compare a text type to a number directly. You must pass the value as text. The simplistic way is to put quotes around it:
pmrn = '201401270001'
but what you should be doing instead is letting psycopg2 take care of all this for you by using parameterized queries. E.g.
curs.execute("SELECT name,age,dob,address FROM TABLENAME WHERE pmrn=%s", (self.pmrn,))
i.e. pass the SQL query as a string, then a 1-tuple containing the query params. (You might have to convert self.pmrn to str if it's an int, too, eg str(self.pmrn)).

How can I provide data to a tempo template?

I'm trying to combine auto-insert and tempo templates to fill new files with the right content automatically.
My goal is to make auto-insert call a tempo template, providing it with some data (a class' name for example).
Something like this :
(eval-after-load 'autoinsert
'(define-auto-insert
(cons "\\.\\([Hh]\\|hh\\|hpp\\)\\'" "My C / C++ header")
(lambda()
(tempo-template-c++-class))))
I'd like to provide the C++ class template the buffer's file name so it can expand nicely. Ideally, creating a file named 'foo.h' would expand the template with 'foo' as data, creating the 'foo' class.
I tried to play around with the "save list" as explained in the Tempo Manual, but no luck so far.
Thanks for the help.
En passant, is there a better way than
(file-name-sans-extension (file-name-nondirectory buffer-file-name))
to get a class name from the file's?
C-h f tempo-define-template RET gives a list of template elements and their meaning:
A string: It is sent to the hooks in `tempo-insert-string-functions',
and the result is inserted.
...
Anything else: It is evaluated and the result is treated as an
element to be inserted. One additional tag is useful for these
cases. If an expression returns a list '(l foo bar), the elements
after `l' will be inserted according to the usual rules. This makes
it possible to return several elements from one expression.
So just put (file-name-sans-extension (file-name-nondirectory buffer-file-name)) in the template where you want the class name (and yes, I think this is indeed the best way to get a class name out of a file name).

SharePoint UserData and the ;# Syntax in returned data

Can a SharePoint expert explain to me the ;# in data returned by the GetListItems() call to the Lists web service?
I think I understand what they are doing here. The ;# is almost like a syntax for making a comment... or better yet, including the actual data (string) and not just the ID. This way you can use either, but they are nicely paired together in the same column.
Am I way off base? I just can't figure out the slighly different use. For example
I have a list with:
ows_Author
658;#Tyndall, Bruno
*in this case the 658 seems to be an ID for me in a users table somewhere*
ows_CreatedDate (note: a custom field. not ows_Created)
571;#2009-08-31 23:41:58
*in this case the 571 seems to be an ID of the row I'm already in. Why the repetition?*
Can anyone out there shed some light on this aspect of SharePoint?
The string ;# is used as a delimiter by SharePoint's lookup fields, including user fields. When working with the object model, you can use SPFieldLookupValue and SPFieldUserValue to convert the delimited string into a strongly-typed object. When working with the web services, however, I believe you'll need to parse the string yourself.
You are correct that the first part is an integer ID: ID in the site user list, or ID of the corresponding item in the lookup list. The second part is the user name or value of the lookup column.
Nicolas correctly notes that this delimiter is also used for other composite field values, including...
SPFieldLookupValueCollection
SPFieldMultiColumnValue
SPFieldMultiChoiceValue
SPFieldUserValueCollection
The SPFieldUser inherits from the SPFieldLookup which uses the ;# notation. You can easily parse the value by creating a new instance of the SPFieldLookupValue class:
string rawValue = "1;#value";
SPFieldLookupValue lookupValue = new SPFieldLookupValue(rawValue);
string value = lookupValue.LookupValue; // returns value