API Documentation for PormG

Overview

The PormG module provides a set of abstractions and functions for working with SQL databases in Julia. It includes various types for SQL operations, models, and migrations, along with utilities for querying and manipulating data.

Exported Functions

object

  • Description: Retrieves an object from the database.
  • Usage: query = M.Model_name |> object;

show_query

  • Description: Displays the SQL query that will be executed.
  • Usage: show_query(...)

list

  • Description: Lists records from the database.
  • Usage: list(...)

bulk_insert

  • Description: Inserts multiple records into the database in a single operation.
  • Usage: bulk_insert(...)

bulk_update

  • Description: Updates multiple records in the database in a single operation.
  • Usage: bulk_update(...)

delete

  • Description: Deletes records from the database.
  • Usage: delete(...)

do_count

  • Description: Counts the number of records that match a query.
  • Usage: do_count(...)

do_exists

  • Description: Checks if any records exist that match a query.
  • Usage: do_exists(...)

Abstract Types

PormGAbstractType

  • Description: The base abstract type for all types in the PormG module.

SQLConn

  • Description: Represents a connection to a SQL database.

SQLObject

  • Description: Represents an object that can be stored in the database.

SQLObjectHandler

  • Description: Handles operations related to SQL objects.

SQLTableAlias

  • Description: Manages table aliases in SQL queries.

SQLInstruction

  • Description: Represents an instruction to build a SQL query.

SQLType

  • Description: Base type for SQL-related types.

SQLTypeField

  • Description: Represents a field to be used in SQL queries.

Usage Examples

Connecting to a Database

conn = SQLConn(...)  # Create a connection to the database

Inserting Records

bulk_insert(conn, data)  # Insert multiple records

Querying Records

results = list(conn, query)  # Retrieve records based on a query

Conclusion

This documentation provides an overview of the API for the PormG module. For more detailed information on each function and type, please refer to the source code and additional documentation files.

API Reference

PormG.QueryBuilder.CountMethod

Count(x; distinct::Bool = false)

Creates an aggregate COUNT function object for use in query building.

Arguments

  • x: The column or expression to count.
  • distinct::Bool = false: If true, counts only distinct values of x.

Examples

# Count just when other_model_id is distinct  
query = MyModels.model_test |> object;
query.filter("id__@gte" => 1)
query.values("id", "count" => Count("other_model_id", distinct=true))
df = query |> list |> DataFrame
source
PormG.QueryBuilder.QMethod

Q(x...)

Create a QObject with the given filters. Ex.: julia a = object("tb_user") a.filter(Q("name" => "John", Qor("age" => 18, "age" => 19)))

Arguments:

  • x: A list of key-value pairs or Qor(x...) or Q(x...) objects.
source
PormG.QueryBuilder.QorMethod

Qor(x...)

Create a QorObject from the given arguments. The QorObject represents a disjunction of SQLTypeQ or SQLTypeQor objects.

Ex.: julia a = object("tb_user") a.filter(Qor("name" => "John", Q("age__gte" => 18, "age__lte" => 19)))

Arguments

  • x...: A variable number of arguments. Each argument can be either a SQLTypeQ or SQLTypeQor object, or a Pair object.
source
PormG.QueryBuilder.WithMethod

Add a Common Table Expression (CTE) to the query object.

CTEs can be joined like regular tables using their field names.

Arguments

  • q::SQLObject: The SQL object to add the CTE to
  • name::String: The name of the CTE (will be used as table name in JOINs)
  • query::SQLObjectHandler: The subquery that defines the CTE

Returns

  • The modified SQLObject with the CTE added

Examples

# Basic CTE with JOIN
duplicates = MyModel.Evaluation |> object
duplicates.filter("status" => "active")
duplicates.values("aval_id", "dias" => Count("id"))

query = MyModel.Evaluation |> object
With(query, "tb_dup", duplicates)
# Now you can reference tb_dup fields: "tb_dup__aval_id", "tb_dup__dias"
query.filter("id" => F("tb_dup__aval_id"))
query.values("id", "name", "tb_dup__dias")
source
PormG.QueryBuilder._get_pair_to_operMethod

getpairtooper(x::Pair)

Converts a Pair object to an OperObject. If the Pair's key is a string, it checks if it contains an operator suffix (e.g. "@gte", "@lte") and returns an OperObject with the corresponding operator. If the key does not contain an operator suffix, it returns an OperObject with the "=" operator. If the key is not a string, it throws an error.

Arguments

  • x::Pair: A Pair object to be converted to an OperObject.

Returns

  • OperObject: An OperObject with the corresponding operator and values.
source
PormG.QueryBuilder._preset_cte_fieldsMethod

Set the field definitions from a CTE query to create temporary PormGField objects. This allows the CTE to be treated like a table with queryable fields for JOINs.

source
PormG.QueryBuilder._solve_fieldMethod

This function checks if the given field is a valid field in the provided model. If the field is valid, it returns the field name, potentially modified based on certain conditions.

source
PormG.QueryBuilder.build_cte_clauseMethod

Build CTE (WITH clause) SQL string from the CTEs defined in the query object.

Arguments

  • ctes::Dict{String, Dict{String, Union{SQLObjectHandler, PormGField}}}: Dict of CTE name => fields dict
  • connection: Database connection for quoting identifiers
  • parameters: Parameterized query object to collect all parameters

Returns

  • String containing the WITH clause SQL, or empty string if no CTEs
source
PormG.QueryBuilder.bulk_insertMethod

Inserts multiple rows into the database in bulk from a DataFrame.

Arguments

  • objct::SQLObjectHandler: The SQL object handler to use for the operation.
  • df::DataFrames.DataFrame: The DataFrame containing the data to be inserted.
  • columns::Vector{Union{String, Pair{String, String}}}: Optional. Specifies the columns to insert and their mappings.
  • chunk_size::Integer: Optional. The number of rows to insert in each batch (default: 1000).
  • show_query::Bool: Optional. If true, prints the generated SQL query (default: false).
  • copy::Bool: Optional. If true, creates a copy of the DataFrame before processing (default: false).

Examples

```julia include("models.jl") import models as mdl

Basic usage

query = mdl.User |> object df = DataFrame(name=["Alice", "Bob"], age=[30, 25]) bulk_insert(query, df)

With column mapping and excluding unwanted variables

query = mdl.Boook |> object df = DataFrame(title=["Book A", "Book B"], authorname=["Alice", "Bob"], year=[2020, 2021], ignoreme=["x", "y"])

Map DataFrame column "author_name" to model field "author"

Exclude "ignore_me" by not including it in the columns argument

bulkinsert(query, df, columns=["title", "year", "authorname" => "author"])

the df will be modified to only include the columns "title", "year", and "author_name" (renamed to "author").

If you want to copy the DataFrame before processing, set copy=true:

bulkinsert(query, df, columns=["title", "year", "authorname" => "author"], copy=true)

```

source
PormG.QueryBuilder.bulk_updateMethod

Performs a bulk update operation on a database table using the provided DataFrame and a query object.

Arguments

  • objct::SQLObjectHandler: The database handler object.
  • df::DataFrames.DataFrame: The DataFrame containing the data to be used for the update.
  • columns: (Optional) Specifies which columns to update. Can be a String, a Pair{String, String}, or a Vector of these. If nothing, no columns are specified.
  • filters: (Optional) Specifies the filters to apply for the update. Can be a String, a Pair{String, T} where T is String, Integer, Bool, Date, or DateTime, or a Vector of these. If nothing, no filters are applied.
  • show_query::Bool: (Optional) If true, prints the generated SQL query. Defaults to false.
  • chunk_size::Integer: (Optional) Number of rows to process per chunk. Defaults to 1000.

Example

# Update the columns of the DataFrame df if df contains the primary key of the table
bulk_update(objct, df)
# Update the name and dof columns for the security_id in the DataFrame df
bulk_update(objct, df, columns=["security_id", "name", "dof"], filters=["security_id"])
source
PormG.QueryBuilder.deleteMethod

Delete objects from the database with proper handling of foreign key relationships and cascading operations.

Arguments

  • objct::SQLObjectHandler: The SQL object handler containing the query and model information
  • show_query::Bool=false: If true, displays the generated SQL queries instead of executing them
  • allow_delete_all::Bool=false: If true, allows deletion without WHERE clause filters (dangerous operation)

Returns

  • Tuple{Integer, Dict{String, Integer}}: A tuple containing:
    • Total number of deleted objects
    • Dictionary mapping model names to their respective deletion counts

Behavior

  • Validates that the connection allows data modification operations
  • Requires WHERE clause filters unless allow_delete_all is explicitly set to true
  • Handles foreign key relationships by building a deletion dependency graph
  • Processes SETNULL, SETDEFAULT, and cascading delete operations appropriately
  • Executes all operations within a database transaction for data integrity

Examples

# Delete objects from a model with a specific filter
query = M.Status |> object
query.filter("status" => "Engine")
total, dict = delete(query)

# Show the SQL query without executing it
query = M.Just_a_test_deletion |> object
query.filter("test_result__constructorid__name" => "Williams")
total, dict = delete(query, show_query = true)

# Delete related tables (cascading delete)
query = M.Result |> object
query.filter("resultid" => 1)
total, dict = delete(query, show_query = false)

# Delete all objects from a model (use with caution)
query = M.Just_a_test_deletion |> object
total, dict = delete(query; allow_delete_all = true)

source
PormG.QueryBuilder.get_filter_queryMethod

getfilterquery(object::SQLObject, instruc::SQLInstruction)

Iterates over the filter of the object and generates the WHERE query for the given SQLInstruction object.

ALERT

  • This internal function is called by the build function.

Arguments

  • object::SQLObject: The object containing the filter to be selected.
  • instruc::SQLInstruction: The SQLInstruction object to which the WHERE query will be added.
source
PormG.QueryBuilder.get_select_queryMethod

getselectquery(object::SQLObject, instruc::SQLInstruction)

Iterates over the values of the object and generates the SELECT query for the given SQLInstruction object.

ALERT

  • This internal function is called by the build function.

Arguments

  • object::SQLObject: The object containing the values to be selected.
  • instruc::SQLInstruction: The SQLInstruction object to which the SELECT query will be added.
source
PormG.QueryBuilder.listMethod

Fetches a list of records from the database and returns them as an array of dictionaries.

This function executes the query and converts each row to a dictionary with column names as keys.

Arguments

  • objct::SQLObjectHandler: The SQL object handler containing the query

Returns

  • Vector{Dict{Symbol, Any}}: Array of dictionaries, where each dictionary represents a row

Example

query = M.Result |> object
query.filter("raceid__year" => 2020)
query.values("driverid__forename", "constructorid__name", "laps")
records = query |> list  # Returns array of dictionaries
# Example output: [Dict(:driverid__forename => "Lewis", :constructorid__name => "Mercedes", :laps => 58), ...]
source
PormG.QueryBuilder.list_jsonMethod

Fetches a list of records from the database and returns them as a JSON string.

This function executes the query, converts each row to a dictionary, and serializes the result as JSON.

Arguments

  • objct::SQLObjectHandler: The SQL object handler containing the query

Returns

  • String: JSON string representation of the query results

Example

query = M.Result |> object
query.filter("raceid__year" => 2020)
query.values("driverid__forename", "constructorid__name", "laps")
json_data = query |> list_json  # Returns JSON string
# Example output: "[{"driverid__forename":"Lewis","constructorid__name":"Mercedes","laps":58}]"
source
PormG.QueryBuilder.objectMethod

Wraps a PormGModel into an ObjectHandler on which you can call:

- .filter(...) to add WHERE clauses
- .values(...) to choose/annotate columns
- .order_by(...) to sort
- .distinct() to add DISTINCT clause
- .create(...) for single-row DML
- .update(...) for single-row DML
- plus bulk_insert, bulk_update, do_count, do_exists, list

Arguments

  • model::PormGModel: The model to be wrapped and handled.

Example

using PormG, DataFrames

# assume models loaded as `M`
query = M.User |> object

# 1) Filtering & selecting
query.filter("is_active" => true)
query.values("id", "username", "email")
df = query |> list |> DataFrame

# 2) Counting
active_users = query |> do_count

# 3) Inserting a single row
query = M.Status |> object
new = query.create("statusid" => 42, "status" => "Foo")  
# returns a Dict of the inserted row

# 4) Updating a single row
query = M.Status |> object
query.filter("statusid" => 42)
query.update("status" => "Bar")

# 5) Ordering & aggregation
query = M.Result |> object
query.filter("raceid__year" => 2020)
query.values(
  "driverid__forename", 
  "constructorid__name", 
  "laps" => Count("laps")
)
query.order_by("-laps")
df2 = query |> list |> DataFrame

# 6) Existence check
query = M.User |> object
query.filter("id" => 1)
exists = query |> do_exists

# 7) Bulk insert
df_new = DataFrame(name=["A","B"], age=[30,25])
bulk_insert(M.User |> object, df_new)

# 8) Bulk update (by primary key)
df_up = DataFrame(id=[1,2], name=["Alice","Bob"])
bulk_update(M.User |> object, df_up, columns=["name"], filters=["id"])
source
PormG.QueryBuilder.pageMethod

Set pagination parameters for a SQL query object.

Arguments

  • object::SQLObjectHandler: The SQL object handler to modify
  • limit::Integer: Maximum number of records to return (default: 10)
  • offset::Integer: Number of records to skip from the beginning (default: 0)

Examples

page(query, limit=20, offset=10) |> list |> DataFrame or page(query, 20, 10) page(query, limit=20) |> list |> DataFrame or page(query, 20)

source
PormG.QueryBuilder.query_listMethod

Fetches a list of records from the database for the given SQLObjectHandler.

Returns

  • The result of the database query as returned by fetch.

Example

query = M.Result |> object
query.filter("raceid__year" => 2020)
query.values("driverid__forename", "constructorid__name", "laps" => Count("laps"))
query.order_by("-laps")
df = query |> list |> DataFrame
source
DataFrames.DataFrameMethod

Creates a DataFrame directly from a SQLObjectHandler query.

This extends the DataFrame constructor to work directly with PormG query objects,

Arguments

  • objct::SQLObjectHandler: The SQL object handler containing the query

Returns

  • DataFrames.DataFrame: The query results as a DataFrame

Example

query = M.Result |> object
query.filter("raceid__year" => 2020)
query.values("driverid__forename", "constructorid__name", "laps")
df = query |> DataFrame  # Direct conversion to DataFrame
source
PormG.QueryBuilder.FExpressionType

F object for direct database field references and operations (similar to Django F expressions).

Allows you to reference database fields directly in operations without pulling data into Julia.

Examples

# Update a field with another field's value
query = MyModel |> object
query.filter("id" => 1)
query.update("field1" => F("field2"))

# Increment a field by a constant
query.update("counter" => F("counter") + 1)

# Update with arithmetic operations between fields
query.update("total" => F("price") * F("quantity"))

# Use in filters to compare fields
query.filter(F("start_date") <= F("end_date"))

# Use in annotations/values
query.values("price", "discounted_price" => F("price") * 0.9)
source
PormG.QueryBuilder.OperObjectType

Mutable struct representing an SQL operator object for using in the filter and annotate. That is a internal function, please do not use it.

Fields

  • operator::String: the operator used in the SQL query.
  • values::Union{String, Integer, Bool}: the value(s) to be used with the operator.
  • column::Union{String, SQLTypeFunction}: the column to be used with the operator.
source
PormG.Models.AutoFieldMethod
AutoField(; kwargs...)

A field type for auto-incrementing integer primary keys, equivalent to PostgreSQL's SERIAL columns.

The AutoField is designed for auto-incrementing integer primary keys and automatically generates unique integer values for each record. Unlike IDField which uses BIGINT, AutoField uses INTEGER type and is suitable for applications that don't require the extended range of BIGINT values.

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • primary_key::Bool = true: Whether this field is the primary key for the table
  • auto_increment::Bool = true: Whether the field should auto-increment (generate values automatically)
  • unique::Bool = true: Whether values in this field must be unique across all records
  • blank::Bool = false: Whether the field can be left blank in forms (not applicable for auto fields)
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = false: Whether to create a database index on this field (primary keys are automatically indexed)
  • default::Union{Int64, Nothing} = nothing: Default value for the field (rarely used with auto-increment)
  • editable::Bool = false: Whether the field should be editable in forms (typically false for auto fields)

Database Mapping

  • PostgreSQL Type: INTEGER with SERIAL auto-increment
  • Auto-increment: Supported through PostgreSQL's SERIAL type (sequence-based)
  • Index: Automatically indexed as primary key
  • Range: 32-bit signed integers (-2,147,483,648 to 2,147,483,647)

AutoField vs IDField Comparison

FeatureAutoFieldIDField
Database TypeINTEGER (SERIAL)BIGINT (BIGSERIAL/IDENTITY)
Range32-bit (-2B to 2B)64-bit (-9Q to 9Q)
Storage4 bytes8 bytes
GenerationSequence-basedIdentity columns or sequence
Use CaseSmall to medium appsLarge-scale applications

When to Use AutoField vs IDField

Use AutoField when:

  • Building small to medium-sized applications
  • You don't expect more than ~2 billion records
  • Storage efficiency is important (4 bytes vs 8 bytes per ID)
  • Working with legacy systems that expect INTEGER primary keys
  • Building lookup tables, categories, or reference data

Use IDField when:

  • Building large-scale applications with potential for massive growth
  • You need the extended range of 64-bit integers
  • Working with data warehouses or analytics platforms
  • Future-proofing against scale requirements
  • Using modern PostgreSQL features like identity columns
source
PormG.Models.BigIntegerFieldMethod
BigIntegerField(; kwargs...)

A field for storing 64-bit signed integers, equivalent to PostgreSQL's BIGINT columns.

The BigIntegerField stores large whole numbers within the 64-bit signed integer range (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807). It's ideal for large identifiers, timestamps, population counts, and other numeric data requiring extended range beyond regular integers.

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • unique::Bool = false: Whether values in this field must be unique across all records
  • blank::Bool = false: Whether the field can be left blank in forms
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = false: Whether to create a database index on this field
  • default::Union{Int64, Nothing} = nothing: Default value for the field
  • editable::Bool = false: Whether the field should be editable in forms

Database Mapping

  • PostgreSQL Type: BIGINT
  • Storage: 8 bytes per value
  • Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
  • Index: Optional, recommended for frequently queried fields

Examples

Large identifier field:

Analytics = Models.Model(
    _id = IDField(),
    user_id = BigIntegerField(db_index=true),
    session_id = BigIntegerField(),
    timestamp_ms = BigIntegerField()  # Unix timestamp in milliseconds
)

Population and statistics:

Country = Models.Model(
    _id = IDField(),
    name = CharField(max_length=100),
    population = BigIntegerField(null=true),
    gdp_usd = BigIntegerField(null=true),  # GDP in USD cents
    area_sq_meters = BigIntegerField()
)

Large external identifiers:

SocialMedia = Models.Model(
    _id = IDField(),
    user = ForeignKey("User"),
    twitter_id = BigIntegerField(unique=true, null=true),
    facebook_id = BigIntegerField(unique=true, null=true),
    follower_count = BigIntegerField(default=0)
)

Common Use Cases

  1. Large Identifiers: External API IDs, social media IDs
  2. Timestamps: Unix timestamps in milliseconds or microseconds
  3. Population Data: Country populations, large counts
  4. Financial Data: Large monetary values in smallest units
  5. Scientific Data: Large measurements, particle counts
  6. Analytics: Large user IDs, session identifiers

Migration Considerations

  • From IntegerField: Safe upgrade, no data loss
  • To IntegerField: Requires validation that all values fit in 32-bit range
  • Index Changes: Indexes will be recreated with new size
  • Application Code: May need updates if expecting different ranges
source
PormG.Models.BooleanFieldMethod
BooleanField(; kwargs...)

A field for storing boolean (true/false) values, equivalent to PostgreSQL's BOOLEAN columns.

The BooleanField stores binary true/false values and is ideal for flags, switches, status indicators, and any field that represents a yes/no or on/off state. It maps directly to PostgreSQL's BOOLEAN type and Julia's Bool type.

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • unique::Bool = false: Whether values in this field must be unique (rarely used with booleans)
  • blank::Bool = false: Whether the field can be left blank in forms
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = false: Whether to create a database index on this field
  • default::Union{Bool, Nothing} = nothing: Default value for the field (true or false)
  • editable::Bool = false: Whether the field should be editable in forms

Examples

Basic boolean flags:

User = Models.Model(
    _id = IDField(),
    username = CharField(max_length=150),
    is_active = BooleanField(default=true),
    is_staff = BooleanField(default=false),
    email_verified = BooleanField(default=false)
)

Boolean Values and Conversion

The field handles various input formats:

  • Julia Bool: true, false
  • Integers: 1 (true), 0 (false)
  • Strings: "true", "false", "1", "0", "yes", "no"
  • NULL: When null=true, accepts NULL/nothing
source
PormG.Models.CharFieldMethod
CharField(; kwargs...)

A field for storing short to medium-length strings, equivalent to PostgreSQL's VARCHAR columns.

The CharField is the most commonly used field for storing textual data with a limited length. It maps to a PostgreSQL VARCHAR column and supports validation, indexing, choices, and various constraints. This field is ideal for names, titles, codes, and other string data with known maximum lengths.

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • max_length::Int = 250: Maximum number of characters allowed (1-255)
  • unique::Bool = false: Whether values in this field must be unique across all records
  • blank::Bool = false: Whether the field can be left blank in forms
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = false: Whether to create a database index on this field
  • db_column::Union{String, Nothing} = nothing: Custom database column name (defaults to field name)
  • default::Union{String, Nothing} = nothing: Default value for the field
  • choices::Union{NTuple{N, Tuple{AbstractString, AbstractString}}, Nothing} = nothing: Restricted set of valid values
  • editable::Bool = true: Whether the field should be editable in forms

Length Constraints

  • Minimum: 1 character
  • Maximum: 255 characters
  • Validation: Automatically enforced at the field level
  • Storage: Efficient variable-length storage in PostgreSQL

Examples

Basic string field:

User = Models.Model(
    _id = IDField(),
    username = CharField(max_length=150, unique=true),
    first_name = CharField(max_length=50),
    last_name = CharField(max_length=50)
)

String field with choices (enumeration):

Order = Models.Model(
    _id = IDField()
    status = CharField(
        max_length=20,
        choices=(
            ("1", "Pending"),
            ("2", "Processing"),
            ("3", "Shipped"),
            ("4", "Delivered"),
            ("5", "Cancelled")
        ),
        default="1"
    )
    customer_name = CharField(max_length=200)
)

Optional field with custom database column:

Product = Models.Model(
    _id = IDField(),
    name = CharField(max_length=200),
    sku = CharField(
        max_length=50, 
        unique=true, 
        db_column="product_sku",
        verbose_name="Stock Keeping Unit"
    )
    category = CharField(max_length=100, null=true, blank=true)
)

Indexed field for performance:

Article = Models.Model(
    _id = IDField(),
    title = CharField(max_length=200, db_index=true),
    slug = CharField(max_length=200, unique=true, db_index=true),
    content = TextField()
)

Choices Feature

The choices parameter allows you to restrict field values to a predefined set:

# Define choices as tuples of (value, display_name)
priority_choices = (
    ("low", "Low Priority"),
    ("medium", "Medium Priority"),
    ("high", "High Priority"),
    ("urgent", "Urgent")
)

Task = Models.Model(
    _id = IDField(),
    title = CharField(max_length=200),
    priority = CharField(max_length=10, choices=priority_choices, default="medium")
)

Choice Format Options:

  1. Tuple of Tuples: (("value1", "Display 1"), ("value2", "Display 2"))
  2. String Format: "(value1, Display 1)(value2, Display 2)"

Default Values

  • Static Default: default="some_value"
  • Must Match Choices: If choices are specified, default must be one of the choice values
  • Length Validation: Default value must not exceed max_length

Database Column Naming

  • Conventions: Follow PostgreSQL naming conventions (lowercase, underscores)

CharField vs TextField

FeatureCharFieldTextField
LengthLimited (1-255)Unlimited
Database TypeVARCHARTEXT
Use CaseShort stringsLong content
IndexingEfficientLess efficient
PerformanceFast queriesSlower for large content

Migration Considerations

  • Increasing Length: Safe operation
  • Decreasing Length: Requires data validation
  • Adding Choices: Application-level change only
  • Changing Column Name: Use db_column parameter

Notes

  • The field uses VARCHAR type which is efficient for short to medium strings
  • Choices are validated at the Julia application level, not in the database
  • The editable=true default makes this field suitable for user input forms
  • Database indexing is optional but recommended for frequently queried fields
  • Compatible with PostgreSQL's text search and pattern matching features

See Also

  • TextField for unlimited length text content
  • EmailField for email address validation
  • Database design best practices for string field sizing
source
PormG.Models.DateFieldMethod
DateField(; kwargs...)

A field for storing date values (without time), equivalent to PostgreSQL's DATE columns.

The DateField stores calendar dates in YYYY-MM-DD format and is ideal for birth dates, event dates, deadlines, and any date information that doesn't require time precision. It maps to PostgreSQL's DATE type and Julia's Date type.

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • unique::Bool = false: Whether values in this field must be unique across all records
  • blank::Bool = false: Whether the field can be left blank in forms
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = false: Whether to create a database index on this field
  • default::Union{String, Nothing} = nothing: Default value for the field (YYYY-MM-DD format)
  • editable::Bool = false: Whether the field should be editable in forms
  • auto_now::Bool = false: Whether to automatically set to current date on every save
  • auto_now_add::Bool = false: Whether to automatically set to current date on creation only

Examples

Basic date fields:

User = Models.Model(
    _id = IDField(),
    username = CharField(max_length=150),
    birth_date = DateField(null=true, blank=true),
    join_date = DateField(auto_now_add=true),
    last_login_date = DateField(null=true)
)

Event and scheduling:

Event = Models.Model(
    _id = IDField(),
    title = CharField(max_length=200),
    event_date = DateField(db_index=true),
    registration_deadline = DateField(),
    created_date = DateField(auto_now_add=true)
)

Business dates:

Invoice = Models.Model(
    _id = IDField(),
    customer = ForeignKey("Customer"),
    issue_date = DateField(auto_now_add=true),
    due_date = DateField(),
    paid_date = DateField(null=true, blank=true)
)

Auto Date Features

autonowadd

Sets the date automatically when the record is first created:

created_date = DateField(auto_now_add=true)
# Automatically set to today's date on creation
# Never changes after initial creation

auto_now

Updates the date automatically every time the record is saved:

last_modified_date = DateField(auto_now=true)
# Set to today's date on every save operation
# Useful for tracking last update dates

Date Input Formats

The field accepts various input formats:

  • Julia Date: Date(2024, 7, 28)
  • DateTime: DateTime(2024, 7, 28, 10, 30) (time ignored)
  • String ISO: "2024-07-28"
  • String formats: Various date strings parseable by Julia
source
PormG.Models.DateTimeFieldMethod
DateTimeField(; kwargs...)

A field for storing date and time values with timezone information.

Keyword Arguments

  • verbose_name::Union{String, Nothing}: Human-readable name for the field. Default: nothing
  • unique::Bool: If true, ensures field values are unique across the table. Default: false
  • blank::Bool: If true, allows empty values in forms/validation. Default: false
  • null::Bool: If true, allows NULL values in the database. Default: false
  • db_index::Bool: If true, creates a database index for faster queries. Default: false
  • default::Union{DateTime, Nothing, String}: Default value for the field. Can be a DateTime object, ISO string, or nothing. Default: nothing
  • editable::Bool: If true, field can be edited in forms. Default: false
  • auto_now::Bool: If true, automatically updates to current datetime on every save. Default: false
  • auto_now_add::Bool: If true, automatically sets to current datetime when record is created. Default: false

Examples

```julia

Basic datetime field

created_at = DateTimeField()

Auto-timestamp fields

createdat = DateTimeField(autonowadd=true) updatedat = DateTimeField(auto_now=true)

Indexed datetime for queries

eventtime = DateTimeField(dbindex=true, verbose_name="Event Timestamp")

With default value

scheduled_at = DateTimeField(default=DateTime(2024, 1, 1, 12, 0, 0))

Optional datetime field

deadline = DateTimeField(null=true, blank=true)```

source
PormG.Models.DecimalFieldMethod
DecimalField(; kwargs...)

A field for storing decimal numbers with fixed precision and scale.

Keyword Arguments

  • verbose_name::Union{String, Nothing}: Human-readable name for the field. Default: nothing
  • unique::Bool: If true, ensures field values are unique across the table. Default: false
  • blank::Bool: If true, allows empty values in forms/validation. Default: false
  • null::Bool: If true, allows NULL values in the database. Default: false
  • db_index::Bool: If true, creates a database index for faster queries. Default: false
  • default::Union{Float64, Nothing}: Default value for the field. Default: nothing
  • editable::Bool: If true, field can be edited in forms. Default: false
  • max_digits::Int: Maximum number of digits allowed (including decimal places). Default: 10
  • decimal_places::Int: Number of decimal places to store. Default: 2

Examples

# Currency field (2 decimal places)
price = DecimalField(max_digits=10, decimal_places=2)

# High precision scientific values
measurement = DecimalField(max_digits=15, decimal_places=6)

# Percentage with 4 decimal places
rate = DecimalField(max_digits=7, decimal_places=4, default=0.0)

# Financial calculation field
amount = DecimalField(
    max_digits=12, 
    decimal_places=2, 
    verbose_name="Transaction Amount",
    db_index=true
)

# Optional decimal field
discount = DecimalField(
    max_digits=5, 
    decimal_places=2, 
    null=true, 
    blank=true
)
source
PormG.Models.EmailFieldMethod
EmailField(; kwargs...)

A field for storing and validating email addresses.

Keyword Arguments

  • verbose_name::Union{String, Nothing}: Human-readable name for the field. Default: nothing
  • unique::Bool: If true, ensures field values are unique across the table. Default: false
  • blank::Bool: If true, allows empty values in forms/validation. Default: false
  • null::Bool: If true, allows NULL values in the database. Default: false
  • db_index::Bool: If true, creates a database index for faster queries. Default: false
  • default::Union{String, Nothing}: Default email address. Default: nothing
  • editable::Bool: If true, field can be edited in forms. Default: false

Examples

# Basic email field
email = EmailField()

# Unique email for user accounts
user_email = EmailField(unique=true, verbose_name="User Email")

# Optional contact email
contact_email = EmailField(null=true, blank=true)

# Email with default value
notification_email = EmailField(default="admin@example.com")

# Indexed email for fast lookups
primary_email = EmailField(
    unique=true, 
    db_index=true, 
)
source
PormG.Models.FloatFieldMethod
FloatField(; kwargs...)

A field for storing floating-point numbers with double precision.

Keyword Arguments

  • verbose_name::Union{String, Nothing}: Human-readable name for the field. Default: nothing
  • unique::Bool: If true, ensures field values are unique across the table. Default: false
  • blank::Bool: If true, allows empty values in forms/validation. Default: false
  • null::Bool: If true, allows NULL values in the database. Default: false
  • db_index::Bool: If true, creates a database index for faster queries. Default: false
  • default::Union{Float64, String, Int64, Nothing}: Default value for the field. Default: nothing
  • editable::Bool: If true, field can be edited in forms. Default: false

Examples

# Basic float field
temperature = FloatField()

# Scientific measurement with default
ph_level = FloatField(default=7.0)

# Optional measurement
weight = FloatField(null=true)
source
PormG.Models.ForeignKeyMethod
ForeignKey(to::Union{String, PormGModel}; kwargs...)

A field that creates a many-to-one relationship to another model, similar to Django's ForeignKey.

The ForeignKey field represents a relationship where many records in the current model can reference a single record in the target model. It creates a foreign key constraint in the database and enables efficient querying of related data.

Required Arguments

  • to::Union{String, PormGModel}: The target model that this field references. Can be either:
    • A string with the model name (e.g., "User", "Category")
    • A direct reference to a PormGModel instance

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • primary_key::Bool = false: Whether this field is the primary key (rarely used with ForeignKey)
  • unique::Bool = false: Whether values must be unique (creates a one-to-one relationship if true)
  • blank::Bool = false: Whether the field can be left blank in forms
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = true: Whether to create a database index on this field (recommended for performance)
  • default::Union{Int64, Nothing} = nothing: Default value for the field (ID of the referenced record)
  • editable::Bool = false: Whether the field should be editable in forms
  • pk_field::Union{String, Symbol, Nothing} = nothing: Which field in the target model to reference (defaults to primary key)
  • on_delete::Union{Function, String, Nothing} = nothing: Action when the referenced object is deleted
  • on_update::Union{String, Nothing} = nothing: Action when the referenced object's key is updated
  • deferrable::Bool = false: Whether the constraint check can be deferred until transaction commit
  • initially_deferred::Bool = false: Whether constraint checking is initially deferred
  • how::Union{String, Nothing} = nothing: Join type for queries ("INNER JOIN", "LEFT JOIN", etc.)
  • related_name::Union{String, Nothing} = nothing: Name for the reverse relation
  • db_constraint::Bool = true: Whether to create a database foreign key constraint

Database Mapping

  • PostgreSQL Type: BIGINT with foreign key constraint
  • Constraint: Creates FOREIGN KEY constraint linking to target table
  • Index: Automatically indexed for query performance

On Delete Options

The on_delete parameter controls what happens when the referenced object is deleted:

  • CASCADE: Delete this object when referenced object is deleted
  • RESTRICT: Prevent deletion of referenced object if this object exists
  • SET_NULL: Set this field to NULL (requires null=true)
  • SET_DEFAULT: Set this field to its default value (requires default to be set)
  • SET: Set this field to a specific value
  • PROTECT: Raise an error to prevent deletion
  • DO_NOTHING: Take no action (may cause database integrity errors)

Examples

Basic foreign key relationship:

Article = Models.Model(
    _id = IDField()
    title = CharField(max_length=200)
    author = ForeignKey("User")
    category = ForeignKey("Category", on_delete=CASCADE)
)

Foreign key allowing NULL values:

Product = Models.Model(
    _id = IDField()
    _id = IDField()
    name = CharField(max_length=100)
    category = ForeignKey("Category", null=true, blank=true, on_delete=SET_NULL)
)

Multiple foreign keys to same model (requires related_name):

Message = Models.Model(
    _id = IDField()
    sender = ForeignKey("User", related_name="sent_messages")
    recipient = ForeignKey("User", related_name="received_messages")
    content = TextField()
)

Related Names and Reverse Relations

  • If related_name is not specified, PormG automatically generates one
  • When multiple ForeignKeys point to the same model, related_name must be explicitly set
  • The related name allows querying from the target model back to this model
  • If you can't remember the related name, you can type your_query.objects.related_objects or your_model.related_objects to see all related names

Database Constraints

  • When db_constraint=true (default), creates actual foreign key constraints in PostgreSQL
  • When db_constraint=false, no database constraint is created (useful for legacy databases)
  • Database constraints ensure referential integrity but may impact performance

Validation

  • The to parameter must be a valid model name or PormGModel instance
  • All boolean parameters are validated for type safety
  • The on_delete parameter is validated against allowed values
  • Invalid parameters trigger warnings but don't cause errors

Notes

  • The field stores the primary key value of the referenced object
  • Uses BIGINT type to match IDField primary keys
  • Supports deferred constraint checking for complex transactions
  • Compatible with PostgreSQL's foreign key features

See Also

  • Django's ForeignKey documentation for conceptual understanding
source
PormG.Models.IDFieldMethod
IDField(; kwargs...)

A field type for auto-incrementing integer primary keys, equivalent to PostgreSQL's BIGSERIAL or GENERATED AS IDENTITY columns.

The IDField is typically used as the primary key for models and automatically generates unique integer values for each record. It maps to a PostgreSQL BIGINT column with auto-increment capabilities.

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • primary_key::Bool = true: Whether this field is the primary key for the table
  • auto_increment::Bool = true: Whether the field should auto-increment (generate values automatically)
  • unique::Bool = true: Whether values in this field must be unique across all records
  • blank::Bool = false: Whether the field can be left blank in forms (not applicable for ID fields)
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = true: Whether to create a database index on this field
  • default::Union{Int64, Nothing} = nothing: Default value for the field (rarely used with auto-increment)
  • editable::Bool = false: Whether the field should be editable in forms (typically false for ID fields)
  • generated::Bool = true: Whether to use PostgreSQL's GENERATED AS IDENTITY feature
  • generated_always::Bool = false: Whether to use GENERATED ALWAYS AS IDENTITY (stricter than regular GENERATED)

Database Mapping

  • PostgreSQL Type: BIGINT with GENERATED AS IDENTITY or GENERATED ALWAYS AS IDENTITY
  • Auto-increment: Supported through PostgreSQL's identity columns
  • Index: Automatically indexed as primary key

Examples

Basic usage (most common):

User = Models.Model(
    _id::PormGField = IDField()
    name::PormGField = CharField(max_length=100)
    email::PormGField = EmailField()
)

Using GENERATED ALWAYS (stricter identity):

Order = Models.Model(
    _id::PormGField = IDField(generated_always=true)
    customer_id::PormGField = ForeignKey("Customer")
    order_date::PormGField = DateTimeField()
)

Notes

  • The IDField is designed to be the primary key and should typically be the first field in your model
  • Values are automatically generated by the database, so you don't need to provide them when creating records
  • The field uses BIGINT type to support large ranges of ID values
  • When generated_always=true, the database will reject any attempts to manually insert ID values
  • This field type is PostgreSQL-specific and optimized for PormG's PostgreSQL backend

Validation

  • All boolean parameters are validated to ensure type safety
  • The verbose_name must be a String or nothing
  • The default value, if provided, must be convertible to Int64
  • Invalid parameters will trigger warnings but won't cause errors (they'll be ignored)
source
PormG.Models.ImageFieldMethod
ImageField(; kwargs...)

A field for storing image file references and metadata.

Keyword Arguments

  • verbose_name::Union{String, Nothing}: Human-readable name for the field. Default: nothing
  • unique::Bool: If true, ensures field values are unique across the table. Default: false
  • blank::Bool: If true, allows empty values in forms/validation. Default: false
  • null::Bool: If true, allows NULL values in the database. Default: false
  • db_index::Bool: If true, creates a database index for faster queries. Default: false
  • default::Union{String, Nothing}: Default image path or URL. Default: nothing
  • editable::Bool: If true, field can be edited in forms. Default: false

Examples

# Basic image field
avatar = ImageField()

# Product image with default
product_image = ImageField(
    default="/static/images/default-product.jpg",
    verbose_name="Product Image"
)

# Optional profile picture
profile_pic = ImageField(null=true)

# Unique banner image
banner = ImageField(
    unique=true,
    db_index=true
)
source
PormG.Models.IntegerFieldMethod
IntegerField(; kwargs...)

A field for storing 32-bit signed integers, equivalent to PostgreSQL's INTEGER columns.

The IntegerField stores whole numbers within the 32-bit signed integer range (-2,147,483,648 to 2,147,483,647). It's ideal for counts, quantities, ratings, and other numeric data that doesn't require decimal places or extremely large values.

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • unique::Bool = false: Whether values in this field must be unique across all records
  • blank::Bool = false: Whether the field can be left blank in forms
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = false: Whether to create a database index on this field
  • default::Union{Int64, Nothing} = nothing: Default value for the field
  • editable::Bool = false: Whether the field should be editable in forms

Examples

Basic integer field:

Product = Models.Model(
    _id = IDField(),
    name = CharField(max_length=200),
    quantity = IntegerField(default=0),
    price_cents = IntegerField()  # Store price in cents to avoid decimals
)

Integer field with constraints:

User = Models.Model(
    _id = IDField(),
    username = CharField(max_length=150, unique=true),
    age = IntegerField(null=true, blank=true),
    score = IntegerField(default=0, db_index=true)
)

Rating system:

Review = Models.Model(
    _id = IDField(),
    product = ForeignKey("Product"),
    rating = IntegerField(default=5),  # 1-5 star rating
    helpful_votes = IntegerField(default=0)
)

Validation and Constraints

  • Range: Automatically validates within INTEGER bounds
  • Type: Accepts integers, numeric strings (converted automatically)
  • Default: Must be an integer or convertible to integer
  • Null: When null=true, accepts NULL values

Migration Considerations

  • Range Changes: Changing to BigIntegerField is safe
  • Adding Constraints: Adding uniqueness or indexes is safe
  • Default Values: Can be added or modified safely
  • Null Constraints: Removing null constraint requires data validation
source
PormG.Models.Model_to_strMethod

Converts a model object to a string representation to create the model.

Arguments

Model_to_str(model::Union{Model_Type, PormGModel}; contants_julia::Vector{String}=reserved_words)::String
  • model::Union{Model_Type, PormGModel}: The model object to convert.
  • contants_julia::Vector{String}=reserved_words: A vector of reserved words in Julia.

Returns

  • String: The string representation of the model object.

Examples

users = Models.Model("users", 
  name = Models.CharField(), 
  email = Models.CharField(), 
  age = Models.IntegerField()
)
source
PormG.Models.OneToOneFieldMethod
OneToOneField(to::Union{String, PormGModel}; kwargs...)

A field that creates a one-to-one relationship to another model, similar to Django's OneToOneField.

The OneToOneField represents a strict one-to-one relationship where each record in the current model corresponds to exactly one record in the target model, and vice versa. It's essentially a ForeignKey with a unique constraint that ensures no two records can reference the same target record.

Required Arguments

  • to::Union{String, PormGModel}: The target model that this field references. Can be either:
    • A string with the model name (e.g., "UserProfile", "Settings")
    • A direct reference to a PormGModel instance

