1
|
# Algen<br><br>Algen generates opionated ORM classes for sqlalchemy given a simple schema<br>either as a commandline string or as a yaml file.<br>It is designed to have minimal dependencies and is trivially extensible.<br>A command line tool is bundled along to help generate the models.<br>For DB specific types, only postgres is currently supported.<br>The tool currently assumes that sqlalchemy's declarative base object<br>is to be imported like ```from .alchemy_base import Base```<br><br><br>### CLI<br>```bash<br>$ algen --help<br>Usage: algen [OPTIONS]<br><br>Options:<br> -n, --name TEXT Name of model<br> -c, --columns TEXT Column definition. e.g. col_name:col_type Can be<br> used multiple times hence named columns. e.g. -c<br> foo:Int -c bar:Unicode(20)<br> -d, --destination PATH Destination directory. Default will assume 'Models'<br> directory inside the current working directory<br> -y, --yaml PATH Yaml file describing the Model. This supersedes the<br> column definition provided through --columns option.<br> --help Show this message and exit.<br>```<br><br>Given a file as follows:<br>```yaml<br>Person:<br> columns:<br> - name: id<br> type: BigInteger<br> primary_key: True<br> auto_increment: True<br> - name: name<br> type: Unicode(255)<br> - name: is_vip<br> type: Boolean<br> - name: created_at<br> type: DateTime(timezone=True)<br><br>Address:<br> columns:<br> - name: id<br> type: BigInteger<br> primary_key: True<br> auto_increment: True<br> - name: line1<br> type: Unicode()<br> - name: line2<br> type: Unicode()<br> - name: line3<br> type: Unicode()<br> - name: postcode<br> type: Unicode(10)<br> index: True<br>```<br><br>The cli tool will create two the following two files ```Person.py``` and ```Address.py```.<br><br>```python<br>from __future__ import unicode_literals, absolute_import, print_function<br><br>from collections import namedtuple<br><br>from sqlalchemy import Column, DateTime, Boolean, Unicode, BigInteger<br><br><br>from .alchemy_base import Base<br><br>__author__ = 'danishabdullah'<br><br><br>class Person(Base):<br> __tablename__ = 'persons'<br><br> id = Column(BigInteger, primary_key=True, auto_increment=True)<br> name = Column(Unicode(255), )<br> is_vip = Column(Boolean, )<br> created_at = Column(DateTime(timezone=True), )<br><br><br> def __init__(self, id=None, name=None, is_vip=None, created_at=None):<br> self.id = id<br> self.name = name<br> self.is_vip = is_vip<br> self.created_at = created_at<br><br> def add(self, session):<br> session.add(self)<br><br> def update(self, name=None, is_vip=None, created_at=None):<br> # This function only updates a value if it is not None.<br> # Falsy values go through in the normal way.<br> # To set things to None use the usual syntax:<br> # Person.column_name = None<br><br> if name is not None:<br> self.name = name<br><br> if is_vip is not None:<br> self.is_vip = is_vip<br><br> if created_at is not None:<br> self.created_at = created_at<br><br> def delete(self, session):<br> session.delete(self)<br><br> def to_dict(self):<br> return {x: y for x, y in self.__dict__.items() if not x.startswith("_sa")}<br><br> def get_proxy_cls(self):<br> # PersonProxy is useful when you want to persist data<br> # independent of the sqlalchemy session. It's just a namedtuple<br> # that has very low memory/cpu footprint compared the regular<br> # orm class instances.<br> keys = self.to_dict().keys()<br> name = "PersonProxy"<br> return namedtuple(name, keys)<br><br> def to_proxy(self):<br> # Proxy-ing is useful when you want to persist data<br> # independent of the sqlalchemy session. It's just a namedtuple<br> # that has very low memory/cpu footprint compared the regular<br> # orm class instances.<br> cls = self._get_proxy_cls()<br> return cls(**self.to_dict())<br><br> @classmethod<br> def from_proxy(cls, proxy):<br> return cls(**proxy._asdict())<br><br> def __hash__(self):<br> return hash(str(self.id))<br><br> def __eq__(self, other):<br> return (self.id == other.id)<br><br> def __neq__(self, other):<br> return not (self.id == other.id)<br><br> def __str__(self):<br> return "<Person: {id}>".format(id=self.id)<br><br> def __unicode__(self):<br> return "<Person: {id}>".format(id=self.id)<br><br> def __repr__(self):<br> return "<Person: {id}>".format(id=self.id)<br>```<br><br>```python<br>from __future__ import unicode_literals, absolute_import, print_function<br><br>from collections import namedtuple<br><br>from sqlalchemy import Column, Unicode, BigInteger<br><br><br>from .alchemy_base import Base<br><br>__author__ = 'danishabdullah'<br><br><br>class Address(Base):<br> __tablename__ = 'addresses'<br><br> id = Column(BigInteger, primary_key=True, auto_increment=True)<br> line1 = Column(Unicode(), )<br> line2 = Column(Unicode(), )<br> line3 = Column(Unicode(), )<br> postcode = Column(Unicode(10), index=True)<br><br><br> def __init__(self, id=None, line1=None, line2=None, line3=None, postcode=None):<br> self.id = id<br> self.line1 = line1<br> self.line2 = line2<br> self.line3 = line3<br> self.postcode = postcode<br><br> def add(self, session):<br> session.add(self)<br><br> def update(self, line1=None, line2=None, line3=None, postcode=None):<br> # This function only updates a value if it is not None.<br> # Falsy values go through in the normal way.<br> # To set things to None use the usual syntax:<br> # Address.column_name = None<br><br> if line1 is not None:<br> self.line1 = line1<br><br> if line2 is not None:<br> self.line2 = line2<br><br> if line3 is not None:<br> self.line3 = line3<br><br> if postcode is not None:<br> self.postcode = postcode<br><br> def delete(self, session):<br> session.delete(self)<br><br> def to_dict(self):<br> return {x: y for x, y in self.__dict__.items() if not x.startswith("_sa")}<br><br> def get_proxy_cls(self):<br> # AddressProxy is useful when you want to persist data<br> # independent of the sqlalchemy session. It's just a namedtuple<br> # that has very low memory/cpu footprint compared the regular<br> # orm class instances.<br> keys = self.to_dict().keys()<br> name = "AddressProxy"<br> return namedtuple(name, keys)<br><br> def to_proxy(self):<br> # Proxy-ing is useful when you want to persist data<br> # independent of the sqlalchemy session. It's just a namedtuple<br> # that has very low memory/cpu footprint compared the regular<br> # orm class instances.<br> cls = self._get_proxy_cls()<br> return cls(**self.to_dict())<br><br> @classmethod<br> def from_proxy(cls, proxy):<br> return cls(**proxy._asdict())<br><br> def __hash__(self):<br> return hash(str(self.id))<br><br> def __eq__(self, other):<br> return (self.id == other.id)<br><br> def __neq__(self, other):<br> return not (self.id == other.id)<br><br> def __str__(self):<br> return "<Address: {id}>".format(id=self.id)<br><br> def __unicode__(self):<br> return "<Address: {id}>".format(id=self.id)<br><br> def __repr__(self):<br> return "<Address: {id}>".format(id=self.id)<br><br>```<br>
|