Changeset 872

Show
Ignore:
Timestamp:
12/03/08 13:04:38 (5 weeks ago)
Author:
xi
Message:

Ported json and yaml formatters.

Location:
branches/forest-queries
Files:
6 modified

Legend:

Unmodified
Added
Removed
  • branches/forest-queries/htsql/commands/descriptors.py

    r871 r872  
    6666                           (element.entity.__class__.__name__.lower() 
    6767                            if element.entity is not None else None), 
    68                            (str(element.entity) 
     68                           (str(element.entity.identifier()) 
    6969                            if element.entity is not None else None)]) 
    7070 
  • branches/forest-queries/htsql/commands/formatters.py

    r866 r872  
    7070        self.product = product 
    7171        self.profiles = product.profile.segments 
    72         self.labels = range(len(product.profile.segments)) 
    73         self.parents = self.init_parents() 
    74         self.children = self.init_children() 
    75         self.depths = self.init_depths() 
     72        self.labels = product.profile.labels 
     73        self.parents = product.profile.parents 
     74        self.children = product.profile.children 
     75        self.depths = product.profile.depths 
    7676        self.titles = self.init_titles() 
    7777        self.branches = self.init_branches() 
     
    7979    def __iter__(self): 
    8080        assert False, "abstract method" 
    81  
    82     def init_parents(self): 
    83         parents = [] 
    84         for label in self.labels: 
    85             profile = self.profiles[label] 
    86             parent_profile = profile.parent 
    87             if parent_profile is not None: 
    88                 parent = self.profiles.index(parent_profile) 
    89             else: 
    90                 parent = None 
    91             parents.append(parent) 
    92         return parents 
    93  
    94     def init_children(self): 
    95         children = { None: [] } 
    96         for label in self.labels: 
    97             children[label] = [] 
    98             children[self.parents[label]].append(label) 
    99         return children 
    100  
    101     def init_depths(self): 
    102         depths = { None: -1 } 
    103         for label in self.labels: 
    104             depths[label] = depths[self.parents[label]]+1 
    105         return depths 
    10681 
    10782    def init_titles(self): 
     
    606581    declaration = [ 
    607582            ('generic', BOOL(), False), 
    608             ('flat', BOOL(), False), 
    609583            ('unfold', BOOL(), False), 
    610584            ('prune', BOOL(), False), 
     
    682656        return data 
    683657 
     658    def build_titles(self, segments): 
     659        segment_titles = [] 
     660        element_titles = [] 
     661        for segment in segments: 
     662            segment_titles.append(str(segment.title)) 
     663            titles = [] 
     664            element_titles.append(titles) 
     665            for element in segment.elements: 
     666                chain = [] 
     667                if (isinstance(element.title, descriptions.CompositeTitle) 
     668                        and not self.unfold): 
     669                    for item in element.title.chain(): 
     670                        if isinstance(item, descriptions.FunctionTitle): 
     671                            chain.append(str(item.function)) 
     672                        else: 
     673                            chain.append(str(item)) 
     674                elif isinstance(element.title, descriptions.FunctionTitle): 
     675                    chain.append(str(element.title.function)) 
     676                else: 
     677                    chain.append(str(element.title)) 
     678                titles.append(chain) 
     679        return segment_titles, element_titles 
     680 
    684681    def build(self, product): 
    685682        """Construct the normal tree representation.""" 
    686         row_stack = [[]] 
    687         for row in product: 
    688             elements = row.description.elements 
    689             fields = self.mapping_class() 
    690             for element, item in zip(elements, row): 
    691                 output = self.output(element.domain, item) 
    692                 if (not self.unfold 
    693                 and isinstance(element.title, descriptions.CompositeTitle)): 
    694                     title_chain = [] 
    695                     for item in element.title.chain(): 
    696                         if isinstance(item, descriptions.FunctionTitle): 
    697                             title_chain.append(str(item.function)) 
    698                         else: 
    699                             title_chain.append(str(item)) 
     683        children = product.profile.children 
     684        segment_titles, titles = self.build_titles(product.profile.segments) 
     685        rows = iter(product) 
     686        mapping = self.mapping_class() 
     687        collection = { None: [mapping] } 
     688        label = None 
     689        while True: 
     690            for child_label in children[label]: 
     691                title = segment_titles[child_label] 
     692                if title in mapping: 
     693                    raise errors.InvalidQuery("duplicate title '%s'" % title, 
     694                                              self.mark) 
     695                collection[child_label] = mapping[title] = [] 
     696            try: 
     697                row = rows.next() 
     698            except StopIteration: 
     699                break 
     700            label = row.label 
     701            elements = product.profile.segments[label].elements 
     702            mapping = self.mapping_class() 
     703            collection[label].append(mapping) 
     704            for element, item, title_chain in zip(elements, row, titles[label]): 
     705                item = self.output(element.domain, item) 
     706                fields = mapping 
     707                for title in title_chain[:-1]: 
     708                    if title not in fields: 
     709                        fields[title] = self.mapping_class() 
     710                    elif not isinstance(fields[title], self.mapping_class): 
     711                        raise errors.InvalidQuery("duplicate title '%s'" 
     712                                                  % title, self.mark) 
     713                    fields = fields[title] 
     714                title = title_chain[-1] 
     715                if title in fields: 
     716                    raise errors.InvalidQuery("duplicate title '%s'" 
     717                                              % title, self.mark) 
     718                if (isinstance(element.domain, domains.Composite) 
     719                        and self.unfold and item is not None): 
     720                    for key in item: 
     721                        fields["%s.%s" % (title, key)] = item[key] 
    700722                else: 
    701                     if isinstance(element.title, descriptions.FunctionTitle): 
    702                         title_chain = [str(element.title.function)] 
    703                     else: 
    704                         title_chain = [str(element.title)] 
    705                 mapping = fields 
    706                 for title in title_chain[:-1]: 
    707                     if title not in mapping: 
    708                         mapping[title] = self.mapping_class() 
    709                     elif not isinstance(mapping[title], self.mapping_class): 
    710                         raise errors.InvalidQuery("duplicate title", 
    711                                                   self.input.mark) 
    712                     mapping = mapping[title] 
    713                 title = title_chain[-1] 
    714                 if title in mapping: 
    715                     raise errors.InvalidQuery("duplicate title", 
    716                                               self.input.mark) 
    717                 if (self.unfold and 
    718                         isinstance(element.domain, domains.Composite) and 
    719                         output is not None): 
    720                     for key in output: 
    721                         mapping["%s.%s" % (title, key)] = output[key] 
    722                 else: 
    723                     mapping[title] = output 
    724             del row_stack[row.index+1:] 
    725             rows = [] 
    726             if row.index < len(product.description.segments)-1: 
    727                 title = product.description.segments[row.index+1].title 
    728                 if title is None: 
    729                     title = '' 
    730                 else: 
    731                     title = str(title) 
    732                 if title in fields: 
    733                     raise errors.InvalidQuery("duplicate title", 
    734                                               self.input.mark) 
    735                 fields[title] = rows 
    736             row_stack[-1].append(fields) 
    737             row_stack.append(rows) 
    738         data = row_stack[0] 
     723                    fields[title] = item 
     724        root = collection[None][0] 
     725        if len(root) == 1: 
     726            root = root.values()[0] 
    739727        if self.prune: 
    740             data = self.prune_data(data) 
    741         return data 
     728            root = self.prune_data(root) 
     729        return root 
    742730     
    743731    def build_generic(self, product): 
    744732        """Construct a simple, "generic" representation """ 
    745         row_stack = [[]] 
     733        children = product.profile.children 
     734        collection = {} 
     735        top = [] 
     736        for child_label in children[None]: 
     737            sequence = [] 
     738            collection[child_label] = sequence 
     739            top.append(sequence) 
    746740        for row in product: 
    747             elements = row.description.elements 
    748             fields = [self.output(element.domain, item) 
    749                       for element, item in zip(elements, row)] 
    750             del row_stack[row.index+1:] 
    751             rows = [] 
    752             if row.index < len(product.description.segments)-1: 
    753                 fields.append(rows) 
    754             row_stack[-1].append(fields) 
    755             row_stack.append(rows) 
    756         return row_stack[0] 
     741            elements = row.profile.elements 
     742            fields = [] 
     743            for element, item in zip(elements, row): 
     744                fields.append(self.output(element.domain, item)) 
     745            for child_label in children[row.label]: 
     746                sequence = [] 
     747                collection[child_label] = sequence 
     748                fields.append(sequence) 
     749            collection[row.label].append(fields) 
     750        if len(top) == 1: 
     751            top = top[0] 
     752        return top 
    757753 
    758754    def format(self, product): 
    759         if product.has_content(): 
    760             if self.flat: 
    761                 product = product.flatten() 
     755        if product: 
    762756            if self.generic: 
    763757                tree = self.build_generic(product) 
     
    797791        data = simplejson.dumps(tree, sort_keys=True, indent=self.indent) 
    798792        return [data, "\n"] 
     793 
    799794 
    800795class YAML(TreeFormatter): 
  • branches/forest-queries/htsql/commands/transformers.py

    r870 r872  
    134134 
    135135    def convert_generator(self, generator, profile): 
    136         children = { None: [] } 
    137         for label, segment in enumerate(profile.segments): 
    138             parent_label = None 
    139             if segment.parent is not None: 
    140                 parent_label = profile.segments.index(segment.parent) 
    141             children[label] = [] 
    142             children[parent_label].append(label) 
    143136        widths = {} 
    144137        for label, segment in reversed(list(enumerate(profile.segments))): 
     
    150143            widths[label] += len(segment.elements) 
    151144            widths[parent_label] += widths[label] 
    152         generator = FlattenGenerator(generator, children, widths) 
     145        generator = FlattenGenerator(generator, profile.children, widths) 
    153146        return iter(generator) 
    154147 
     
    270263        return Product(iter(new_rows), new_profile, None) 
    271264 
     265 
  • branches/forest-queries/htsql/descriptions.py

    r866 r872  
    163163        self.title = title 
    164164        self.segments = segments 
     165        self.labels = range(len(segments)) 
     166        self.parents = [] 
     167        self.children = { None: [] } 
     168        self.depths = { None: -1 } 
     169        for label in self.labels: 
     170            segment = self.segments[label] 
     171            parent_label = self.segments.index(segment.parent)  \ 
     172                           if segment.parent is not None else None 
     173            self.parents.append(parent_label) 
     174            self.children[parent_label].append(label) 
     175            self.children[label] = [] 
     176            self.depths[label] = self.depths[parent_label]+1 
    165177 
    166178 
  • branches/forest-queries/test/expect.yaml

    r871 r872  
    85388538        - [Content-Type, text/plain; charset=UTF-8] 
    85398539        body: |2 
    8540            | request (1 of 1)                                                                                                                          | 
    8541           =+===========================================================================================================================================+= 
    8542            | title       : /organization/                                                                                                              | 
    8543            | authority   : "htsql_regress":"owner"                                                                                                     | 
    8544            | perspective : "htsql_regress":"owner"                                                                                                     | 
    8545            \                                                                                                                                           / 
     8540           | request (1 of 1)                                                                             | 
     8541          =+==============================================================================================+= 
     8542           | title       : /organization/                                                                 | 
     8543           | authority   : "htsql_regress":"owner"                                                        | 
     8544           | perspective : "htsql_regress":"owner"                                                        | 
     8545           \                                                                                              / 
    85468546                segment (1 of 1) 
    8547               +=====================================================================================================================================+ 
    8548               | parent{title} :                                                                                                                     | 
    8549               | title         : organization                                                                                                        | 
    8550               \                                                                                                                                     / 
     8547              +========================================================================================+ 
     8548              | parent{title} :                                                                        | 
     8549              | title         : organization                                                           | 
     8550              \                                                                                        / 
    85518551                   element 
    8552                  +-------------------------------------------------------------------------------------------------------------------------------+ 
    8553                  | title       | domain{class} | domain{name}        | entity{class} | entity{name}                                              | 
    8554                  +-------------+---------------+---------------------+---------------+-----------------------------------------------------------+ 
    8555                  | org_id      | string        | "character varying" | columnfield   | "htsql_regress":"owner"."op":"organization"."org_id"      | 
    8556                  | name        | string        | "character varying" | columnfield   | "htsql_regress":"owner"."op":"organization"."name"        | 
    8557                  | is_active   | boolean       | boolean             | columnfield   | "htsql_regress":"owner"."op":"organization"."is_active"   | 
    8558                  | division_of | string        | "character varying" | keyfield      | "htsql_regress":"owner"."op":"organization"."division_of" | 
    8559                                                                                                                                           (4 rows) 
     8552                 +----------------------------------------------------------------------------------+ 
     8553                 | title       | domain{class} | domain{name}        | entity{class} | entity{name} | 
     8554                 +-------------+---------------+---------------------+---------------+--------------+ 
     8555                 | org_id      | string        | "character varying" | columnfield   | org_id       | 
     8556                 | name        | string        | "character varying" | columnfield   | name         | 
     8557                 | is_active   | boolean       | boolean             | columnfield   | is_active    | 
     8558                 | division_of | string        | "character varying" | keyfield      | division_of | 
     8559                                                                                             (4 rows) 
    85608560 
    85618561           ----- 
     
    85668566        - [Content-Type, text/plain; charset=UTF-8] 
    85678567        body: |2 
    8568            | request (1 of 1)                                                                                                                          | 
    8569           =+===========================================================================================================================================+= 
    8570            | title       : /organization/person/                                                                                                       | 
    8571            | authority   : "htsql_regress":"owner"                                                                                                     | 
    8572            | perspective : "htsql_regress":"owner"                                                                                                     | 
    8573            \                                                                                                                                           / 
     8568           | request (1 of 1)                                                                             | 
     8569          =+==============================================================================================+= 
     8570           | title       : /organization/person/                                                          | 
     8571           | authority   : "htsql_regress":"owner"                                                        | 
     8572           | perspective : "htsql_regress":"owner"                                                        | 
     8573           \                                                                                              / 
    85748574                segment (1 of 2) 
    8575               +=====================================================================================================================================+ 
    8576               | parent{title} :                                                                                                                     | 
    8577               | title         : organization                                                                                                        | 
    8578               \                                                                                                                                     / 
     8575              +========================================================================================+ 
     8576              | parent{title} :                                                                        | 
     8577              | title         : organization                                                           | 
     8578              \                                                                                        / 
    85798579                   element 
    8580                  +-------------------------------------------------------------------------------------------------------------------------------+ 
    8581                  | title       | domain{class} | domain{name}        | entity{class} | entity{name}                                              | 
    8582                  +-------------+---------------+---------------------+---------------+-----------------------------------------------------------+ 
    8583                  | org_id      | string        | "character varying" | columnfield   | "htsql_regress":"owner"."op":"organization"."org_id"      | 
    8584                  | name        | string        | "character varying" | columnfield   | "htsql_regress":"owner"."op":"organization"."name"        | 
    8585                  | is_active   | boolean       | boolean             | columnfield   | "htsql_regress":"owner"."op":"organization"."is_active"   | 
    8586                  | division_of | string        | "character varying" | keyfield      | "htsql_regress":"owner"."op":"organization"."division_of" | 
    8587                                                                                                                                           (4 rows) 
     8580                 +----------------------------------------------------------------------------------+ 
     8581                 | title       | domain{class} | domain{name}        | entity{class} | entity{name} | 
     8582                 +-------------+---------------+---------------------+---------------+--------------+ 
     8583                 | org_id      | string        | "character varying" | columnfield   | org_id       | 
     8584                 | name        | string        | "character varying" | columnfield   | name         | 
     8585                 | is_active   | boolean       | boolean             | columnfield   | is_active    | 
     8586                 | division_of | string        | "character varying" | keyfield      | division_of | 
     8587                                                                                             (4 rows) 
    85888588 
    85898589                segment (2 of 2) 
    8590               +=====================================================================================================================================+ 
    8591               | parent{title} : organization                                                                                                        | 
    8592               | title         : person                                                                                                              | 
    8593               \                                                                                                                                     / 
     8590              +========================================================================================+ 
     8591              | parent{title} : organization                                                           | 
     8592              | title         : person                                                                 | 
     8593              \                                                                                        / 
    85948594                   element 
    8595                  +-------------------------------------------------------------------------------------------------------------------------------+ 
    8596                  | title       | domain{class} | domain{name}        | entity{class} | entity{name}                                              | 
    8597                  +-------------+---------------+---------------------+---------------+-----------------------------------------------------------+ 
    8598                  | org_id      | string        | "character varying" | keyfield      | "htsql_regress":"owner"."op":"person"."org_id"            | 
    8599                  | nickname    | string        | "character varying" | columnfield   | "htsql_regress":"owner"."op":"person"."nickname"          | 
    8600                  | full_name   | string        | "character varying" | columnfield   | "htsql_regress":"owner"."op":"person"."full_name"         | 
    8601                  | email       | string        | "character varying" | columnfield   | "htsql_regress":"owner"."op":"person"."email"             | 
    8602                                                                                                                                           (4 rows) 
     8595                 +----------------------------------------------------------------------------------+ 
     8596                 | title       | domain{class} | domain{name}        | entity{class} | entity{name} | 
     8597                 +-------------+---------------+---------------------+---------------+--------------+ 
     8598                 | org_id      | string        | "character varying" | keyfield      | org_id       | 
     8599                 | nickname    | string        | "character varying" | columnfield   | nickname     | 
     8600                 | full_name   | string        | "character varying" | columnfield   | full_name    | 
     8601                 | email       | string        | "character varying" | columnfield   | email        | 
     8602                                                                                             (4 rows) 
    86038603 
    86048604           ----- 
     
    86088608        headers: 
    86098609        - [Content-Type, application/x-javascript; charset=UTF-8] 
    8610         body: "[\n  {\n    \"segment\": [\n      {\n        \"element\": [\n     \ 
    8611           \     {\n            \"domain\": {\n              \"class\": \"string\"\ 
     8610        body: "[\n  {\n    \"authority\": \"\\\"htsql_regress\\\":\\\"owner\\\"\"\ 
     8611          , \n    \"perspective\": \"\\\"htsql_regress\\\":\\\"owner\\\"\", \n   \ 
     8612          \ \"segment\": [\n      {\n        \"element\": [\n          {\n       \ 
     8613          \     \"domain\": {\n              \"class\": \"string\", \n           \ 
     8614          \   \"name\": \"\\\"character varying\\\"\"\n            }, \n         \ 
     8615          \   \"entity\": {\n              \"class\": \"columnfield\", \n        \ 
     8616          \      \"name\": \"org_id\"\n            }, \n            \"title\": \"\ 
     8617          org_id\"\n          }, \n          {\n            \"domain\": {\n      \ 
     8618          \        \"class\": \"string\", \n              \"name\": \"\\\"character\ 
     8619          \ varying\\\"\"\n            }, \n            \"entity\": {\n          \ 
     8620          \    \"class\": \"columnfield\", \n              \"name\": \"name\"\n  \ 
     8621          \          }, \n            \"title\": \"name\"\n          }, \n       \ 
     8622          \   {\n            \"domain\": {\n              \"class\": \"boolean\",\ 
     8623          \ \n              \"name\": \"boolean\"\n            }, \n            \"\ 
     8624          entity\": {\n              \"class\": \"columnfield\", \n              \"\ 
     8625          name\": \"is_active\"\n            }, \n            \"title\": \"is_active\"\ 
     8626          \n          }, \n          {\n            \"domain\": {\n              \"\ 
     8627          class\": \"string\", \n              \"name\": \"\\\"character varying\\\ 
     8628          \"\"\n            }, \n            \"entity\": {\n              \"class\"\ 
     8629          : \"keyfield\", \n              \"name\": \"division_of\"\n            },\ 
     8630          \ \n            \"title\": \"division_of\"\n          }\n        ], \n \ 
     8631          \       \"parent\": {\n          \"title\": null\n        }, \n        \"\ 
     8632          title\": \"organization\"\n      }, \n      {\n        \"element\": [\n\ 
     8633          \          {\n            \"domain\": {\n              \"class\": \"string\"\ 
    86128634          , \n              \"name\": \"\\\"character varying\\\"\"\n            },\ 
    8613           \ \n            \"title\": \"org_id\"\n          }, \n          {\n    \ 
    8614           \        \"domain\": {\n              \"class\": \"string\", \n        \ 
    8615           \      \"name\": \"\\\"character varying\\\"\"\n            }, \n      \ 
    8616           \      \"title\": \"name\"\n          }, \n          {\n            \"domain\"\ 
    8617           : {\n              \"class\": \"boolean\", \n              \"name\": \"\ 
    8618           boolean\"\n            }, \n            \"title\": \"is_active\"\n     \ 
    8619           \     }, \n          {\n            \"domain\": {\n              \"class\"\ 
    8620           : \"string\", \n              \"name\": \"\\\"character varying\\\"\"\n\ 
    8621           \            }, \n            \"title\": \"division_of\"\n          }\n\ 
    8622           \        ], \n        \"title\": \"organization\"\n      }, \n      {\n\ 
    8623           \        \"element\": [\n          {\n            \"domain\": {\n      \ 
    8624           \        \"class\": \"string\", \n              \"name\": \"\\\"character\ 
    8625           \ varying\\\"\"\n            }, \n            \"title\": \"org_id\"\n  \ 
    8626           \        }, \n          {\n            \"domain\": {\n              \"class\"\ 
    8627           : \"string\", \n              \"name\": \"\\\"character varying\\\"\"\n\ 
     8635          \ \n            \"entity\": {\n              \"class\": \"keyfield\", \n\ 
     8636          \              \"name\": \"org_id\"\n            }, \n            \"title\"\ 
     8637          : \"org_id\"\n          }, \n          {\n            \"domain\": {\n  \ 
     8638          \            \"class\": \"string\", \n              \"name\": \"\\\"character\ 
     8639          \ varying\\\"\"\n            }, \n            \"entity\": {\n          \ 
     8640          \    \"class\": \"columnfield\", \n              \"name\": \"nickname\"\n\ 
    86288641          \            }, \n            \"title\": \"nickname\"\n          }, \n \ 
    86298642          \         {\n            \"domain\": {\n              \"class\": \"string\"\ 
    86308643          , \n              \"name\": \"\\\"character varying\\\"\"\n            },\ 
    8631           \ \n            \"title\": \"full_name\"\n          }, \n          {\n \ 
    8632           \           \"domain\": {\n              \"class\": \"string\", \n     \