Mercurial > p > roundup > code
comparison roundup/backends/back_anydbm.py @ 2239:c8a06e10e2c6
much faster anydbm filter(), but it breaks most filtering tests
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Mon, 26 Apr 2004 00:46:34 +0000 |
| parents | f624fc20f8fe |
| children | 7d5398391610 |
comparison
equal
deleted
inserted
replaced
| 2238:df0444e39bc3 | 2239:c8a06e10e2c6 |
|---|---|
| 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" | 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" |
| 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, |
| 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| 17 # | 17 # |
| 18 #$Id: back_anydbm.py,v 1.142 2004-04-25 22:19:15 richard Exp $ | 18 #$Id: back_anydbm.py,v 1.143 2004-04-26 00:46:34 richard Exp $ |
| 19 '''This module defines a backend that saves the hyperdatabase in a | 19 '''This module defines a backend that saves the hyperdatabase in a |
| 20 database chosen by anydbm. It is guaranteed to always be available in python | 20 database chosen by anydbm. It is guaranteed to always be available in python |
| 21 versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several | 21 versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several |
| 22 serious bugs, and is not available) | 22 serious bugs, and is not available) |
| 23 ''' | 23 ''' |
| 1660 else: | 1660 else: |
| 1661 l.append((OTHER, k, v)) | 1661 l.append((OTHER, k, v)) |
| 1662 filterspec = l | 1662 filterspec = l |
| 1663 | 1663 |
| 1664 # now, find all the nodes that are active and pass filtering | 1664 # now, find all the nodes that are active and pass filtering |
| 1665 l = [] | 1665 matches = [] |
| 1666 cldb = self.db.getclassdb(cn) | 1666 cldb = self.db.getclassdb(cn) |
| 1667 try: | 1667 try: |
| 1668 # TODO: only full-scan once (use items()) | 1668 # TODO: only full-scan once (use items()) |
| 1669 for nodeid in self.getnodeids(cldb): | 1669 for nodeid in self.getnodeids(cldb): |
| 1670 node = self.db.getnode(cn, nodeid, cldb) | 1670 node = self.db.getnode(cn, nodeid, cldb) |
| 1722 elif t == OTHER: | 1722 elif t == OTHER: |
| 1723 # straight value comparison for the other types | 1723 # straight value comparison for the other types |
| 1724 if node[k] != v: | 1724 if node[k] != v: |
| 1725 break | 1725 break |
| 1726 else: | 1726 else: |
| 1727 l.append((nodeid, node)) | 1727 matches.append([nodeid, node]) |
| 1728 finally: | 1728 finally: |
| 1729 cldb.close() | 1729 cldb.close() |
| 1730 l.sort() | |
| 1731 | 1730 |
| 1732 # filter based on full text search | 1731 # filter based on full text search |
| 1733 if search_matches is not None: | 1732 if search_matches is not None: |
| 1734 k = [] | 1733 k = [] |
| 1735 for v in l: | 1734 for v in matches: |
| 1736 if search_matches.has_key(v[0]): | 1735 if search_matches.has_key(v[0]): |
| 1737 k.append(v) | 1736 k.append(v) |
| 1738 l = k | 1737 matches = k |
| 1739 | 1738 |
| 1740 # now, sort the result | 1739 # add sorting information to the match entries |
| 1741 def sortfun(a, b, sort=sort, group=group, properties=self.getprops(), | 1740 directions = [] |
| 1742 db = self.db, cl=self): | 1741 for dir, prop in sort, group: |
| 1743 a_id, an = a | 1742 if dir is None or prop is None: |
| 1744 b_id, bn = b | 1743 continue |
| 1745 # sort by group and then sort | 1744 directions.append(dir) |
| 1746 for dir, prop in group, sort: | 1745 propclass = props[prop] |
| 1747 if dir is None or prop is None: continue | 1746 for entry in matches: |
| 1748 | 1747 itemid = entry[-2] |
| 1749 # sorting is class-specific | 1748 item = entry[-1] |
| 1750 propclass = properties[prop] | |
| 1751 | |
| 1752 # handle the properties that might be "faked" | 1749 # handle the properties that might be "faked" |
| 1753 # also, handle possible missing properties | 1750 # also, handle possible missing properties |
| 1754 try: | 1751 try: |
| 1755 if not an.has_key(prop): | 1752 v = self.get(itemid, prop) |
| 1756 an[prop] = cl.get(a_id, prop) | |
| 1757 av = an[prop] | |
| 1758 except KeyError: | 1753 except KeyError: |
| 1759 # the node doesn't have a value for this property | 1754 # the node doesn't have a value for this property |
| 1760 if isinstance(propclass, Multilink): av = [] | 1755 if isinstance(propclass, Multilink): v = [] |
| 1761 else: av = '' | 1756 else: v = None |
| 1762 try: | 1757 s.append((v, itemid, item)) |
| 1763 if not bn.has_key(prop): | 1758 continue |
| 1764 bn[prop] = cl.get(b_id, prop) | 1759 |
| 1765 bv = bn[prop] | |
| 1766 except KeyError: | |
| 1767 # the node doesn't have a value for this property | |
| 1768 if isinstance(propclass, Multilink): bv = [] | |
| 1769 else: bv = '' | |
| 1770 | |
| 1771 # String and Date values are sorted in the natural way | |
| 1772 if isinstance(propclass, String): | 1760 if isinstance(propclass, String): |
| 1773 # clean up the strings | |
| 1774 if av and av[0] in string.uppercase: | |
| 1775 av = av.lower() | |
| 1776 if bv and bv[0] in string.uppercase: | |
| 1777 bv = bv.lower() | |
| 1778 if (isinstance(propclass, String) or | |
| 1779 isinstance(propclass, Date)): | |
| 1780 # it might be a string that's really an integer | 1761 # it might be a string that's really an integer |
| 1781 try: | 1762 try: tv = int(v) |
| 1782 av = int(av) | 1763 except: v = v.lower() |
| 1783 bv = int(bv) | 1764 else: v = tv |
| 1784 except: | |
| 1785 pass | |
| 1786 if dir == '+': | |
| 1787 r = cmp(av, bv) | |
| 1788 if r != 0: return r | |
| 1789 elif dir == '-': | |
| 1790 r = cmp(bv, av) | |
| 1791 if r != 0: return r | |
| 1792 | |
| 1793 # Link properties are sorted according to the value of | |
| 1794 # the "order" property on the linked nodes if it is | |
| 1795 # present; or otherwise on the key string of the linked | |
| 1796 # nodes; or finally on the node ids. | |
| 1797 elif isinstance(propclass, Link): | 1765 elif isinstance(propclass, Link): |
| 1798 link = db.classes[propclass.classname] | 1766 link = self.db.classes[propclass.classname] |
| 1799 if av is None and bv is not None: return -1 | |
| 1800 if av is not None and bv is None: return 1 | |
| 1801 if av is None and bv is None: continue | |
| 1802 if link.getprops().has_key('order'): | 1767 if link.getprops().has_key('order'): |
| 1803 if dir == '+': | 1768 v = link.get(v, 'order') |
| 1804 r = cmp(link.get(av, 'order'), | |
| 1805 link.get(bv, 'order')) | |
| 1806 if r != 0: return r | |
| 1807 elif dir == '-': | |
| 1808 r = cmp(link.get(bv, 'order'), | |
| 1809 link.get(av, 'order')) | |
| 1810 if r != 0: return r | |
| 1811 elif link.getkey(): | 1769 elif link.getkey(): |
| 1812 key = link.getkey() | 1770 key = link.getkey() |
| 1813 if dir == '+': | 1771 v = link.get(v, key) |
| 1814 r = cmp(link.get(av, key), link.get(bv, key)) | 1772 entry.insert(0, v) |
| 1815 if r != 0: return r | 1773 |
| 1816 elif dir == '-': | 1774 if directions: |
| 1817 r = cmp(link.get(bv, key), link.get(av, key)) | 1775 # sort using the first one or two columns |
| 1818 if r != 0: return r | 1776 def sortfun(a, b, directions=directions, n=range(len(directions))): |
| 1777 for i in n: | |
| 1778 if a[i] == b[i]: continue | |
| 1779 if directions[i] == '-': | |
| 1780 return cmp(a[i],b[i]) | |
| 1819 else: | 1781 else: |
| 1820 if dir == '+': | 1782 return cmp(b[i],a[i]) |
| 1821 r = cmp(av, bv) | 1783 return 0 |
| 1822 if r != 0: return r | 1784 matches.sort(sortfun) |
| 1823 elif dir == '-': | 1785 |
| 1824 r = cmp(bv, av) | 1786 # pull the id out of the individual entries |
| 1825 if r != 0: return r | 1787 matches = [entry[-2] for entry in matches] |
| 1826 | |
| 1827 else: | |
| 1828 # all other types just compare | |
| 1829 if dir == '+': | |
| 1830 r = cmp(av, bv) | |
| 1831 elif dir == '-': | |
| 1832 r = cmp(bv, av) | |
| 1833 if r != 0: return r | |
| 1834 | |
| 1835 # end for dir, prop in sort, group: | |
| 1836 # if all else fails, compare the ids | |
| 1837 return cmp(a[0], b[0]) | |
| 1838 | |
| 1839 l.sort(sortfun) | |
| 1840 l = [i[0] for i in l] | |
| 1841 if __debug__: | 1788 if __debug__: |
| 1842 self.db.stats['filtering'] += (time.time() - start_t) | 1789 self.db.stats['filtering'] += (time.time() - start_t) |
| 1843 return l | 1790 return matches |
| 1844 | 1791 |
| 1845 def count(self): | 1792 def count(self): |
| 1846 '''Get the number of nodes in this class. | 1793 '''Get the number of nodes in this class. |
| 1847 | 1794 |
| 1848 If the returned integer is 'numnodes', the ids of all the nodes | 1795 If the returned integer is 'numnodes', the ids of all the nodes |