Keyword Arguments

  • verbose_name::Union{String, Nothing} = nothing: A human-readable name for the field
  • primary_key::Bool = false: Whether this field is the primary key (rarely used with OneToOneField)
  • unique::Bool = true: Whether values must be unique (always true for one-to-one relationships)
  • blank::Bool = false: Whether the field can be left blank in forms
  • null::Bool = false: Whether the database column can store NULL values
  • db_index::Bool = true: Whether to create a database index on this field (recommended for performance)
  • default::Union{Int64, Nothing} = nothing: Default value for the field (ID of the referenced record)
  • editable::Bool = false: Whether the field should be editable in forms
  • pk_field::Union{String, Symbol, Nothing} = nothing: Which field in the target model to reference (defaults to primary key)
  • on_delete::Union{Function, String, Nothing} = nothing: Action when the referenced object is deleted
  • on_update::Union{String, Nothing} = nothing: Action when the referenced object's key is updated
  • deferrable::Bool = false: Whether the constraint check can be deferred until transaction commit
  • initially_deferred::Bool = false: Whether constraint checking is initially deferred
  • how::Union{String, Nothing} = nothing: Join type for queries ("INNER JOIN", "LEFT JOIN", etc.)
  • related_name::Union{String, Nothing} = nothing: Name for the reverse relation
  • db_constraint::Bool = true: Whether to create a database foreign key constraint

Database Mapping

  • PostgreSQL Type: BIGINT with unique foreign key constraint
  • Constraint: Creates FOREIGN KEY constraint with UNIQUE constraint
  • Index: Automatically indexed for query performance and uniqueness enforcement

One-to-One Relationship Characteristics

  • Uniqueness: Each target record can only be referenced by one record in the current model
  • Bidirectional: The relationship can be traversed in both directions
  • Inheritance: Often used to extend models without modifying the original table
  • Profile Pattern: Commonly used for user profiles, settings, or detailed information tables

On Delete Options

The on_delete parameter controls what happens when the referenced object is deleted:

  • CASCADE: Delete this object when referenced object is deleted
  • RESTRICT: Prevent deletion of referenced object if this object exists
  • SET_NULL: Set this field to NULL (requires null=true)
  • SET_DEFAULT: Set this field to its default value (requires default to be set)
  • SET: Set this field to a specific value
  • PROTECT: Raise an error to prevent deletion
  • DO_NOTHING: Take no action (may cause database integrity errors)

Examples

Basic one-to-one relationship (User Profile pattern):

User = Models.Model(
    _id = IDField()
    username = CharField(max_length=150, unique=true)
    email = EmailField()
)

UserProfile = Models.Model(
    _id = IDField()
    user = OneToOneField("User", on_delete=CASCADE)
    bio = TextField(blank=true)
    avatar = ImageField(blank=true)
    birth_date = DateField(null=true, blank=true)
)

One-to-one with null values allowed:

Employee = Models.Model(
    _id = IDField()
    name = CharField(max_length=100)
    department = CharField(max_length=50)
)

EmployeeSettings = Models.Model(
    _id = IDField()
    employee = OneToOneField("Employee", null=true, blank=true, on_delete=SET_NULL)
    email_notifications = BooleanField(default=true)
    theme_preference = CharField(max_length=20, default="light")
)

Extending a model without modifying it:

Product = Models.Model(
    _id = IDField()
    name = CharField(max_length=200)
    price = DecimalField(max_digits=10, decimal_places=2)
)

ProductDetails = Models.Model(
    _id = IDField()
    product = OneToOneField("Product", on_delete=CASCADE, related_name="details")
    detailed_description = TextField()
    technical_specs = TextField()
    warranty_info = TextField()
)

Database Constraints vs. Unique ForeignKey

OneToOneField is equivalent to:

# These are functionally identical:
user = OneToOneField("User")
user = ForeignKey("User", unique=true)

However, OneToOneField is more explicit about the intended relationship type and provides better semantic meaning.

Validation

  • The to parameter must be a valid model name or PormGModel instance
  • All boolean parameters are validated for type safety
  • The on_delete parameter is validated against allowed values
  • Uniqueness is automatically enforced at the database level
  • Invalid parameters trigger warnings but don't cause errors

See Also

  • Django's OneToOneField documentation for conceptual understanding
  • Database normalization principles for when to use one-to-one relationships
source
PormG.Models.TextFieldMethod
TextField(; kwargs...)

A field for storing large amounts of text without length restrictions.

Keyword Arguments

  • verbose_name::Union{String, Nothing}: Human-readable name for the field. Default: nothing
  • unique::Bool: If true, ensures field values are unique across the table. Default: false
  • blank::Bool: If true, allows empty values in forms/validation. Default: false
  • null::Bool: If true, allows NULL values in the database. Default: false
  • db_index::Bool: If true, creates a database index for faster queries. Default: false
  • default::Union{String, Nothing}: Default text content. Default: nothing
  • editable::Bool: If true, field can be edited in forms. Default: false

Examples

# Basic text field for long content
description = TextField()

# Blog post content
content = TextField(blank=true)

# Optional notes field
notes = TextField(null=true, blank=true)

# Indexed text field for search
searchable_content = TextField(
    db_index=true
)

# Text field with default content
template = TextField(
    default="Enter your text here...",
    verbose_name="Template Content"
)
source
PormG.Models.get_all_modelsMethod

Returns a vector containing all the models defined in the given module.

Arguments

get_all_models(modules::Module; symbol::Bool=false)::Vector{Union{Symbol, PormGModel}}
  • modules::Module: The module to search for models.
  • symbol::Bool=false: If true, returns the model names as symbols. If false, returns the model instances.

Returns

A vector containing all the models defined in the module.

source
PormG.Models.validate_defaultMethod

validatedefault(default, expectedtype::Type, field_name::String, converter::Function)

Validate the default value for a field based on the expected type.

Arguments

  • default: The default value to be validated.
  • expected_type::Type: The expected type for the default value.
  • field_name::String: The name of the field being validated.
  • converter::Function: A function used to convert the default value if it is not of the expected type.

Returns

  • If the default value is of the expected type, it is returned as is.
  • If the default value can be converted to the expected type using the provided converter function, the converted value is returned.
  • If the default value is neither of the expected type nor convertible to it, an ArgumentError is thrown.
source