2009-06-05 9 views
1

J'ai une table sqlalchemy comme ceci:Comment puis-je déterminer si un PGArray est inclus dans un autre utilisant des sessions SQLAlchemy?

table = sql.Table('treeItems', META, 
    sql.Column('id', sql.Integer(), primary_key=True), 
    sql.Column('type', sql.String, nullable=False), 
    sql.Column('parentId', sql.Integer, sql.ForeignKey('treeItems.id')), 
    sql.Column('lineage', PGArray(sql.Integer)), 
    sql.Column('depth', sql.Integer), 
)

Ce qui est mis en correspondance avec un objet comme ceci:

orm.mapper(TreeItem, TreeItem.table, polymorphic_on=TreeItem.table.c.type, polymorphic_identity='TreeItem')

J'aimerais sélectionner un nœud enfant d'un nœud donné si ce que je m est à la recherche de SQL qui ressemble à ceci (pour un parent avec pk = 2):

SELECT * 
FROM "treeItems" 
WHERE ARRAY[2] <@ "treeItems".lineage AND "treeItems".id != 2 
ORDER BY "treeItems".lineage

Voici le code sqlalchemy/Python-je utiliser pour essayer d'obtenir le SQL ci-dessus avec peu de chance:

arrayStr = 'ARRAY[%s]' % ','.join([str(i) for i in self.lineage]) 
lineageFilter = expr.text('%s <@ %s' % (arrayStr, TreeItem.table.c.lineage)) 
query = SESSION.query(TreeItem).filter(expr.and_(lineageFilter, TreeItem.table.c.id!=self.id))

Mais voici le SQL que je le vent avec (notez l'absence de guillemets autour du nom de la table TreeItems dans la clause where):

SELECT "treeItems".id AS "treeItems_id", "treeItems".type AS "treeItems_type", "treeItems"."parentId" AS "treeItems_parentId", "treeItems".lineage AS "treeItems_lineage", "treeItems".depth AS "treeItems_depth" 
FROM "treeItems" 
WHERE ARRAY[2] <@ treeItems.lineage AND "treeItems".id != %(id_1)s

Alors, maintenant les questions suivantes:

Existe-t-il une meilleure façon de faire cela que d'utiliser l'expression text()/Existe-t-il un opérateur ou une expression dans SqlAlchemy qui peut faire < @ avec PGArray? Comment puis-je obtenir les guillemets pour apparaître autour de mon nom de table si je dois utiliser l'expression text()?

Merci à tous!

Répondre

4

Les éléments de clause SQLAlchemy ont une méthode .op() pour les opérateurs personnalisés. Ce qui n'est pas disponible est une clause spéciale pour les littéraux de tableau. Vous pouvez spécifier le tableau littéral avec literal_column:

print sql.literal_column('ARRAY[2]').op('<@')(table.c.lineage) 
# ARRAY[2] <@ "treeItems".lineage 

Si vous voulez une meilleure API pour les littéraux de tableau, vous pouvez créer avec le module sqlalchemy.ext.compiler ajouté dans SQLAlchemy 0.5.4.

0

Dans ce cas particulier, j'ai remarqué que la citation dans le SQL était due au fait que j'utilisais un nom de table qui était mixte. Conversion du nom de la table de « TreeItems » à « tree_items » résolu la question en citant et j'ai pu obtenir mon expression texte au travail:

expr.text('%s <@ %s' % (arrayStr, TreeItem.table.c.lineage))

Il est une solution et il est bon de savoir que les noms de tables de cas mixtes besoin d'être cité, mais la réponse des fourmis reste la bonne façon de résoudre le problème.

Questions connexes