Commits

Kirill Simonov committed f9ec841

Added `/:sql` formatter.

  • Participants
  • Parent commits ee4d46f

Comments (0)

Files changed (10)

src/htsql/cmd/command.py

     format = TSVRenderer
 
 
+class SQLCmd(Command):
+
+    def __init__(self, producer):
+        assert isinstance(producer, Command)
+        self.producer = producer
+
+

src/htsql/cmd/retrieve.py

 
 
 from ..adapter import adapts, Utility
-from .command import RetrieveCmd
-from .act import act, Act, ProduceAction, AnalyzeAction
+from .command import RetrieveCmd, SQLCmd
+from .act import act, analyze, Act, ProduceAction, AnalyzeAction, RenderAction
 from ..tr.encode import encode
 from ..tr.rewrite import rewrite
 from ..tr.compile import compile
                 cursor = connection.cursor()
                 cursor.execute(plan.sql)
                 records = []
-                for row in cursor.fetchall():
+                for row in cursor:
                     values = []
                     for item, normalize in zip(row, normalizers):
                         value = normalize(item)
                 connection.commit()
                 connection.release()
             except DBError, exc:
-                raise EngineError("error while executing %r: %s"
-                                  % (plan.sql, exc))
+                raise EngineError("failed to execute a database query: %s"
+                                  % exc)
             except:
                 if connection is not None:
                     connection.invalidate()
         return plan
 
 
+class RenderSQL(Act):
+
+    adapts(SQLCmd, RenderAction)
+    def __call__(self):
+        plan = analyze(self.command.producer)
+        status = '200 OK'
+        headers = [('Content-Type', 'text/plain; charset=UTF-8')]
+        body = []
+        if plan.sql:
+            body = [plan.sql]
+        return (status, headers, body)
+
+

src/htsql/connect.py

         """
         Iterates over the rows of the result.
         """
-        # FIXME: guarding doesn't seem to work well with generators.
-        with self.guard:
-            for row in self.cursor:
-                yield row
+        iterator = iter(self.cursor)
+        while True:
+            with self.guard:
+                row = next(iterator, None)
+            if row is None:
+                break
+            yield row
 
     def close(self):
         """

src/htsql/tr/fn/bind.py

                         QuotientSig, AssignmentSig, DefineSig,
                         WhereSig, SelectSig, LinkSig)
 from ...cmd.command import (DefaultCmd, RetrieveCmd, TextCmd, HTMLCmd, JSONCmd,
-                            CSVCmd, TSVCmd)
+                            CSVCmd, TSVCmd, SQLCmd)
 import sys
 
 
     command = TSVCmd
 
 
+class BindSQL(BindFormat):
+
+    named('sql')
+    command = SQLCmd
+
+
 class BindNull(BindMacro):
 
     named('null', ('null', None))

test/regress/input/format.yaml

   - uri: /school/:retrieve
   - uri: /retrieve(/school)
   - uri: /school/:retrieve/:json
+  - uri: /school/:sql
+  - uri: /school/:retrieve/:sql
   # Errors
   - uri: /retrieve()
     expect: 400
     expect: 400
   - uri: /school/:html/:json
     expect: 400
+  - uri: /school/:html/:sql
+    expect: 400
 

test/regress/output/mssql.yaml

                 ["sc", "School of Continuing Studies", null]
               ]
             }
+        - uri: /school/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT [school].[code],
+                   [school].[name],
+                   [school].[campus]
+            FROM [ad].[school] AS [school]
+            ORDER BY 1 ASC
+        - uri: /school/:retrieve/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT [school].[code],
+                   [school].[name],
+                   [school].[campus]
+            FROM [ad].[school] AS [school]
+            ORDER BY 1 ASC
         - uri: /retrieve()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
             invalid request: unsupported action
+        - uri: /school/:html/:sql
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            invalid request: unsupported action

test/regress/output/mysql.yaml

                 ["sc", "School of Continuing Studies", null]
               ]
             }
+        - uri: /school/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT `school`.`code`,
+                   `school`.`name`,
+                   `school`.`campus`
+            FROM `htsql_regress`.`school` AS `school`
+            ORDER BY 1 ASC
+        - uri: /school/:retrieve/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT `school`.`code`,
+                   `school`.`name`,
+                   `school`.`campus`
+            FROM `htsql_regress`.`school` AS `school`
+            ORDER BY 1 ASC
         - uri: /retrieve()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
             invalid request: unsupported action
+        - uri: /school/:html/:sql
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            invalid request: unsupported action

test/regress/output/oracle.yaml

                 ["sc", "School of Continuing Studies", null]
               ]
             }
+        - uri: /school/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT "SCHOOL"."CODE",
+                   "SCHOOL"."NAME",
+                   "SCHOOL"."CAMPUS"
+            FROM "HTSQL_REGRESS"."SCHOOL" "SCHOOL"
+            ORDER BY 1 ASC
+        - uri: /school/:retrieve/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT "SCHOOL"."CODE",
+                   "SCHOOL"."NAME",
+                   "SCHOOL"."CAMPUS"
+            FROM "HTSQL_REGRESS"."SCHOOL" "SCHOOL"
+            ORDER BY 1 ASC
         - uri: /retrieve()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
             invalid request: unsupported action
+        - uri: /school/:html/:sql
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            invalid request: unsupported action

test/regress/output/pgsql.yaml

                 ["sc", "School of Continuing Studies", null]
               ]
             }
+        - uri: /school/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT "school"."code",
+                   "school"."name",
+                   "school"."campus"
+            FROM "ad"."school" AS "school"
+            ORDER BY 1 ASC
+        - uri: /school/:retrieve/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT "school"."code",
+                   "school"."name",
+                   "school"."campus"
+            FROM "ad"."school" AS "school"
+            ORDER BY 1 ASC
         - uri: /retrieve()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
             invalid request: unsupported action
+        - uri: /school/:html/:sql
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            invalid request: unsupported action

test/regress/output/sqlite.yaml

                 ["sc", "School of Continuing Studies", null]
               ]
             }
+        - uri: /school/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT "school"."code",
+                   "school"."name",
+                   "school"."campus"
+            FROM "school" AS "school"
+            ORDER BY 1 ASC
+        - uri: /school/:retrieve/:sql
+          status: 200 OK
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            SELECT "school"."code",
+                   "school"."name",
+                   "school"."campus"
+            FROM "school" AS "school"
+            ORDER BY 1 ASC
         - uri: /retrieve()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
             invalid request: unsupported action
+        - uri: /school/:html/:sql
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            invalid request: unsupported action