Advertisement
Guest User

Untitled

a guest
Jan 29th, 2018
304
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.27 KB | None | 0 0
  1. % language=uk
  2.  
  3. % author : Hans Hagen, PRAGMA ADE, NL
  4. % license : Creative Commons, Attribution-NonCommercial-ShareAlike 3.0 Unported
  5.  
  6. usemodule[art-01,abr-02]
  7.  
  8. definecolor
  9. [maincolor]
  10. [r=.4]
  11.  
  12. setupbodyfont
  13. [10pt]
  14.  
  15. setuptype
  16. [color=maincolor]
  17.  
  18. setuptyping
  19. [color=maincolor]
  20.  
  21. definefont
  22. [TitlePageFont]
  23. [file:lmmonolt10-bold.otf]
  24.  
  25. setuphead
  26. [color=maincolor]
  27.  
  28. usesymbols
  29. [cc]
  30.  
  31. setupinteraction
  32. [hidden]
  33.  
  34. startdocument
  35. [metadata:author=Hans Hagen,
  36. metadata:title=SQL in ConTeXt,
  37. author=Hans Hagen,
  38. affiliation=PRAGMA ADE,
  39. location=Hasselt NL,
  40. title=SQL in CONTEXT,
  41. support=www.contextgarden.net,
  42. website=www.pragma-ade.nl]
  43.  
  44. startMPpage
  45.  
  46. StartPage ;
  47.  
  48. numeric w ; w := bbwidth(Page) ;
  49. numeric h ; h := bbheight(Page) ;
  50.  
  51. fill Page withcolor MPcolor{maincolor} ;
  52.  
  53. draw textext.urt("TitlePageFont Q") xysized (1.1 w,0.9 h) shifted (-.05w,.05h) withcolor .20white ;
  54. draw textext.top("TitlePageFont SQL") xysized (0.4725w,0.13h) shifted (.675w,.24w) withcolor .60white ;
  55. draw textext.top("TitlePageFont CONTEXT") xsized (0.6 w) shifted (.675w,.10w) withcolor .60white ;
  56.  
  57. StopPage ;
  58.  
  59. stopMPpage
  60.  
  61. startsubject[title=Contents]
  62.  
  63. placelist[section][alternative=a]
  64.  
  65. stopsubject
  66.  
  67. startsection[title=Introduction]
  68.  
  69. Although CONTEXT is a likely candidate for typesetting content that comes from
  70. databases it was only in 2011 that I ran into a project where a connection was
  71. needed. After all, much document related typesetting happens on files or
  72. dedicated storage systems.
  73.  
  74. Because we run most projects in an infrastructure suitable for TEX, it made
  75. sense to add some helper scripts to the CONTEXT core distribution that deal
  76. with getting data from (in our case) MYSQL databases. That way we can use the
  77. already stable infrastructure for installing and updating files that comes with
  78. CONTEXT.
  79.  
  80. As LUA support is nicely integrated in CONTEXT, and as dealing with
  81. information from databases involves some kind of programming anyway, there is (at
  82. least currently) no TEX interface. The examples shown here work in CONTEXT,
  83. but you need to keep in mind that LUA scripts can also use this interface.
  84.  
  85. {em Although this code is under construction the interfaces are unlikely to
  86. change, if only because we use it on production.}
  87.  
  88. stopsection
  89.  
  90. startsection[title=Presets]
  91.  
  92. In order to consult a database you need to provide credentials. You also need
  93. to reach the database server, either by using some client program or via a
  94. library. More about that later.
  95.  
  96. Because we don't want to key in all that information again and again, we will
  97. collect it in a table. This also permits us to store it in a file and load it
  98. on demand. For instance:
  99.  
  100. starttyping
  101. local presets = {
  102. database = "test",
  103. username = "root",
  104. password = "none",
  105. host = "localhost",
  106. port = 3306,
  107. }
  108. stoptyping
  109.  
  110. You can put a table in a file type {presets.lua} like this:
  111.  
  112. starttyping
  113. return {
  114. database = "test",
  115. username = "root",
  116. password = "none",
  117. host = "localhost",
  118. port = 3306,
  119. }
  120. stoptyping
  121.  
  122. and then load it as follows:
  123.  
  124. starttyping
  125. local presets = table.load("presets.lua")
  126. stoptyping
  127.  
  128. If you really want, you can use some library to open a connection, execute a
  129. query, collect results and close the connection, but here we use just one
  130. function that does it all. The presets are used to access the database and the
  131. same presets will be used more often it makes sense to keep a connection open as
  132. long as possible. That way you can execute much more queries per second,
  133. something that makes sense when there are many small ones, as in web related
  134. services. A connection is made persistent when the presets have an type {id}
  135. key, like
  136.  
  137. starttyping
  138. presets.id = "myproject"
  139. stoptyping
  140.  
  141. stopsection
  142.  
  143. startsection[title=Templates]
  144.  
  145. A query often looks like this:
  146.  
  147. starttyping
  148. SELECT
  149. `artist`, `title`
  150. FROM
  151. `cd`
  152. WHERE
  153. `artist` = 'archive' ;
  154. stoptyping
  155.  
  156. However, often you want to use the same query for multiple lookups, in which case
  157. you can do this:
  158.  
  159. starttyping
  160. SELECT
  161. `artist`, `title`
  162. FROM
  163. `cd`
  164. WHERE
  165. `artist` = '%artist%' ;
  166. stoptyping
  167.  
  168. In the next section we will see how type {%artist%} can be replaced by a more
  169. meaningful value. You can a percent sign by entering two in a row: type {%%}.
  170.  
  171. As with any programming language that deals with strings natively, you need a
  172. way to escape the characters that fence the string. In SQL a field name is
  173. fenced by type {``} and a string by type {''}. Field names can often be
  174. used without type {``} but you can better play safe.
  175.  
  176. starttyping
  177. `artist` = 'Chilly Gonzales'
  178. stoptyping
  179.  
  180. Escaping of the type {'} is simple:
  181.  
  182. starttyping
  183. `artist` = 'Jasper van''t Hof'
  184. stoptyping
  185.  
  186. When you use templates you often pass a string as variable and you don't want to
  187. be bothered with escaping them. In the previous example we used:
  188.  
  189. starttyping
  190. `artist` = '%artist%'
  191. stoptyping
  192.  
  193. When you expect embedded quotes you can use this:
  194.  
  195. starttyping
  196. `artist` = '%[artist]%'
  197. stoptyping
  198.  
  199. In this case the variable {artist} will be escaped. When we reuse a template we
  200. store it in a variable:
  201.  
  202. starttyping
  203. local template = [[
  204. SELECT
  205. `artist`, `title`
  206. FROM
  207. `cd`
  208. WHERE
  209. `artist` = '%artist%' ;
  210. ]]
  211. stoptyping
  212.  
  213. stopsection
  214.  
  215. startsection[title=Queries]
  216.  
  217. In order to execute a query you need to pass the previously discussed presets
  218. as well as the query itself.
  219.  
  220. starttyping
  221. local data, keys = utilities.sql.execute {
  222. presets = presets,
  223. template = template,
  224. variables = {
  225. artist = "Dream Theater",
  226. },
  227. }
  228. stoptyping
  229.  
  230. The variables in the presets table can also be passed at the outer
  231. level. In fact there are three levels of inheritance: settings, presets
  232. and module defaults.
  233.  
  234. starttabulate
  235. NC presets NC a table with values NC NR
  236. NC template NC a query string NC NR
  237. NC templatefile NC a file containing a template NC NR
  238. NC em resultfile NC a (temporary) file to store the result NC NR
  239. NC em queryfile NC a (temporary) file to store a query NC NR
  240. NC variables NC variables that are subsituted in the template NC NR
  241. NC username NC used to connect to the database NC NR
  242. NC password NC used to connect to the database NC NR
  243. NC host NC the quote {machine} where the database server runs on NC NR
  244. NC port NC the port where the database server listens to NC NR
  245. NC database NC the name of the database NC NR
  246. stoptabulate
  247.  
  248. The type {resultfile} and type {queryfile} parameters are used when a client
  249. approach is used. When a library is used all happens in memory.
  250.  
  251. When the query succeeds two tables are returned: type {data} and type {keys}. The
  252. first is an indexed table where each entry is a hash. So, if we have only one
  253. match and that match has only one field, you get something like this:
  254.  
  255. starttyping
  256. data = {
  257. {
  258. key = "value"
  259. }
  260. }
  261.  
  262. keys = {
  263. "key"
  264. }
  265. stoptyping
  266.  
  267. stopsection
  268.  
  269. startsection[title=Converters]
  270.  
  271. All values in the result are strings. Of course we could have provided some
  272. automatic type conversion but there are more basetypes in MYSQL and some are
  273. not even standard SQL. Instead the module provides a converter mechanism
  274.  
  275. starttyping
  276. local converter = utilities.sql.makeconverter {
  277. { name = "id", type = "number" },
  278. { name = "name", type = "string" },
  279. { name = "enabled", type = "boolean" },
  280. }
  281. stoptyping
  282.  
  283. You can pass the converter to the execute function:
  284.  
  285. starttyping
  286. local data, keys = utilities.sql.execute {
  287. presets = presets,
  288. template = template,
  289. converter = converter,
  290. variables = {
  291. name = "Hans Hagen",
  292. },
  293. }
  294. stoptyping
  295.  
  296. In addition to numbers, strings and booleans you can also use a function
  297. or table:
  298.  
  299. starttyping
  300. local remap = {
  301. ["1"] = "info"
  302. ["2"] = "warning"
  303. ["3"] = "debug"
  304. ["4"] = "error"
  305. }
  306.  
  307. local converter = utilities.sql.makeconverter {
  308. { name = "id", type = "number" },
  309. { name = "status", type = remap },
  310. }
  311. stoptyping
  312.  
  313. I use this module for managing CONTEXT jobs in web services. In that case we
  314. need to store jobtickets and they have some common properties. The definition of
  315. the table looks as follows: footnote {The tickets manager is part of the
  316. CONTEXT distribution.}
  317.  
  318. starttyping
  319. CREATE TABLE IF NOT EXISTS %basename% (
  320. `id` int(11) NOT NULL AUTO_INCREMENT,
  321. `token` varchar(50) NOT NULL,
  322. `subtoken` INT(11) NOT NULL,
  323. `created` int(11) NOT NULL,
  324. `accessed` int(11) NOT NULL,
  325. `category` int(11) NOT NULL,
  326. `status` int(11) NOT NULL,
  327. `usertoken` varchar(50) NOT NULL,
  328. `data` longtext NOT NULL,
  329. `comment` longtext NOT NULL,
  330.  
  331. PRIMARY KEY (`id`),
  332. UNIQUE INDEX `id_unique_index` (`id` ASC),
  333. KEY `token_unique_key` (`token`)
  334. )
  335. DEFAULT CHARSET = utf8 ;
  336. stoptyping
  337.  
  338. We can register a ticket from (for instance) a web service and use an independent
  339. watchdog to consult the database for tickets that need to be processed. When the
  340. job is finished we register this in the database and the web service can poll for
  341. the status.
  342.  
  343. It's easy to imagine more fields, for instance the way CONTEXT is called, what
  344. files to use, what results to expect, what extra data to pass, like style
  345. directives, etc. Instead of putting that kind of information in fields we store
  346. them in a LUA table, serialize that table, and put that in the data field.
  347.  
  348. The other way around is that we take this data field and convert it back to LUA.
  349. For this you can use a helper:
  350.  
  351. starttyping
  352. local results = utilities.sql.execute { ... }
  353.  
  354. for i=1,#results do
  355. local result = results[i]
  356. result.data = utilities.sql.deserialize(result.data)
  357. end
  358. stoptyping
  359.  
  360. Much more efficient is to use a converter:
  361.  
  362. starttyping
  363. local converter = utilities.sql.makeconverter {
  364. ...
  365. { name = "data", type = "deserialize" },
  366. ...
  367. }
  368. stoptyping
  369.  
  370. This way you don't need to loop over the result and deserialize each data
  371. field which not only takes less runtime (often neglectable) but also takes
  372. less (intermediate) memory. Of course in some cases it can make sense to
  373. postpone the deserialization.
  374.  
  375. A variant is not to store a serialized data table, but to store a key|-|value
  376. list, like:
  377.  
  378. starttyping
  379. data = [[key_1="value_1" key_2="value_2"]]
  380. stoptyping
  381.  
  382. Such data fields can be converted with:
  383.  
  384. starttyping
  385. local converter = utilities.sql.makeconverter {
  386. ...
  387. { name = "data", type = utilities.parsers.keq_to_hash },
  388. ...
  389. }
  390. stoptyping
  391.  
  392. You can imagine more converters like this, and if needed you can use them to
  393. preprocess data as well.
  394.  
  395. starttabulate[|Tl|p|]
  396. NC "boolean" NC This converts a string into the value type {true} or type {false}.
  397. Valid values for type {true} are: type {1}, type {true}, type
  398. {yes}, type {on} and type {t} NC NR
  399. NC "number" NC This one does a straightforward type {tonumber} on the value. NC NR
  400. NC function NC The given function is applied to value. NC NR
  401. NC table NC The value is resolved via the given table. NC NR
  402. NC "deserialize" NC The value is deserialized into LUA code. NC NR
  403. NC "key" NC The value is used as key which makes the result table is now hashed
  404. instead of indexed. NC NR
  405. NC "entry" NC An entry is added with the given name and optionally with a default
  406. value. NC NR
  407. stoptabulate
  408.  
  409. stopsection
  410.  
  411. startsection[title=Typesetting]
  412.  
  413. For good reason a CONTEXT job often involves multiple passes. Although the
  414. database related code is quite efficient it can be considered a waste of time
  415. and bandwidth to fetch the data several times. For this reason there is
  416. another function:
  417.  
  418. starttyping
  419. local data, keys = utilities.sql.prepare {
  420. tag = "table-1",
  421. ...
  422. }
  423.  
  424. -- do something useful with the result
  425.  
  426. local data, keys = utilities.sql.prepare {
  427. tag = "table-2",
  428. ...
  429. }
  430.  
  431. -- do something useful with the result
  432. stoptyping
  433.  
  434. The type {prepare} alternative stores the result in a file and reuses
  435. it in successive runs.
  436.  
  437. stopsection
  438.  
  439. startsection[title=Methods]
  440.  
  441. Currently we have several methods for accessing a database:
  442.  
  443. starttabulate
  444. NC client NC use the command line tool, pass arguments and use files NC NR
  445. NC library NC use the standard library (somewhat tricky in LUATEX as we need to work around bugs) NC NR
  446. NC lmxsql NC use the library with a LUA based pseudo client (stay in the LUA domain) NC NR
  447. NC swiglib NC use the (still experimental) library that comes with LUATEX NC NR
  448. stoptabulate
  449.  
  450. All methods use the same interface (type {execute}) and hide the dirty details
  451. for the user. All return the data and keys tables and all take care of the proper
  452. escaping and parsing.
  453.  
  454. stopsection
  455.  
  456. startsection[title=Helpers]
  457.  
  458. There are some helper functions and extra modules that will be described when
  459. they are stable.
  460.  
  461. There is an quote {extra} option to the type {context} command that can be used
  462. to produce an overview of a database. You can get more information about this
  463. with the command:
  464.  
  465. starttyping
  466. context --extra=sql-tables --help
  467. stoptyping
  468.  
  469. stopsection
  470.  
  471. startsection[title=Colofon]
  472.  
  473. starttabulate[|B|p|]
  474. NC author NC getvariable{document}{author}, getvariable{document}{affiliation}, getvariable{document}{location} NC NR
  475. NC version NC currentdate NC NR
  476. NC website NC getvariable{document}{website} endash getvariable{document}{support} NC NR
  477. NC copyright NC symbol[cc][cc-by-sa-nc] NC NR
  478. stoptabulate
  479.  
  480. stopsection
  481.  
  482. stopdocument
  483.  
  484. documentclass{article}
  485. % this is preamble, if need
  486. begin{titlepage}
  487. beginfig (1);
  488. %this is code from ConTeXt
  489. endfig;
  490. end.
  491. end{titlepage}
  492. begin{document}
  493. Context to LaTeX
  494. end{document}
  495.  
  496. documentclass[a4paper,10pt]{article}
  497.  
  498. usepackage{eso-pic}
  499.  
  500. usepackage{luamplib}
  501.  
  502. usepackage{fontspec}
  503. newfontfamilyTitlePageFont{lmmonolt10-bold.otf}
  504. begin{document}
  505.  
  506. AddToShipoutPictureFG*{%
  507. begin{mplibcode}
  508. input "mp-tool.mpiv" ;
  509.  
  510. beginfig(0) ;
  511.  
  512. path Page ; Page := unitsquare xscaled (mpdim{paperwidth}) yscaled (mpdim{paperheight}) ;
  513.  
  514. numeric w ; w := bbwidth(Page) ;
  515. numeric h ; h := bbheight(Page) ;
  516.  
  517. fill Page withcolor .4red ;
  518.  
  519. draw textext.urt("TitlePageFont Q") xysized (1.1 w,0.9 h) shifted (-.05w,.05h) withcolor .20white ;
  520. draw textext.top("TitlePageFont SQL") xysized (0.4725w,0.13h) shifted (.675w,.24w) withcolor .60white ;
  521. draw textext.top("TitlePageFont CONTEXT") xsized (0.6 w) shifted (.675w,.10w) withcolor .60white ;
  522.  
  523. endfig ;
  524. end{mplibcode}%
  525. }
  526.  
  527. % Generate a page
  528. leavevmode
  529. thispagestyle{empty}
  530.  
  531. end{document}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement