<p dir="auto"><strong>Migrated issue, originally created by Anonymous</strong></p>
<p dir="auto">(original reporter: ged) As you know, I've been playing with a C extension lately. I am at the point where I have translated all the RowProxy methods which benefit from more speed, and all common result processors (the result is quite encouraging btw). I have also reviewed the result processors for "common" types in all dialects and noticed there is quite a bit of duplication.</p>
<p dir="auto">The code seem to be either copy-pasted from other dialects or worse: recoded slightly differently to do (apparently) the same work. The most glaring example is the Boolean type: AFAICT, every dialect except PostgreSQL redefine it, but they have all the same intent: convert a boolean to an int and back. For this particular case, I think it would make sense to move that code to types.py.</p>
<p dir="auto">Even in more "complex" types, such as Numeric, the processors seem to return one of a few predefined conversion functions: decimal_to_float or float_to_decimal. I think it would be a good idea to make an explicit module with a collection of those "most often used conversion functions". This would have several advantages:</p>
<ul dir="auto">
<li>less code duplication</li>
<li>avoiding subtle implementation differences when the requirements of the DBAPI are the same. This is especially True for bind_processors, which sometimes accept different types on different dialects, usually without a good reason to do so (AFAICT).</li>
<li>less code to write for dialect implementors</li>
<li>I would only have to try ... except for the C processor in one place, and not in all dialects.</li>
<li>it would make it more obvious when one dialect doesn't use one of those common functions that it does something special.</li>
</ul>
<p dir="auto">For example, the _PGNumeric result_processor would look like this:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    def result_processor(self, dialect, coltype):
        if self.asdecimal:
            if coltype in (700, 701):
                return processors.float_to_decimal
            elif coltype == 1700:
                # pg8000 returns Decimal natively for 1700
                return None
            else:
                raise exc.InvalidRequestError(&quot;Unknown PG numeric type: %d&quot; % coltype)
        else:
            if coltype in (700, 701):
                # pg8000 returns float natively for 701
                return None
            elif coltype == 1700:
                return processors.decimal_to_float
            else:
                raise exc.InvalidRequestError(&quot;Unknown PG numeric type: %d&quot; % coltype)"><pre class="notranslate"><code class="notranslate">    def result_processor(self, dialect, coltype):
        if self.asdecimal:
            if coltype in (700, 701):
                return processors.float_to_decimal
            elif coltype == 1700:
                # pg8000 returns Decimal natively for 1700
                return None
            else:
                raise exc.InvalidRequestError("Unknown PG numeric type: %d" % coltype)
        else:
            if coltype in (700, 701):
                # pg8000 returns float natively for 701
                return None
            elif coltype == 1700:
                return processors.decimal_to_float
            else:
                raise exc.InvalidRequestError("Unknown PG numeric type: %d" % coltype)
</code></pre></div>
<p dir="auto">I should also note that some processors (such as String and Decimal -- for the Decimal lookup) require local storage. Those usually correspond to Python closures in the current code. That does not translate well into C. Defining factories for those would be the solution:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="def string_to_unicode_result_processor_factory(encoding):
    decoder = codecs.getdecoder(encoding)
    def process(value):
        if value is not None:
            # decoder returns a tuple: (value, len)
            return decoder(value)[0](0)
        else:
            return value"><pre class="notranslate"><code class="notranslate">def string_to_unicode_result_processor_factory(encoding):
    decoder = codecs.getdecoder(encoding)
    def process(value):
        if value is not None:
            # decoder returns a tuple: (value, len)
            return decoder(value)[0](0)
        else:
            return value
</code></pre></div>
<p dir="auto">which can then use the C processor (or in fact, the C class in this case):</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="try:
    from demo import UnicodeResultProcessor
    def string_to_unicode_result_processor_factory(encoding):
        result_processor = UnicodeResultProcessor(encoding)
        return result_processor.process
except ImportError:
    ... (same as above)"><pre class="notranslate"><code class="notranslate">try:
    from demo import UnicodeResultProcessor
    def string_to_unicode_result_processor_factory(encoding):
        result_processor = UnicodeResultProcessor(encoding)
        return result_processor.process
except ImportError:
    ... (same as above)
</code></pre></div>
<p dir="auto">What do you think? I'm willing to do all the changes myself, I just need an official blessing from you. If you agree with the general idea, does "processors" as the module name also suit you?</p>
<p dir="auto"><strong>Migrated issue, originally created by Michael Bayer (<a href="https://github.com/zzzeek">@zzzeek</a>)</strong></p>
<p dir="auto">to make it easier to support joined-table inheritance with no explcit discriminator, as well as any functional situation:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from sqlalchemy.orm import joined_discriminator
mapper(Cls, table, 
select_table=table.outerjoin(subtable1).outerjoin(subtable2), polymorphic_on=joined_discriminator, ...)"><pre class="notranslate"><code class="notranslate">from sqlalchemy.orm import joined_discriminator
mapper(Cls, table, 
select_table=table.outerjoin(subtable1).outerjoin(subtable2), polymorphic_on=joined_discriminator, ...)
</code></pre></div>
<p dir="auto">polymorphic_on accepts a callable.  at result time, it gets called:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="if callable(self.polymorphic_on):
    discriminator = self.polymorphic_on(self, row)
    ...etc ..."><pre class="notranslate"><code class="notranslate">if callable(self.polymorphic_on):
    discriminator = self.polymorphic_on(self, row)
    ...etc ...
</code></pre></div>
<p dir="auto">we can skip the "callable" check by just making a string-based polymorphic_on into a callable of its own.</p>
<p dir="auto">joined_discriminator then works like this (will have to optimize this):</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="def joined_discrminator(mapper, row):
    for key, submapper in mapper.polymorphic_map.iteritems():
        if row[submapper.local_table.primary_keys[0](submapper.local_table.primary_keys[0)]:
            return key
    return mapper.polymorphic_identity"><pre class="notranslate"><code class="notranslate">def joined_discrminator(mapper, row):
    for key, submapper in mapper.polymorphic_map.iteritems():
        if row[submapper.local_table.primary_keys[0](submapper.local_table.primary_keys[0)]:
            return key
    return mapper.polymorphic_identity
</code></pre></div>
<p dir="auto">i.e. it looks at all the joined tables and returns the discriminator for the one thats present in the row.  primary_keys<a href="0">0</a> might not be possible depending on how the outerjoin is set up (also the base table pk wont get confused for the sub-table pk ?)</p>