Domain files

Pyaella uses a domain file to describe an application or system’s logical models. The domain file is compiled by pyaella.metacode.pyaellac into python modules that can be used in conjunction with the domain file and any of its dependency injection declarations, attributes, or imports.

Here we define a User logic model than will be used to dynamically create a business object and an underlying SQLAlchemy ORM object.

User:
    Fields:
        id: Column(BigInteger,
            Sequence('users_id_seq', start=1011011011),
            CheckConstraint('id<11111111111'),
            server_default=text("nextval('users_id_seq')"),
            primary_key=True)
        user_name: Column(String(50), nullable=False, unique=True)
        email_address: Column(String(255), nullable=False, unique=True)
        password: Column(String(128),
            CheckConstraint('"char_length"(password)>126'), nullable=False)
        is_active: Column(Boolean, default=True)
        first_name: Column(String(64), nullable=False)
        last_name: Column(String(64), nullable=False)
        country_code: Column(String(3), nullable=False)
        phone_number: Column(String(15))
        address1: Column(String(255))
        address2: Column(String(255))
        city: Column(String(255))
        region: Column(String(255))
        post_code: Column(String(16))
        open_id: Column(String(128))
        auth_code: Column(String(8))
        access_token: Column(String(128))
        device_tokens: Column(Text)

Each field in the Fields attribute can become a SQLAlchemy Column, mapped to a users table in the database. If a field is not a SQLAlchemy construct, its created as a Python slot.

We can add some object and table spanning Rules to this logic model:

.
.
.
        auth_code: Column(String(8))
        access_token: Column(String(128))
        device_tokens: Column(Text)
    Rules:
        Unique: [user_name, email_address]

We can also define some custom actions and options:

.
.
.
    Options:
        - add_tr_standard_mod.sql.mako

And if this logic model is destined to be persisted in a table in a database, we can run literal SQL statements directly after the table is created:

.
.
.
    SQL: |

        INSERT INTO users
            (   user_name, email_address, password,
                first_name, last_name, country_code,
                is_active,
                access_token
            )
        VALUES
            (   'xef', 'el.xef@miga.me', '12345678',
                'Xef', 'Fe', 'USA',
                False
            );

Once the Pyaella logical model is defined in the domain file and compiled by pyaellac, the resulting models module can be run directly by python, which will instantiate each model, and have SQLAlchemy emit the SQL statements to stdout:

CREATE TABLE users (
    key VARCHAR,
    initial_entry_by VARCHAR,
    initial_entry_date TIMESTAMP WITHOUT TIME ZONE,
    last_uid VARCHAR,
    last_opr VARCHAR,
    last_upd TIMESTAMP WITHOUT TIME ZONE,
    phone_number VARCHAR(15),
    city VARCHAR(255),
    first_name VARCHAR(64) NOT NULL,
    last_name VARCHAR(64) NOT NULL,
    open_id VARCHAR(128),
    access_token VARCHAR(128),
    address1 VARCHAR(255),
    address2 VARCHAR(255),
    is_active BOOLEAN,
    post_code VARCHAR(16),
    country_code VARCHAR(3) NOT NULL,
    auth_code VARCHAR(8),
    region VARCHAR(255),
    device_tokens TEXT,
    password VARCHAR(128) NOT NULL CHECK ("char_length"(password)>126),
    email_address VARCHAR(255) NOT NULL,
    id BIGINT DEFAULT nextval('users_id_seq') NOT NULL CHECK (id<11111111111),
    user_name VARCHAR(50) NOT NULL,
    PRIMARY KEY (id),
    UNIQUE (user_name, email_address),
    UNIQUE (email_address),
    UNIQUE (user_name)
)

However, this SQL statement emmision isn’t needed or required, but gives the developer options to either create databases and tables ‘on-the-fly’ with Pyaella, or to have Pyaella and SQLAlchemy reflect the database upon each start.

More of the domain-specific syntax of Pyaella and its domain file will be explained else where in this documentation.

More complete example

The following is a fairly complete example of a domain file that describes Users in a fairly typical web application:

PyaellaConfig:
    DeclBase: PyaellaSQLAlchemyBase
    MetaCls: PyaellaDataModelMetaclass
    ReflCls: PyaellaReflectiveModelMetaclass
    SuperCls: PyaellaDataModel

ApplicationDomain:
    Fields:
        id: Column(BigInteger,
            Sequence('application_domains_id_seq', start=1357913579135791),
            CheckConstraint('id<2468024680246802'),
            server_default=text("nextval('application_domains_id_seq')"),
            primary_key=True)
        name: Column(String(64), unique=True, nullable=True)
    Options:
        - add_tr_standard_mod.sql.mako

Application:
    Fields:
        id: Column(Integer,
            Sequence('applications_id_seq', start=1600),
            CheckConstraint('id<2600'),
            server_default=text("nextval('applications_id_seq')"),
            primary_key=True)
        name: Column(String(64), unique=True, nullable=True)
        key_sequence: Column(String(36))
    Relations:
        application_domain_id: Column(BigInteger, ForeignKey('application_domains.id'))
    Rules:
        Unique: [id, application_domain_id]
    Options:
        - add_tr_standard_mod.sql.mako

