Skip to content

Instantly share code, notes, and snippets.

@sneppy
Last active April 18, 2020 09:55
Show Gist options
  • Save sneppy/63ea892b7b18f8231f57d9211dacda74 to your computer and use it in GitHub Desktop.
Save sneppy/63ea892b7b18f8231f57d9211dacda74 to your computer and use it in GitHub Desktop.
PonyORM
---------------------------------------------
-- This procedure takes as input the hash of
-- a post commit and returns the chain of
-- parent commits up to the root commit (i.e.
-- NULL parent)
---------------------------------------------
-- Drop old procedure
drop procedure if exists commit_chain;
delimiter //
create procedure commit_chain(in commit_hash varchar(40)) deterministic
begin
declare current_hash varchar(40) default NULL;
declare post_id bigint(20) unsigned default NULL;
-- Create temporary table to store chain.
-- Init with initial commit.
drop temporary table if exists chain;
create temporary table chain select * from postcommit where hash = commit_hash;
-- Get current hash and global post id.
select post, parent
from chain
into post_id, current_hash;
while current_hash is not NULL do
insert into chain
select *
from postcommit
where hash = current_hash and post = post_id; -- Sanity check.
-- Update current hash.
select parent
from chain
where hash = current_hash
into current_hash;
end while;
select *
from chain;
-- Drop temporary table.
drop temporary table if exists chain;
end //
delimiter ;
-- Procedure created
from datetime import datetime
from pony.orm import Database, db_session, select
from pony.orm import PrimaryKey, Required, Optional, Set, LongStr, Json
from hashlib import sha1
db = Database()
class Post(db.Entity):
""" A post associated to either a party an adventure or both """
# Post id, large int
id = PrimaryKey(int, unsigned=True, size=64, auto=True)
# Post title
title = Required(str, max_len=255, index=True)
# Set of commits
commits = Set('PostCommit')
# HEAD commit
head = Optional(str, max_len=40, nullable=True)
@property
def content(self):
""" Return computed content """
return self.get_content_at()
def get_content_at(self, commit_hash=None):
""" Compute content starting from commit hash """
commit_hash = commit_hash or self.head
if commit_hash is None: return ''
# Get commits.
commits = PostCommit.select_by_sql('call commit_chain($commit_hash)')
print(commits)
if len(commits) == 0: return ''
# Check that post id is correct.
if any([c.post.id != self.id for c in commits]): raise ValueError
# Get deltas.
deltas = [c.delta for c in commits]
if len(deltas) == 1:
return deltas[0]
else:
# Apply patches and return result.
patches = dmp.patch_fromText('\n'.join(deltas[1:]))
return dmp.patch_apply(patches, deltas[0])[0]
@property
def commit_head(self):
""" Return head commit """
return PostCommit[self.head]
def __init__(self, *args, **kwargs):
""" Constructor """
# Trim title
kwargs['title'] = kwargs['title'].strip()
super().__init__(*args, **kwargs)
class PostCommit(db.Entity):
""" A single commit associated with a post """
# Commit hash, uniquely identifies commit
hash = PrimaryKey(str, max_len=40)
# Post associated with this commit
post = Required(Post, index=True)
# Commit delta content
delta = Required(LongStr)
# Parent commit hash
parent = Optional('PostCommit', nullable=True)
# Set of children commits
children = Set('PostCommit')
def __init__(self, *args, **kwargs):
""" We must compute hash and delta """
if not kwargs['delta']:
# No real change, raise exception to abort
raise ValueError
# And compute hash
created_at = kwargs.get('created_at') or datetime.now()
kwargs['hash'] = sha1(':'.join([kwargs.get('parent', None) or '', kwargs['delta'], created_at.isoformat()]).encode('utf-8')).hexdigest()
# Create entity.
super().__init__(*args, **kwargs)
# If parent commit was HEAD, make this HEAD
if self.parent is None or self.post.head == self.parent.hash:
self.post.head = self.hash
@staticmethod
def commit_chain(commit):
""" Get chain of commits """
# If PostCommit object try to get hash
commit_hash = getattr(commit, 'hash', commit)
return PostCommit.select_by_sql('call commit_chain($commit_hash)')
# Bind db
db.bind(provider='mysql', host='localhost', user='', passwd='', db='')
db.generate_mapping(create_tables=True)
with db_session:
post = select(p for p in Post).first()
commits = PostCommit.select_by_sql('call commit_chain($post.head)')
print(commits)
mysqlclient==1.4.6
pkg-resources==0.0.0
pony==0.7.13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment