Changeset 872
- Timestamp:
- 12/03/08 13:04:38 (5 weeks ago)
- Location:
- branches/forest-queries
- Files:
-
- 6 modified
-
htsql/commands/descriptors.py (modified) (1 diff)
-
htsql/commands/formatters.py (modified) (5 diffs)
-
htsql/commands/transformers.py (modified) (3 diffs)
-
htsql/descriptions.py (modified) (1 diff)
-
test/expect.yaml (modified) (7 diffs)
-
test/regress/selection.yaml (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/forest-queries/htsql/commands/descriptors.py
r871 r872 66 66 (element.entity.__class__.__name__.lower() 67 67 if element.entity is not None else None), 68 (str(element.entity )68 (str(element.entity.identifier()) 69 69 if element.entity is not None else None)]) 70 70 -
branches/forest-queries/htsql/commands/formatters.py
r866 r872 70 70 self.product = product 71 71 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 76 76 self.titles = self.init_titles() 77 77 self.branches = self.init_branches() … … 79 79 def __iter__(self): 80 80 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.parent87 if parent_profile is not None:88 parent = self.profiles.index(parent_profile)89 else:90 parent = None91 parents.append(parent)92 return parents93 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 children100 101 def init_depths(self):102 depths = { None: -1 }103 for label in self.labels:104 depths[label] = depths[self.parents[label]]+1105 return depths106 81 107 82 def init_titles(self): … … 606 581 declaration = [ 607 582 ('generic', BOOL(), False), 608 ('flat', BOOL(), False),609 583 ('unfold', BOOL(), False), 610 584 ('prune', BOOL(), False), … … 682 656 return data 683 657 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 684 681 def build(self, product): 685 682 """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] 700 722 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] 739 727 if self.prune: 740 data = self.prune_data(data)741 return data728 root = self.prune_data(root) 729 return root 742 730 743 731 def build_generic(self, product): 744 732 """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) 746 740 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 757 753 758 754 def format(self, product): 759 if product.has_content(): 760 if self.flat: 761 product = product.flatten() 755 if product: 762 756 if self.generic: 763 757 tree = self.build_generic(product) … … 797 791 data = simplejson.dumps(tree, sort_keys=True, indent=self.indent) 798 792 return [data, "\n"] 793 799 794 800 795 class YAML(TreeFormatter): -
branches/forest-queries/htsql/commands/transformers.py
r870 r872 134 134 135 135 def convert_generator(self, generator, profile): 136 children = { None: [] }137 for label, segment in enumerate(profile.segments):138 parent_label = None139 if segment.parent is not None:140 parent_label = profile.segments.index(segment.parent)141 children[label] = []142 children[parent_label].append(label)143 136 widths = {} 144 137 for label, segment in reversed(list(enumerate(profile.segments))): … … 150 143 widths[label] += len(segment.elements) 151 144 widths[parent_label] += widths[label] 152 generator = FlattenGenerator(generator, children, widths)145 generator = FlattenGenerator(generator, profile.children, widths) 153 146 return iter(generator) 154 147 … … 270 263 return Product(iter(new_rows), new_profile, None) 271 264 265 -
branches/forest-queries/htsql/descriptions.py
r866 r872 163 163 self.title = title 164 164 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 165 177 166 178 -
branches/forest-queries/test/expect.yaml
r871 r872 8538 8538 - [Content-Type, text/plain; charset=UTF-8] 8539 8539 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 \ / 8546 8546 segment (1 of 1) 8547 +======================================================================================== =============================================+8548 | parent{title} : |8549 | title : organization |8550 \ /8547 +========================================================================================+ 8548 | parent{title} : | 8549 | title : organization | 8550 \ / 8551 8551 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) 8560 8560 8561 8561 ----- … … 8566 8566 - [Content-Type, text/plain; charset=UTF-8] 8567 8567 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 \ / 8574 8574 segment (1 of 2) 8575 +======================================================================================== =============================================+8576 | parent{title} : |8577 | title : organization |8578 \ /8575 +========================================================================================+ 8576 | parent{title} : | 8577 | title : organization | 8578 \ / 8579 8579 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) 8588 8588 8589 8589 segment (2 of 2) 8590 +======================================================================================== =============================================+8591 | parent{title} : organization |8592 | title : person |8593 \ /8590 +========================================================================================+ 8591 | parent{title} : organization | 8592 | title : person | 8593 \ / 8594 8594 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) 8603 8603 8604 8604 ----- … … 8608 8608 headers: 8609 8609 - [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\"\ 8612 8634 , \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\ 8628 8641 \ }, \n \"title\": \"nickname\"\n }, \n \ 8629 8642 \ {\n \"domain\": {\n \"class\": \"string\"\ 8630 8643 , \n \"name\": \"\\\"character varying\\\"\"\n },\ 8631 \ \n \"title\": \"full_name\"\n }, \n {\n \ 8632 \ \"domain\": {\n \"class\": \"string\", \n \
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)