1votos

SQL String Generator en Haskell

por josejuan hace 6 años

No es una solución completa (sólo es la idea). En Haskell, puede usarse QuasiQuotation para embeber el código SQL y detectar errores en tiempo de compilación así como generar código optimizado y nativo.

Write a DSL to generate valid SQL statements for SELECT, INSERT, UPDATE and DELETE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
{-- 
 
  La idea es embeber las consultas SQL dentro 
  del código Haskell (eg. en el archivo de modelo) para 
  que éstas sean validadas contra un servidor real SQL 
  en tiempo de compilación del código. 
 
  Ventajas: 
 
  - las consultas se validan en tiempo de compilación, arrojando cualquier 
    error que pueda producirse contra el motor real. 
 
  - las consultas pueden escribirse en (eg.) ANSI SQL y transformarse 
    en tiempo de compilación a SQL nativo del motor en cuestión. 
 
  - al compilarse las consultas a código nativo, el rendimiento en tiempo 
    de ejecución es mucho menor (el código que se ejecuta es nativo y 
    directo de la consulta escrita). 
 
  - las consultas están en el modelo. 
 
--} 
 
import Language.Haskell.TH 
import Language.Haskell.TH.Quote 
import Data.Char 
 
sql :: QuasiQuoter 
sql = QuasiQuoter sqlExp undefined undefined undefined 
 
sqlExp :: String -> ExpQ 
sqlExp input = case parseSql input of 
           Right result -> litE $ stringL result 
           Left error -> fail error 
 
-- A partir de aquí es únicamente un parser. 
-- La idea sería generar el código de acceso a la base de datos en tiempo de compilación, 
--  validando la consulta obteniendo los datos desde la bbdd, realizando test unitarios, etc... 
-- Actualmente únicamente se genera una cadena. 
parseSql :: String -> Either String String 
parseSql xs | "SELECT" == cmd = Right "SELECT ..." -- genera la consulta y valida en tiempo de compilación 
            | "UPDATE" == cmd = Right "UPDATE ..." 
            | "INSERT" == cmd = Right "INSERT ..." 
            | "DELETE" == cmd = Right "UPDATE ..." 
            | otherwise = Left "SQL parse error, unknow instruction" 
  where xs' = removeWhites xs 
        cmd = (map toUpper . take 6) xs' 
 
removeWhites :: String -> String 
removeWhites = dropWhile (flip elem " \t\n\r") 
 
{-- Test --------- 
 
 cmd1 = [sql| select a ,b, c from tabla |] 
 
 cmd2 = [sql|   insert into tabla1 ( 
                       a, 
                select a = 3 * b, 
                       b = a - b 
                from   tabla2 
                where  not a in ( 
                          select a 
                          from   tabla 1 
        |] 
 
 cmd3 = [sql|        SELECT  a.pk, 
                             n = COUNT(DISTINCT b.pk), 
                             s = SUM(a.factor * b.accumulated) 
                     FROM    TABLEA a 
                     JOIN    TABLEB b 
                     ON      a.pk = b.foreignPk 
                     WHERE   b.status = 'Enabled' 
                     GROUP 
                     BY      a.pl 
                     HAVING  MAX(b.accumulated) < 50 
        |] 
 
--} 
2 comentarios
0votos

Escrito por jneira hace 6 años

Imprezionante, ya hasta usando macros.
0votos

Escrito por josejuan hace 6 años

XD XD me alegro, debo agradecérselo a Yesod, es realmente impresionante lo bien hecho que está, muy muy cuidado; el despliegue de funcionalidad quizás no sea tan alto como otros frameworks, pero es una maravilla lo bien pensadas que están las soluciones.

Yesod usa QuasiQuotes para las plantillas de marcado (html, css y js), compila las plantillas y detecta errores en tiempo de compilación, minimiza el js, etc...

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.