On Thursday, September 29, 2016 at 9:45:24 AM UTC-4, Mike Bayer wrote: > > you can add your own types to do these things also, especially > read-only, just make any subclass of UserDefinedType and apply whatever > result-row handling is needed for how cx_Oracle is returning the data. > > The hard part about types is the elaborate expression support (e.g. like > JSON foo ->> bar vs. foo -> bar in PG for example). Reading and > writing a value is not that hard and especially if the type is just > specific to what you need right now, you don't have the burden of making > sure your type works for all versions / flags / settings of Oracle / > cx_Oracle etc. >
The following seems to work fine for my purposes. (It uses alchy, https://github.com/dgilland/alchy). Is there a way to specify that any column of type VARRAY should always be bound literally, so that one doesn't need to specify explicitly .compile(compile_kwargs={"literal_binds": True}) (and thereby literally binding all fields)? Also, is there a way, inside VARRAY.__init__() or some other place that is called before table creation to specify the sa.event.listen(<table>, "before_create", self.create_ddl().execute_if(dialect='oracle'))? import six import sqlalchemy as sa class VARRAY(sa.types.UserDefinedType): def __init__(self, type_name, size_limit, item_type, nullable=True, as_tuple=False): super(VARRAY, self).__init__() self.type_name = type_name self.size_limit = size_limit self.item_type = item_type self.nullable = nullable self.as_tuple = as_tuple def compile(self, dialect=None): return self.type_name def get_col_spec(self, **kw): return self.type_name def create_ddl(self, dialect=None, or_replace=True): sql = "CREATE " if or_replace: sql += "OR REPLACE " sql += "TYPE %(schema)s.{} AS VARRAY({}) OF {}".format(self.type_name, self.size_limit, self.item_type.compile(dialect=dialect)) if not self.nullable: sql += " NOT NULL" return sa.DDL(sql) def process_literal_param(self, value, dialect): return "{}({})".format(self.type_name, ','.join("NULL" if x is None else ("'%s'" % x) if isinstance(x, six.string_types) else str(x) for x in value)) def literal_processor(self, dialect): def processor(value): return self.process_literal_param(value, dialect) return processor def process_result_value(self, value, dialect): if self.as_tuple: value = tuple(value) return value def result_processor(self, dialect, coltype): def processor(value): return self.process_result_value(value, dialect) return processor def copy(self): return VARRAY(self.type_name, self.size_limit, self.item_type, nullable=self.nullable, as_tuple=self.as_tuple) if __name__ == '__main__': uri = "oracle://user:password@host" import alchy import sqlalchemy.dialects.oracle as oc db = alchy.Manager(config={'SQLALCHEMY_DATABASE_URI': uri}) class TestVarray(db.Model): __tablename__ = 'test_varray' __table_args__ = { 'schema': 'myschema' } idx = sa.Column(sa.Integer, primary_key=True) label = sa.Column(sa.String(20), nullable=False) words = sa.Column(VARRAY("tp_test_varray_words", 3000, sa.String(8), nullable=True), nullable=False) numbers = sa.Column(VARRAY("tp_test_varray_numbers", 3000, oc.NUMBER(), nullable=True), nullable=False) sa.event.listen(TestVarray.__table__, "before_create", TestVarray.column_attrs()['words'].columns[0].type.create_ddl().execute_if(dialect='oracle')) sa.event.listen(TestVarray.__table__, "before_create", TestVarray.column_attrs()['numbers'].columns[0].type.create_ddl().execute_if(dialect='oracle')) db.drop_all() db.create_all() db.engine.execute(TestVarray.__table__.insert({'idx': 1, 'label': 'One', 'words': ['Once', 'upon', 'a', 'time'], 'numbers': [1.1, 1.2]}). compile(compile_kwargs={"literal_binds": True})) db.engine.execute(TestVarray.__table__.insert({'idx': 2, 'label': 'Two', 'words': ['To', 'be', 'or', 'not'], 'numbers': [2.1, 2.2]}). compile(compile_kwargs={"literal_binds": True})) print TestVarray.query.all() print db.session().query(TestVarray.label, TestVarray.words, TestVarray.numbers).all() [<TestVarray(idx=1, label='One', words=['Once', 'upon', 'a', 'time'], numbers=[1.1, 1.2])>, <TestVarray(idx=2, label='Two', words=['To', 'be', 'or', 'not'], numbers=[2.1, 2.2])>] [('One', ['Once', 'upon', 'a', 'time'], [1.1, 1.2]), ('Two', ['To', 'be', 'or', 'not'], [2.1, 2.2])] -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.