<div dir="ltr">I haven't read this fully, but you are indeed correct in that there is a relationship between the identifier [tab], which is a value of type [sql_table _ _] (where the two type arguments are filled in with something), and [Tab], which is an ordinary (type-level) value of kind [Name].<div><br></div><div>I believe this special relationship is only for SQL syntactic sugar in SELECT statements. When constructing the queries using the raw functions in Basis (see lib/ur/basis.urs), you can associate names with tables however you like. For UPDATE and DELETE statements, there's always only one table, and its associated name is hard-coded as [#T], though if you use the syntactic sugar this name never appears.</div><div><br></div><div>I spent a lot of time digging into basis.urs because I wanted to write the a function that abstracts the pattern</div><div><br></div><div>SELECT fields FROM table WHERE table.KeyColumn = {[keyValue]}</div><div><br></div><div>and couldn't do it with the syntactic sugar. It don't really have time to walk through it now (it's on my blog post queue, but that queue moves slowly...), but here it is below it in case it helps understanding of what's really going on behind the syntactic sugar. In particular, the table ([tab] in your code)  is passed in as the [(tab : tTab)] argument, while the name associated with it in the query is [#T] and could easily have been anything else.</div><div><br></div><div>Best,</div><div>Ziv</div><div><br></div><div><br></div><div>PS: Here's the code. In retrospect, using a functor like Crud does is probably a better approach for this. It allows you to bind local table variables to inputs of the functor (like [table tab = M.tab] in crud.ur), which allows one to use the typical syntactic sugar. It's when the table is passed in as a function argument that you need to resort to the messiness below. The one downside, as you've discovered, is that you have an extra entanglement between two names, but my opinion is that it's probably mostly worth it :).</div><div><br></div><div><div>fun sqlWhereEq [nKey :: Name] [vals :: {Type}] [[nKey] ~ vals]</div><div>               [tKey] (_ : sql_injectable tKey)</div><div>               [other ::: {Type}] [[nKey] ~ other] [vals ~ other]</div><div>               [tTab] (_ : fieldsOf tTab ([nKey = tKey] ++ vals ++ other))</div><div>               (tab : tTab) (key : tKey)</div><div>               : sql_query [] [] _ _ =</div><div>    let</div><div>        val q1 =</div><div>            sql_query1</div><div>                [[]]</div><div>                {Distinct = False,</div><div>                 From = sql_from_table [#T] tab,</div><div>                 Where = sql_binary sql_eq</div><div>                                    (sql_field [#T] [nKey])</div><div>                                    (sql_inject key),</div><div>                 GroupBy = sql_subset [[T = ([nKey = tKey] ++ vals ++ other,</div><div>                                             [])]],</div><div>                 Having = sql_inject True,</div><div>                 SelectFields = sql_subset [[T = (vals,</div><div>                                                  [nKey = tKey] ++ other)]],</div><div>                 SelectExps = {}}</div><div>    in</div><div>        sql_query</div><div>            {Rows = q1,</div><div>             OrderBy = sql_order_by_Nil [[]],</div><div>             Limit = sql_no_limit,</div><div>             Offset = sql_no_offset}</div><div>    end</div></div><div><br></div><div>Example usage: row <- oneRow1 (sqlWhereEq [#Id] [[Name = string, Age = int]] usersTable userId)</div><div><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Sep 1, 2015 at 1:45 PM, Stefan Scott <span dir="ltr"><<a href="mailto:stefanscottalexx@gmail.com" target="_blank">stefanscottalexx@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div>Consider the (only) two occurrences of the identifier `Tab` in file crud.ur in the Crud demos, in the function `upd (r : int)`, on lines 126 and 138, underscored using the coomment `(*   ^^^  *)` in the excerpt quoted here below:<br></div><div><br></div><div><a href="http://hg.impredicative.com/urweb/file/010ce27228f1/demo/crud.ur#l126" target="_blank">http://hg.impredicative.com/urweb/file/010ce27228f1/demo/crud.ur#l126</a></div><div><br></div><div><a href="http://www.impredicative.com/ur/demo/crud.ur.html" target="_blank">http://www.impredicative.com/ur/demo/crud.ur.html</a><br></div><div><br></div><div> fso <- oneOrNoRows (SELECT tab.{{map fst M.cols}} FROM tab WHERE tab.Id = {[id]});</div><div>        case fso : (Basis.option {Tab : $(map fst M.cols)}) of</div><div>                             (*   ^^^  *)</div><div>            None => return <xml><body>Not found!</body></xml></div><div>          | Some fs => return <xml><body><form></div><div>            {@foldR2 [fst] [colMeta] [fn cols => xml form [] (map snd cols)]</div><div>              (fn [nm :: Name] [t ::_] [rest ::_] [[nm] ~ rest] v (col : colMeta t)</div><div>                               (acc : xml form [] (map snd rest)) =></div><div>                  <xml></div><div>                    <li> {cdata col.Nam}: {col.WidgetPopulated [nm] v}</li></div><div>                    {useMore acc}</div><div>                  </xml>)</div><div>              <xml/></div><div>              M.fl fs.Tab M.cols}</div><div>                 (*   ^^^  *)</div><div>            <submit action={save}/></div><div>          </form></body></xml></div><div><br></div><div>What if we change these two occurrences of the (upper-case) identifier, from `Tab` to `Tabx` - leaving the lower-case identifier `tab` (which also occurs many times elsewhere in the module) unchanged?</div><div><br></div><div>The code no longer compiles! It gives the following error:</div><div><br></div><div>crud.ur:126:32: (to 126:70) Error in final record unification</div><div><br></div><div>Can't unify record constructors</div><div>   Have: </div><div>[Distinct = bool, </div><div>  From =</div><div>   sql_from_items ([])</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols]),</div><div>                                                                        </div><div>  Where =</div><div>   sql_exp</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([]) ([]) bool, </div><div>  GroupBy =</div><div>   sql_subset</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols]),</div><div>                                                                        </div><div>  Having =</div><div>   sql_exp</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([]) bool, </div><div>  SelectFields =</div><div>   sql_subset</div><div>    ([Tab = (map (fn t :: (Type * Type) => t.1) M.cols) ++ [Id = int]])</div><div>    ([Tab = map (fn t :: (Type * Type) => t.1) M.cols]), </div><div>  SelectExps = {}]</div><div>   Need: </div><div>[Distinct = bool, </div><div>  From =</div><div>   sql_from_items ([])</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols]),</div><div>                                                                        </div><div>  Where =</div><div>   sql_exp</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([]) ([]) bool, </div><div>  GroupBy =</div><div>   sql_subset</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols]),</div><div>                                                                        </div><div>  Having =</div><div>   sql_exp</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([]) bool, </div><div>  SelectFields =</div><div>   sql_subset</div><div>    ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div>    ([Tabx = map (fn t :: (Type * Type) => t.1) M.cols]), </div><div>  SelectExps = {}]</div><div>  Field:  #SelectFields</div><div><br></div><div>Value 1: </div><div>sql_subset</div><div> ([Tab = (map (fn t :: (Type * Type) => t.1) M.cols) ++ [Id = int]])</div><div> ([Tab = map (fn t :: (Type * Type) => t.1) M.cols])</div><div><br></div><div>Value 2: </div><div>sql_subset</div><div> ([Tab = ([Id = int]) ++ map (fn t :: (Type * Type) => t.1) M.cols])</div><div> ([Tabx = map (fn t :: (Type * Type) => t.1) M.cols])</div><div><br></div><div>Can't unify record constructors</div><div><br></div><div>Have:  [Tab = map (fn t :: (Type * Type) => t.1) M.cols]</div><div>Need:  [Tabx = map (fn t :: (Type * Type) => t.1) M.cols]</div><div><br></div><div>$ </div><div><br></div><div>The above suggests that there is some sort of "relationship":</div><div><br></div><div>BETWEEN:</div><div><br></div><div>(1) the *lower-case* identifier `tab`:</div><div><br></div><div>  - whose *type* is *declared* (in the parameter signature of the declaration of Crud.Make in crud.urs and crud.ur) as follows:</div><div><br></div><div>      table tab : ([Id = int] ++ map fst cols)</div><div><br></div><div>  - and whose *value* is *defined* in (eg) crud1.ur, in the argument in the call to Crud.Make, as follows:</div><div><br></div><div>      val tab = t1</div><div><br></div><div>  ... where (eg) the table `t1` (defined earlier in crud1.ur) is in lexical scope:</div><div><br></div><div>      table t1 : {Id : int, A : int, B : string, C : float, D : bool}</div><div><br></div><div>VERSUS:</div><div><br></div><div>(2) the *upper-case* identifier `Tab` - which appears to be:</div><div><br></div><div>  - (a) a *field name* whose presence is being "asserted", or</div><div><br></div><div>  - (b) (perhaps?) a *pattern* being assigned to in some sort of record-level or type-level pattern-matching - in the "type declaration" - or "assertion?" or "pattern-matching"?? - provided for `fso` in the `case` statement (*after* `fso` was "created", by the way):</div><div><br></div><div>      case fso : (Basis.option {Tab : $(map fst M.cols)}) of ... </div><div><br></div><div>---</div><div><br></div><div>I have several questions arising from the above:</div><div><br></div><div>(1) What is this relationship between identifier `tab` and identifier `Tab` here? </div><div><br></div><div>One appears to refer to a table, the other appears to be a field.</div><div><br></div><div>Is there some sort of pattern-matching or assertion or assignment going on between them?</div><div><br></div><div><br></div><div>(2) This compile error seems to indicate that identifier `tab` and identifier `Tab` need to be the *same* (except for upper-case versus lower-case). </div><div><br></div><div>Is this true? </div><div><br></div><div>If so, why? </div><div><br></div><div>(2.1) Is it true that an Ur/Web database application can be associated with exactly *one* SQL database (mentioned in the .urp file)? </div><div><br></div><div>(2.2) If (2.1) is true, then is there some relationship:</div><div><br></div><div>BETWEEN:</div><div><br></div><div>- the namespace of unique (upper-case) *field names* defined at the "top level" of an Ur/Web program;</div><div><br></div><div>VERSUS </div><div><br></div><div>- the namespace of unique (lower-case) identifiers assigned to *table names* - in statements such as:</div><div><br></div><div>  table t1 : {Id : int, A : int, B : string, C : float, D : bool}<br></div><div><br></div><div>which generate CREATE TABLE statements in the *.sql script (with names optionally mangled with a "uw_" prefix) for the associated SQL database mentioned in the .urp file?<br></div><div><br></div><div>(3) What does the syntax:</div><div><br></div><div>  {Tab : $(map fst M.cols)}</div><div><br></div><div>ie:</div><div><br></div><div>  { ... : ... }</div><div><br></div><div>mean?</div><div><br></div><div><br></div><div>(3.1) Is the syntax `{ ... : ... }` an instance of the following kind-level production in section 4.2, page 15 of the manual:</div><div><br></div><div>  Kinds κ ::=</div><div>    ...</div><div>    {κ}    type-level records</div><div>    ...</div><div><br></div><div>Question (3.1.1) If so, is this perhaps somehow combined with some *other* production(s) in the present case, to yield (in the present example):</div><div><br></div><div>  {Tab : $(map fst M.cols)}</div><div><br></div><div><br></div><div>(3.1.2) Could the other production being combined here be: </div><div><br></div><div>  Kind ::= Type</div><div><br></div><div>(also from Section 4.2, page 15)<br></div><div><br></div><div>in this case instantiating ``Type`` as:</div><div><br></div><div>  Tab : $(map fst M.cols)</div><div><br></div><div>?</div><div><br></div><div>Question (3.2) Is the above syntax `{ ... : ... }` as used eg in:</div><div><br></div><div>{Tab : $(map fst M.cols)}<br></div><div><br></div><div>related to the "table-definition syntax" (seen frequently in the examples - but never actually explicitly described "as such" in the manual), eg:</div><div><br></div><div>  table t1 : {Id : int, A : int, B : string, C : float, D : bool}</div><div><br></div><div>?<br></div><div><br></div><div><br></div><div>(3.3) Is this syntax `{ ... : ... }`  as used eg in:</div><div><br></div><div>  {Tab : $(map fst M.cols)}</div><div><br></div><div>perhaps also somehow related to the following fragment of code in basis.urs - in particular, the section underscored using the comment `(*   ^^^  *)`:</div><div><br></div><div><a href="http://hg.impredicative.com/urweb/file/010ce27228f1/lib/ur/basis.urs#l488" target="_blank">http://hg.impredicative.com/urweb/file/010ce27228f1/lib/ur/basis.urs#l488</a></div><div><br></div><div>val sql_field : otherTabs ::: {{Type}} -> otherFields ::: {Type}</div><div> -> fieldType ::: Type -> agg ::: {{Type}}</div><div> -> exps ::: {Type}</div><div> -> tab :: Name -> field :: Name</div><div> -> sql_exp</div><div>        ([tab = [field = fieldType] ++ otherFields] ++ otherTabs)</div><div>    (*  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  *)</div><div>        agg exps fieldType</div><div><br></div><div><br></div><div>(4) Finally, the manual (towards the bottom of page 19) states:</div><div><br></div><div>  A declaration </div><div><br></div><div>    table x : {(c = c,)∗} </div><div><br></div><div>  is elaborated into </div><div><br></div><div>    table x : [(c = c,)∗]</div><div><br></div><div>However, a *different* syntax is commonly seen in the "table declarations" frequently used in the demos - ie, in the demos, the "copulas" are `:` not `=`, eg:</div><div><br></div><div>  table t1 : {Id : int, A : int, B : string, C : float, D : bool}</div><div><br></div><div>(4.1) What does the following syntax in the manual (using `=` not `:`) refer to:</div><div><br></div><div>  table x : {(c = c,)∗}</div><div>  table x : [(c = c,)∗]</div><div><br></div><div>(4.2) Are the any examples of its use?</div><div><br></div><div><br></div><div>Thanks for any help!</div><div><br></div><div>###</div><div><br></div><div><br></div></div>
<br>_______________________________________________<br>
Ur mailing list<br>
<a href="mailto:Ur@impredicative.com" target="_blank">Ur@impredicative.com</a><br>
<a href="http://www.impredicative.com/cgi-bin/mailman/listinfo/ur" rel="noreferrer" target="_blank">http://www.impredicative.com/cgi-bin/mailman/listinfo/ur</a><br>
<br></blockquote></div><br></div></div>