1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18  r"""fieldmappings.py: Mappings from field names to term prefixes, etc. 
 19   
 20  """ 
 21  __docformat__ = "restructuredtext en" 
 22   
 23  import cPickle as _cPickle 
 24   
 26      """Mappings from field names to term prefixes, slot values, etc. 
 27   
 28      The following mappings are maintained: 
 29   
 30      - a mapping from field name to the string prefix to insert at the start of 
 31        terms. 
 32      - a mapping from field name to the slot numbers to store the field contents 
 33        in. 
 34   
 35      """ 
 36      __slots__ = '_prefixes', '_prefixcount', '_slots', '_slotcount',  
 37   
 39          """Create a new field mapping object, or unserialise a saved one. 
 40   
 41          """ 
 42          if serialised is not None: 
 43              (self._prefixes, self._prefixcount, 
 44               self._slots, self._slotcount) = _cPickle.loads(serialised) 
 45          else: 
 46              self._prefixes = {} 
 47              self._prefixcount = 0 
 48              self._slots = {} 
 49              self._slotcount = 0 
  50   
 52          """Generate a previously unused prefix. 
 53   
 54          Prefixes are uppercase letters, and start with 'X' (this is a Xapian 
 55          convention, for compatibility with other Xapian tools: other starting 
 56          letters are reserved for special meanings): 
 57   
 58          >>> maps = FieldMappings() 
 59          >>> maps._genPrefix() 
 60          'XA' 
 61          >>> maps._genPrefix() 
 62          'XB' 
 63          >>> [maps._genPrefix() for i in xrange(60)] 
 64          ['XC', 'XD', 'XE', 'XF', 'XG', 'XH', 'XI', 'XJ', 'XK', 'XL', 'XM', 'XN', 'XO', 'XP', 'XQ', 'XR', 'XS', 'XT', 'XU', 'XV', 'XW', 'XX', 'XY', 'XZ', 'XAA', 'XBA', 'XCA', 'XDA', 'XEA', 'XFA', 'XGA', 'XHA', 'XIA', 'XJA', 'XKA', 'XLA', 'XMA', 'XNA', 'XOA', 'XPA', 'XQA', 'XRA', 'XSA', 'XTA', 'XUA', 'XVA', 'XWA', 'XXA', 'XYA', 'XZA', 'XAB', 'XBB', 'XCB', 'XDB', 'XEB', 'XFB', 'XGB', 'XHB', 'XIB', 'XJB'] 
 65          >>> maps = FieldMappings() 
 66          >>> [maps._genPrefix() for i in xrange(27*26 + 5)][-10:] 
 67          ['XVZ', 'XWZ', 'XXZ', 'XYZ', 'XZZ', 'XAAA', 'XBAA', 'XCAA', 'XDAA', 'XEAA'] 
 68          """ 
 69          res = [] 
 70          self._prefixcount += 1 
 71          num = self._prefixcount 
 72          while num != 0: 
 73              ch = (num - 1) % 26 
 74              res.append(chr(ch + ord('A'))) 
 75              num -= ch 
 76              num = num // 26 
 77          return 'X' + ''.join(res) 
  78   
 80          """Get a fieldname from a prefix. 
 81   
 82          If the prefix is not found, return None. 
 83   
 84          """ 
 85          for key, val in self._prefixes.iteritems(): 
 86              if val == prefix: 
 87                  return key 
 88          return None 
  89   
 91          """Get the prefix used for a given field name. 
 92   
 93          """ 
 94          return self._prefixes[fieldname] 
  95   
 97          """Get the slot number used for a given field name and purpose. 
 98   
 99          """ 
100          return self._slots[(fieldname, purpose)] 
 101   
103          """Allocate a prefix for the given field. 
104   
105          If a prefix is already allocated for this field, this has no effect. 
106   
107          """ 
108          if fieldname in self._prefixes: 
109              return 
110          self._prefixes[fieldname] = self._genPrefix() 
 111   
112 -    def add_slot(self, fieldname, purpose, slotnum=None): 
 113          """Allocate a slot number for the given field and purpose. 
114   
115          If a slot number is already allocated for this field and purpose, this 
116          has no effect. 
117   
118          Returns the slot number allocated for the field and purpose (whether 
119          newly allocated, or previously allocated). 
120   
121          If `slotnum` is supplied, the number contained in it is used to 
122          allocate the new slot, instead of allocating a new number.  No checks 
123          will be made to ensure that the slot number doesn't collide with 
124          existing (or later allocated) numbers: the main purpose of this 
125          parameter is to share allocations - ie, to collide deliberately. 
126   
127          """ 
128          try: 
129              return self._slots[(fieldname, purpose)] 
130          except KeyError: 
131              pass 
132   
133          if slotnum is None: 
134              self._slots[(fieldname, purpose)] = self._slotcount 
135              self._slotcount += 1 
136              return self._slotcount - 1 
137          else: 
138              self._slots[(fieldname, purpose)] = slotnum 
139              return slotnum 
 140   
142          """Serialise the field mappings to a string. 
143   
144          This can be unserialised by passing the result of this method to the 
145          constructor of a new FieldMappings object. 
146   
147          """ 
148          return _cPickle.dumps((self._prefixes, 
149                                 self._prefixcount, 
150                                 self._slots, 
151                                 self._slotcount, 
152                                ), 2) 
  153