def iter_attr_edits(cls, attrs, query=None): pk_cols = [k for k in inspect(cls).primary_key] cls_version = version_class(cls) pk_cols_version = [getattr(cls_version, k.name) for k in pk_cols] attrs_version = [getattr(cls_version, a) for a in attrs] cls_transaction = transaction_class(cls) if query is None: query = cls_version.query all_versions = query.join(cls_version.transaction) \ .with_entities(*pk_cols_version + attrs_version + [cls_transaction.issued_at]) \ .order_by(*pk_cols_version + [cls_version.transaction_id]) def get_pk(row): return [getattr(row, k.name) for k in pk_cols_version] for pk, versions in groupby(all_versions, get_pk): # We don't yet process inserts/deletes, but should first = next(versions) attr_vals = {a: getattr(first, a) for a in attrs} attr_times = {a: [first.issued_at] for a in attrs} for version in versions: for attr in attrs: val = getattr(version, attr) if val != attr_vals[attr]: attr_times[attr].append(version.issued_at) attr_vals[attr] = val yield (pk, attr_times)
def iter_attr_edits(cls, attrs, query=None): pk_cols = [k for k in inspect(cls).primary_key] cls_version = version_class(cls) pk_cols_version = [getattr(cls_version, k.name) for k in pk_cols] attrs_version = [getattr(cls_version, a) for a in attrs] cls_transaction = transaction_class(cls) if query is None: query = cls_version.query all_versions = (query.join(cls_version.transaction).with_entities( *pk_cols_version + attrs_version + [cls_transaction.issued_at]).order_by(*pk_cols_version + [cls_version.transaction_id])) def get_pk(row): return [getattr(row, k.name) for k in pk_cols_version] for pk, versions in groupby(all_versions, get_pk): # We don't yet process inserts/deletes, but should first = next(versions) attr_vals = {a: getattr(first, a) for a in attrs} attr_times = {a: [first.issued_at] for a in attrs} for version in versions: for attr in attrs: val = getattr(version, attr) if val != attr_vals[attr]: attr_times[attr].append(version.issued_at) attr_vals[attr] = val yield (pk, attr_times)
def get_export_data(cls): if cls.__name__ == 'Payment': # Export stats for each payment type separately return {} purchase_counts = cls.query.outerjoin(cls.purchases).group_by(cls.id).with_entities(func.count(models.Ticket.id)) refund_counts = cls.query.outerjoin(cls.refunds).group_by(cls.id).with_entities(func.count(Refund.id)) cls_version = version_class(cls) cls_transaction = transaction_class(cls) changes = cls.query.join(cls.versions).group_by(cls.id) change_counts = changes.with_entities(func.count(cls_version.id)) first_changes = changes.join(cls_version.transaction) \ .with_entities(func.min(cls_transaction.issued_at).label('created')) \ .from_self() cls_ver_new = aliased(cls.versions) cls_ver_paid = aliased(cls.versions) cls_txn_new = aliased(cls_version.transaction) cls_txn_paid = aliased(cls_version.transaction) active_time = func.max(cls_txn_paid.issued_at) - func.max(cls_txn_new.issued_at) active_times = cls.query \ .join(cls_ver_new, cls_ver_new.id == cls.id) \ .join(cls_ver_paid, cls_ver_paid.id == cls.id) \ .join(cls_txn_new, cls_txn_new.id == cls_ver_new.transaction_id) \ .join(cls_txn_paid, cls_txn_paid.id == cls_ver_paid.transaction_id) \ .filter(cls_ver_new.state == 'new') \ .filter(cls_ver_paid.state == 'paid') \ .with_entities(active_time.label('active_time')) \ .group_by(cls.id) time_buckets = [timedelta(0), timedelta(minutes=1), timedelta(hours=1)] + \ [timedelta(d) for d in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 28, 60]] data = { 'public': { 'payments': { 'counts': { 'purchases': bucketise(purchase_counts, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20]), 'refunds': bucketise(refund_counts, [0, 1, 2, 3, 4]), 'changes': bucketise(change_counts, range(10)), 'created_week': export_intervals(first_changes, column('created'), 'week', 'YYYY-MM-DD'), 'active_time': bucketise([r.active_time for r in active_times], time_buckets), 'amounts': bucketise(cls.query.with_entities(cls.amount_int / 100), [0, 10, 20, 30, 40, 50, 100, 150, 200]), }, }, }, 'tables': ['payment', 'payment_version'], } count_attrs = ['state', 'reminder_sent', 'currency'] data['public']['payments']['counts'].update(export_attr_counts(cls, count_attrs)) return data
def get_export_data(cls): if cls.__name__ == "Payment": # Export stats for each payment type separately return {} purchase_counts = ( cls.query.outerjoin(cls.purchases) .group_by(cls.id) .with_entities(func.count(Ticket.id)) ) refund_counts = ( cls.query.outerjoin(cls.refunds) .group_by(cls.id) .with_entities(func.count(Refund.id)) ) cls_version = version_class(cls) cls_transaction = transaction_class(cls) changes = cls.query.join(cls.versions).group_by(cls.id) change_counts = changes.with_entities(func.count(cls_version.id)) first_changes = ( changes.join(cls_version.transaction) .with_entities(func.min(cls_transaction.issued_at).label("created")) .from_self() ) cls_ver_new = aliased(cls.versions) cls_ver_paid = aliased(cls.versions) cls_txn_new = aliased(cls_version.transaction) cls_txn_paid = aliased(cls_version.transaction) active_time = func.max(cls_txn_paid.issued_at) - func.max(cls_txn_new.issued_at) active_times = ( cls.query.join(cls_ver_new, cls_ver_new.id == cls.id) .join(cls_ver_paid, cls_ver_paid.id == cls.id) .join(cls_txn_new, cls_txn_new.id == cls_ver_new.transaction_id) .join(cls_txn_paid, cls_txn_paid.id == cls_ver_paid.transaction_id) .filter(cls_ver_new.state == "new") .filter(cls_ver_paid.state == "paid") .with_entities(active_time.label("active_time")) .group_by(cls.id) ) time_buckets = [timedelta(0), timedelta(minutes=1), timedelta(hours=1)] + [ timedelta(d) for d in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 28, 60] ] data = { "public": { "payments": { "counts": { "purchases": bucketise( purchase_counts, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20] ), "refunds": bucketise(refund_counts, [0, 1, 2, 3, 4]), "changes": bucketise(change_counts, range(10)), "created_week": export_intervals( first_changes, column("created"), "week", "YYYY-MM-DD" ), "active_time": bucketise( [r.active_time for r in active_times], time_buckets ), "amounts": bucketise( cls.query.with_entities(cls.amount_int / 100), [0, 10, 20, 30, 40, 50, 100, 150, 200], ), } } }, "tables": ["payment", "payment_version"], } count_attrs = ["state", "reminder_sent", "currency"] data["public"]["payments"]["counts"].update( export_attr_counts(cls, count_attrs) ) return data