User:
    Fields:
        id: Column(BigInteger,
            Sequence('users_id_seq', start=1011011011),
            CheckConstraint('id<11111111111'),
            server_default=text("nextval('users_id_seq')"),
            primary_key=True)
        user_name: Column(String(50), nullable=False, unique=True)
        email_address: Column(String(255), nullable=False, unique=True)
        password: Column(String(128),
            CheckConstraint('"char_length"(password)>126'), nullable=False)
        is_active: Column(Boolean, default=True)
        first_name: Column(String(64), nullable=False)
        last_name: Column(String(64), nullable=False)
        country_code: Column(String(3), nullable=False)
        phone_number: Column(String(15))
        address1: Column(String(255))
        address2: Column(String(255))
        city: Column(String(255))
        region: Column(String(255))
        post_code: Column(String(16))
        open_id: Column(String(128))
        auth_code: Column(String(8))
        access_token: Column(String(128))
        device_tokens: Column(Text)
    Rules:
        Unique: [user_name, email_address]
    Options:
        - add_tr_standard_mod.sql.mako
    SQL: |

        INSERT INTO users
            (   user_name, email_address, password,
                first_name, last_name, country_code,
                is_active
            )
        VALUES
            (   'xef', 'el.xef@miga.me', '12345678',
                'Xef', 'Fe', 'USA',
                False
            );

UserTypeLookup:
    Fields:
        name: Column(String(24), unique=True, nullable=False)
        description: Column(String(64), nullable=False)
    Values:
        name: [
            Sys,
            Dev,
            Admin,
            General,
            Bot
        ]
        description: [
            System Administrator,
            Developer,
            Administrator,
            General User,
            Robot
        ]
    Options:
        - add_tr_standard_lu_mod.sql.mako

UserXUserTypeLookup:
    Relations:
        user_id: Column(BigInteger, ForeignKey('users.id'))
        user_type_id: Column(Integer, ForeignKey('user_type_lu.id'))
    Rules:
        Unique: [user_id, user_type_id]
    Options:
        - add_tr_standard_lu_mod.sql.mako

UserAppLicense:
    Fields:
        app_id: Column(Integer, nullable=False)
        domain_id: Column(BigInteger, nullable=False)
        start: Column(DateTime)
        expiry: Column(DateTime)
        license_hash: Column(String(256))
    Relations:
        user_id: Column(BigInteger, ForeignKey('users.id'), nullable=False)
    Rules:
        Unique: [app_id, domain_id, user_id]
    Options:
        - add_tr_standard_mod.sql.mako

Group:
    Fields:
        name: Column(String(24), nullable=False)
        description: Column(String(128), nullable=False)
        display_name: Column(String(64), nullable=False)
    Rules:
        Unique: [name, application_group_type_id]
    Relations:
        application_group_type_id: Column(Integer, ForeignKey('application_group_type_lu.id'))
    Options:
        - add_tr_standard_mod.sql.mako

ApplicationGroupTypeLookup:
    Fields:
        name: Column(String(24), unique=True, nullable=False)
        description: Column(String(64), nullable=False)
    Values:
        name: [
            Mividio RS,
            Mividio Personal
        ]
        description: [
            Real Estate Mividio Application,
            Personal Mividio Application
        ]
    Options:
        - add_tr_standard_lu_mod.sql.mako

UserXGroup:
    Relations:
        user_id: Column(BigInteger, ForeignKey('users.id'))
        group_id: Column(Integer, ForeignKey('groups.id'))
    Rules:
        Unique: [user_id, group_id]
    Options:
        - add_tr_standard_mod.sql.mako

UserTeam:
    Fields:
        name: Column(String(24), nullable=False)
    Relations:
        team_manager_id: Column(BigInteger, ForeignKey('users.id'), nullable=False)
    Rules:
        Unique: [name, team_manager_id]
    Options:
        - add_tr_standard_mod.sql.mako

UserXUserTeam:
    Relations:
        user_id: Column(BigInteger, ForeignKey('users.id'))
        user_team_id: Column(BigInteger, ForeignKey('user_teams.id'))
    Rules:
        Unique: [user_id, user_team_id]
    Options:
        - add_tr_standard_mod.sql.mako

Country:
    Fields:
        order_id: Column(Integer)
        common_name: Column(String)
        formal_name: Column(String)
        type: Column(String)
        sub_type: Column(String)
        sovereignty: Column(String)
        capital: Column(String)
        ISO_4217_currency_code: Column(String(3))
        ISO_4217_currency_name: Column(String)
        ITU_T_telephone_code: Column(String(3))
        ISO_3166_1_2_letter_code: Column(String(3))
        code: Column(String(3))
        ISO_3166_1_number: Column(String(3))
        IANA_country_Code_TLD: Column(String(3))

Asset:
    Fields:
        id: Column(Integer,
            Sequence('assets_id_seq', start=10000),
            server_default=text("nextval('assets_id_seq')"),
            primary_key=True)
        name: Column(String(64))
        description: Column(Text)
        asset_name: Column(String(256), nullable=False)
        height: Column(Integer, nullable=False)
        width: Column(Integer, nullable=False)
        filesize: Column(BigInteger, nullable=False)
        extention: Column(String(3), nullable=False)
        date_uploaded: Column(DateTime, default=datetime.datetime.now)
    Relations:
        owner_id: Column(BigInteger, ForeignKey('users.id'), nullable=False)
    Options:
        - add_tr_standard_mod.sql.mako

REFLECTIVE:
    CountryLookup:

AFTER_CREATE_SQL:
    Literal: |