Changeset 738 for trunk/pg.py


Ignore:
Timestamp:
Jan 13, 2016, 5:57:29 PM (4 years ago)
Author:
cito
Message:

Renamed some parameters to clarify their meaning

This is uncritical, because these are not keyword parameters. Also, we don't
change much in the 4.x branch in order to stay compatible.

Also, avoided the old terminology "class" for a table or table-like object in PostgreSQL,
because it may confuse people. The word "table" is so much clearer.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/pg.py

    r737 r738  
    5050# Auxiliary functions that are independent from a DB connection:
    5151
    52 def _oid_key(cl):
    53     """Build oid key from a class name."""
    54     return 'oid(%s)' % cl
     52def _oid_key(table):
     53    """Build oid key from a table name."""
     54    return 'oid(%s)' % table
    5555
    5656
     
    373373
    374374    @staticmethod
    375     def _prepare_qualified_param(cl, param):
     375    def _prepare_qualified_param(name, param):
    376376        """Quote parameter representing a qualified name.
    377377
     
    384384        if isinstance(param, int):
    385385            param = "$%d" % param
    386         if '.' not in cl:
     386        if '.' not in name:
    387387            param = 'quote_ident(%s)' % (param,)
    388388        return param
     
    486486        return self.db.query(qstr, args)
    487487
    488     def pkey(self, cl, flush=False):
    489         """This method gets or sets the primary key of a class.
     488    def pkey(self, table, flush=False):
     489        """This method gets or sets the primary key of a table.
    490490
    491491        Composite primary keys are represented as frozensets. Note that
     
    502502            self._do_debug('pkey cache has been flushed')
    503503        try:  # cache lookup
    504             pkey = pkeys[cl]
     504            pkey = pkeys[table]
    505505        except KeyError:  # cache miss, check the database
    506506            q = ("SELECT a.attname FROM pg_index i"
     
    509509                " AND NOT a.attisdropped"
    510510                " WHERE i.indrelid=%s::regclass"
    511                 " AND i.indisprimary" % self._prepare_qualified_param(cl, 1))
    512             pkey = self.db.query(q, (cl,)).getresult()
     511                " AND i.indisprimary") % (
     512                    self._prepare_qualified_param(table, 1),)
     513            pkey = self.db.query(q, (table,)).getresult()
    513514            if not pkey:
    514                 raise KeyError('Class %s has no primary key' % cl)
     515                raise KeyError('Table %s has no primary key' % table)
    515516            if len(pkey) > 1:
    516517                pkey = frozenset(k[0] for k in pkey)
    517518            else:
    518519                pkey = pkey[0][0]
    519             pkeys[cl] = pkey  # cache it
     520            pkeys[table] = pkey  # cache it
    520521        return pkey
    521522
     
    547548        return self.get_relations('r')
    548549
    549     def get_attnames(self, cl, flush=False):
     550    def get_attnames(self, table, flush=False):
    550551        """Given the name of a table, digs out the set of attribute names.
    551552
     
    565566            self._do_debug('pkey cache has been flushed')
    566567        try:  # cache lookup
    567             names = attnames[cl]
     568            names = attnames[table]
    568569        except KeyError:  # cache miss, check the database
    569570            q = ("SELECT a.attname, t.typname%s"
     
    574575                " AND NOT a.attisdropped") % (
    575576                    '::regtype' if self._regtypes else '',
    576                     self._prepare_qualified_param(cl, 1))
    577             names = self.db.query(q, (cl,)).getresult()
     577                    self._prepare_qualified_param(table, 1))
     578            names = self.db.query(q, (table,)).getresult()
    578579            if not names:
    579                 raise KeyError('Class %s does not exist' % cl)
     580                raise KeyError('Table %s does not exist' % table)
    580581            if self._regtypes:
    581582                names = dict(names)
    582583            else:
    583584                names = dict((name, _simpletype(typ)) for name, typ in names)
    584             attnames[cl] = names  # cache it
     585            attnames[table] = names  # cache it
    585586        return names
    586587
     
    596597            return regtypes
    597598
    598     def has_table_privilege(self, cl, privilege='select'):
     599    def has_table_privilege(self, table, privilege='select'):
    599600        """Check whether current user has specified table privilege."""
    600601        privilege = privilege.lower()
    601602        try:  # ask cache
    602             return self._privileges[(cl, privilege)]
     603            return self._privileges[(table, privilege)]
    603604        except KeyError:  # cache miss, ask the database
    604605            q = "SELECT has_table_privilege(%s, $2)" % (
    605                 self._prepare_qualified_param(cl, 1),)
    606             q = self.db.query(q, (cl, privilege))
     606                self._prepare_qualified_param(table, 1),)
     607            q = self.db.query(q, (table, privilege))
    607608            ret = q.getresult()[0][0] == self._make_bool(True)
    608             self._privileges[(cl, privilege)] = ret  # cache it
     609            self._privileges[(table, privilege)] = ret  # cache it
    609610            return ret
    610611
    611     def get(self, cl, arg, keyname=None):
     612    def get(self, table, row, keyname=None):
    612613        """Get a row from a database table or view.
    613614
    614615        This method is the basic mechanism to get a single row.  The keyname
    615616        that the key specifies a unique row.  If keyname is not specified
    616         then the primary key for the table is used.  If arg is a dictionary
     617        then the primary key for the table is used.  If row is a dictionary
    617618        then the value for the key is taken from it and it is modified to
    618619        include the new values, replacing existing values where necessary.
     
    620621        The OID is also put into the dictionary if the table has one, but
    621622        in order to allow the caller to work with multiple tables, it is
    622         munged as "oid(cl)".
    623 
    624         """
    625         if cl.endswith('*'):  # scan descendant tables?
    626             cl = cl[:-1].rstrip()  # need parent table name
     623        munged as "oid(table)".
     624
     625        """
     626        if table.endswith('*'):  # scan descendant tables?
     627            table = table[:-1].rstrip()  # need parent table name
    627628        if not keyname:
    628629            # use the primary key by default
    629630            try:
    630                 keyname = self.pkey(cl)
     631                keyname = self.pkey(table)
    631632            except KeyError:
    632                 raise _prg_error('Class %s has no primary key' % cl)
    633         attnames = self.get_attnames(cl)
     633                raise _prg_error('Table %s has no primary key' % table)
     634        attnames = self.get_attnames(table)
    634635        params = []
    635636        param = partial(self._prepare_param, params=params)
     
    637638        # We want the oid for later updates if that isn't the key.
    638639        # To allow users to work with multiple tables, we munge
    639         # the name of the "oid" key by adding the name of the class.
    640         qoid = _oid_key(cl)
     640        # the name of the "oid" key by adding the name of the table.
     641        qoid = _oid_key(table)
    641642        if keyname == 'oid':
    642             if isinstance(arg, dict):
    643                 if qoid not in arg:
    644                     raise _db_error('%s not in arg' % qoid)
     643            if isinstance(row, dict):
     644                if qoid not in row:
     645                    raise _db_error('%s not in row' % qoid)
    645646            else:
    646                 arg = {qoid: arg}
     647                row = {qoid: row}
    647648            what = '*'
    648             where = 'oid = %s' % param(arg[qoid], 'int')
     649            where = 'oid = %s' % param(row[qoid], 'int')
    649650        else:
    650651            keyname = [keyname] if isinstance(
    651652                keyname, basestring) else sorted(keyname)
    652             if not isinstance(arg, dict):
     653            if not isinstance(row, dict):
    653654                if len(keyname) > 1:
    654                     raise _prg_error('Composite key needs dict as arg')
    655                 arg = dict((k, arg) for k in keyname)
     655                    raise _prg_error('Composite key needs dict as row')
     656                row = dict((k, row) for k in keyname)
    656657            what = ', '.join(col(k) for k in attnames)
    657658            where = ' AND '.join('%s = %s' % (
    658                 col(k), param(arg[k], attnames[k])) for k in keyname)
     659                col(k), param(row[k], attnames[k])) for k in keyname)
    659660        q = 'SELECT %s FROM %s WHERE %s LIMIT 1' % (
    660             what, self._escape_qualified_name(cl), where)
     661            what, self._escape_qualified_name(table), where)
    661662        self._do_debug(q, params)
    662663        q = self.db.query(q, params)
    663664        res = q.dictresult()
    664665        if not res:
    665             raise _db_error('No such record in %s where %s' % (cl, where))
     666            raise _db_error('No such record in %s where %s' % (table, where))
    666667        for n, value in res[0].items():
    667668            if n == 'oid':
     
    669670            elif attnames.get(n) == 'bytea':
    670671                value = self.unescape_bytea(value)
    671             arg[n] = value
    672         return arg
    673 
    674     def insert(self, cl, d=None, **kw):
     672            row[n] = value
     673        return row
     674
     675    def insert(self, table, row=None, **kw):
    675676        """Insert a row into a database table.
    676677
     
    691692        if 'oid' in kw:
    692693            del kw['oid']
    693         if d is None:
    694             d = {}
    695         d.update(kw)
    696         attnames = self.get_attnames(cl)
     694        if row is None:
     695            row = {}
     696        row.update(kw)
     697        attnames = self.get_attnames(table)
    697698        params = []
    698699        param = partial(self._prepare_param, params=params)
     
    700701        names, values = [], []
    701702        for n in attnames:
    702             if n in d:
     703            if n in row:
    703704                names.append(col(n))
    704                 values.append(param(d[n], attnames[n]))
     705                values.append(param(row[n], attnames[n]))
    705706        names, values = ', '.join(names), ', '.join(values)
    706707        ret = 'oid, *' if 'oid' in attnames else '*'
    707708        q = 'INSERT INTO %s (%s) VALUES (%s) RETURNING %s' % (
    708             self._escape_qualified_name(cl), names, values, ret)
     709            self._escape_qualified_name(table), names, values, ret)
    709710        self._do_debug(q, params)
    710711        q = self.db.query(q, params)
     
    714715        for n, value in res[0].items():
    715716            if n == 'oid':
    716                 n = _oid_key(cl)
     717                n = _oid_key(table)
    717718            elif attnames.get(n) == 'bytea' and value is not None:
    718719                value = self.unescape_bytea(value)
    719             d[n] = value
    720         return d
    721 
    722     def update(self, cl, d=None, **kw):
     720            row[n] = value
     721        return row
     722
     723    def update(self, table, row=None, **kw):
    723724        """Update an existing row in a database table.
    724725
     
    733734        # otherwise use the primary key.  Fail if neither.
    734735        # Note that we only accept oid key from named args for safety.
    735         qoid = _oid_key(cl)
     736        qoid = _oid_key(table)
    736737        if 'oid' in kw:
    737738            kw[qoid] = kw['oid']
    738739            del kw['oid']
    739         if d is None:
    740             d = {}
    741         d.update(kw)
    742         attnames = self.get_attnames(cl)
     740        if row is None:
     741            row = {}
     742        row.update(kw)
     743        attnames = self.get_attnames(table)
    743744        params = []
    744745        param = partial(self._prepare_param, params=params)
    745746        col = self.escape_identifier
    746         if qoid in d:
    747             where = 'oid = %s' % param(d[qoid], 'int')
     747        if qoid in row:
     748            where = 'oid = %s' % param(row[qoid], 'int')
    748749            keyname = []
    749750        else:
    750751            try:
    751                 keyname = self.pkey(cl)
     752                keyname = self.pkey(table)
    752753            except KeyError:
    753                 raise _prg_error('Class %s has no primary key' % cl)
     754                raise _prg_error('Table %s has no primary key' % table)
    754755            keyname = [keyname] if isinstance(
    755756                keyname, basestring) else sorted(keyname)
    756757            try:
    757758                where = ' AND '.join('%s = %s' % (
    758                     col(k), param(d[k], attnames[k])) for k in keyname)
     759                    col(k), param(row[k], attnames[k])) for k in keyname)
    759760            except KeyError:
    760761                raise _prg_error('update needs primary key or oid')
     
    763764        values = []
    764765        for n in attnames:
    765             if n in d and n not in keyname:
    766                 values.append('%s = %s' % (col(n), param(d[n], attnames[n])))
     766            if n in row and n not in keyname:
     767                values.append('%s = %s' % (col(n), param(row[n], attnames[n])))
    767768        if not values:
    768             return d
     769            return row
    769770        values = ', '.join(values)
    770771        ret = 'oid, *' if 'oid' in attnames else '*'
    771772        q = 'UPDATE %s SET %s WHERE %s RETURNING %s' % (
    772             self._escape_qualified_name(cl), values, where, ret)
     773            self._escape_qualified_name(table), values, where, ret)
    773774        self._do_debug(q, params)
    774775        q = self.db.query(q, params)
     
    780781                elif attnames.get(n) == 'bytea' and value is not None:
    781782                    value = self.unescape_bytea(value)
    782                 d[n] = value
    783         return d
    784 
    785     def upsert(self, cl, d=None, **kw):
     783                row[n] = value
     784        return row
     785
     786    def upsert(self, table, row=None, **kw):
    786787        """Insert a row into a database table with conflict resolution.
    787788
     
    808809
    809810        So if in the case of a conflict you want to update every column that
    810         has been passed in the dictionary d , you would call upsert(cl, d).
     811        has been passed in the dictionary row , you would call upsert(table, row).
    811812        If you don't want to do anything in case of a conflict, i.e. leave
    812         the existing row as it is, call upsert(cl, d, **dict.fromkeys(d)).
     813        the existing row as it is, call upsert(table, row, **dict.fromkeys(row)).
    813814
    814815        If you need more fine-grained control of what gets updated, you can
     
    829830        if 'oid' in kw:
    830831            del kw['oid']
    831         if d is None:
    832             d = {}
    833         attnames = self.get_attnames(cl)
     832        if row is None:
     833            row = {}
     834        attnames = self.get_attnames(table)
    834835        params = []
    835836        param = partial(self._prepare_param,params=params)
     
    837838        names, values, updates = [], [], []
    838839        for n in attnames:
    839             if n in d:
     840            if n in row:
    840841                names.append(col(n))
    841                 values.append(param(d[n], attnames[n]))
     842                values.append(param(row[n], attnames[n]))
    842843        names, values = ', '.join(names), ', '.join(values)
    843844        try:
    844             keyname = self.pkey(cl)
     845            keyname = self.pkey(table)
    845846        except KeyError:
    846             raise _prg_error('Class %s has no primary key' % cl)
     847            raise _prg_error('Table %s has no primary key' % table)
    847848        keyname = [keyname] if isinstance(
    848849            keyname, basestring) else sorted(keyname)
     
    862863                    update.append('%s = %s' % (col(n), value))
    863864        if not values and not update:
    864             return d
     865            return row
    865866        do = 'update set %s' % ', '.join(update) if update else 'nothing'
    866867        ret = 'oid, *' if 'oid' in attnames else '*'
    867868        q = ('INSERT INTO %s AS included (%s) VALUES (%s)'
    868869            ' ON CONFLICT (%s) DO %s RETURNING %s') % (
    869                 self._escape_qualified_name(cl), names, values,
     870                self._escape_qualified_name(table), names, values,
    870871                target, do, ret)
    871872        self._do_debug(q, params)
     
    880881            for n, value in res[0].items():
    881882                if n == 'oid':
    882                     n = _oid_key(cl)
     883                    n = _oid_key(table)
    883884                elif attnames.get(n) == 'bytea':
    884885                    value = self.unescape_bytea(value)
    885                 d[n] = value
     886                row[n] = value
    886887        elif update:
    887888            raise _int_error('upsert did not return new values')
    888889        else:
    889             self.get(cl, d)
    890         return d
    891 
    892     def clear(self, cl, a=None):
     890            self.get(table, row)
     891        return row
     892
     893    def clear(self, table, row=None):
    893894        """Clear all the attributes to values determined by the types.
    894895
    895896        Numeric types are set to 0, Booleans are set to false, and everything
    896         else is set to the empty string.  If the array argument is present,
    897         it is used as the array and any entries matching attribute names are
    898         cleared with everything else left unchanged.
     897        else is set to the empty string.  If the row argument is present,
     898        it is used as the row dictionary and any entries matching attribute
     899        names are cleared with everything else left unchanged.
    899900
    900901        """
    901902        # At some point we will need a way to get defaults from a table.
    902         if a is None:
    903             a = {}  # empty if argument is not present
    904         attnames = self.get_attnames(cl)
     903        if row is None:
     904            row = {}  # empty if argument is not present
     905        attnames = self.get_attnames(table)
    905906        for n, t in attnames.items():
    906907            if n == 'oid':
     
    909910                    'float', 'real', 'double precision',
    910911                    'num', 'numeric', 'money'):
    911                 a[n] = 0
     912                row[n] = 0
    912913            elif t in ('bool', 'boolean'):
    913                 a[n] = self._make_bool(False)
     914                row[n] = self._make_bool(False)
    914915            else:
    915                 a[n] = ''
    916         return a
    917 
    918     def delete(self, cl, d=None, **kw):
     916                row[n] = ''
     917        return row
     918
     919    def delete(self, table, row=None, **kw):
    919920        """Delete an existing row in a database table.
    920921
     
    929930        # isn't referenced somewhere (or else PostgreSQL will).
    930931        # Note that we only accept oid key from named args for safety.
    931         qoid = _oid_key(cl)
     932        qoid = _oid_key(table)
    932933        if 'oid' in kw:
    933934            kw[qoid] = kw['oid']
    934935            del kw['oid']
    935         if d is None:
    936             d = {}
    937         d.update(kw)
     936        if row is None:
     937            row = {}
     938        row.update(kw)
    938939        params = []
    939940        param = partial(self._prepare_param, params=params)
    940         if qoid in d:
    941             where = 'oid = %s' % param(d[qoid], 'int')
     941        if qoid in row:
     942            where = 'oid = %s' % param(row[qoid], 'int')
    942943        else:
    943944            try:
    944                 keyname = self.pkey(cl)
     945                keyname = self.pkey(table)
    945946            except KeyError:
    946                 raise _prg_error('Class %s has no primary key' % cl)
     947                raise _prg_error('Table %s has no primary key' % table)
    947948            keyname = [keyname] if isinstance(
    948949                keyname, basestring) else sorted(keyname)
    949             attnames = self.get_attnames(cl)
     950            attnames = self.get_attnames(table)
    950951            col = self.escape_identifier
    951952            try:
    952                 where = ' AND '.join('%s = %s'
    953                     % (col(k), param(d[k], attnames[k])) for k in keyname)
     953                where = ' AND '.join('%s = %s' % (
     954                    col(k), param(row[k], attnames[k])) for k in keyname)
    954955            except KeyError:
    955956                raise _prg_error('delete needs primary key or oid')
    956957        q = 'DELETE FROM %s WHERE %s' % (
    957             self._escape_qualified_name(cl), where)
     958            self._escape_qualified_name(table), where)
    958959        self._do_debug(q, params)
    959960        res = self.db.query(q, params)
Note: See TracChangeset for help on using the changeset viewer.