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.Count
— MethodCount(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
: Iftrue
, counts only distinct values ofx
.
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
PormG.QueryBuilder.Q
— MethodQ(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.
PormG.QueryBuilder.Qor
— MethodQor(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 aSQLTypeQ
orSQLTypeQor
object, or aPair
object.
PormG.QueryBuilder.With
— MethodAdd 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 toname::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")
PormG.QueryBuilder._determine_join_type
— Methodbuild a row to join
PormG.QueryBuilder._get_pair_to_oper
— Methodgetpairtooper(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.
PormG.QueryBuilder._preset_cte_fields
— MethodSet 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.
PormG.QueryBuilder._solve_field
— MethodThis 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.
PormG.QueryBuilder.build_cte_clause
— MethodBuild 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 dictconnection
: Database connection for quoting identifiersparameters
: Parameterized query object to collect all parameters
Returns
- String containing the WITH clause SQL, or empty string if no CTEs
PormG.QueryBuilder.bulk_insert
— MethodInserts 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)
```
PormG.QueryBuilder.bulk_update
— MethodPerforms 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 aString
, aPair{String, String}
, or aVector
of these. Ifnothing
, no columns are specified.filters
: (Optional) Specifies the filters to apply for the update. Can be aString
, aPair{String, T}
whereT
isString
,Integer
,Bool
,Date
, orDateTime
, or aVector
of these. Ifnothing
, no filters are applied.show_query::Bool
: (Optional) Iftrue
, prints the generated SQL query. Defaults tofalse
.chunk_size::Integer
: (Optional) Number of rows to process per chunk. Defaults to1000
.
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"])
PormG.QueryBuilder.delete
— MethodDelete 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 informationshow_query::Bool=false
: Iftrue
, displays the generated SQL queries instead of executing themallow_delete_all::Bool=false
: Iftrue
, 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 totrue
- 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)
PormG.QueryBuilder.escape_like_pattern
— MethodEscape LIKE patterns to prevent wildcard injection
PormG.QueryBuilder.get_filter_query
— Methodgetfilterquery(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.
PormG.QueryBuilder.get_select_query
— Methodgetselectquery(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.
PormG.QueryBuilder.list
— MethodFetches 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), ...]
PormG.QueryBuilder.list_json
— MethodFetches 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}]"
PormG.QueryBuilder.object
— MethodWraps 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"])
PormG.QueryBuilder.page
— MethodSet pagination parameters for a SQL query object.
Arguments
object::SQLObjectHandler
: The SQL object handler to modifylimit::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)
PormG.QueryBuilder.query_list
— MethodFetches 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
PormG.QueryBuilder.quote_identifier
— MethodQuote SQL identifiers based on database type
PormG.QueryBuilder.safe_field_identifier
— MethodValidate field name against model and return quoted identifier
PormG.QueryBuilder.safe_table_identifier
— MethodValidate and quote table name
PormG.QueryBuilder.sanitize_identifier
— MethodSanitize SQL identifiers (table names, column names) to prevent injection. Only allows alphanumeric characters, underscores, and validates against model schema.
PormG.QueryBuilder.up_values!
— MethodAgora eu tenho que ver como que eu padronizo todas as variáveis para sair como SQLTypeField
DataFrames.DataFrame
— MethodCreates 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
PormG.QueryBuilder.FExpression
— TypeF 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)
PormG.QueryBuilder.OperObject
— TypeMutable 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.
PormG.Models.AutoField
— MethodAutoField(; 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 fieldprimary_key::Bool = true
: Whether this field is the primary key for the tableauto_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 recordsblank::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 valuesdb_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
Feature | AutoField | IDField |
---|---|---|
Database Type | INTEGER (SERIAL) | BIGINT (BIGSERIAL/IDENTITY) |
Range | 32-bit (-2B to 2B) | 64-bit (-9Q to 9Q) |
Storage | 4 bytes | 8 bytes |
Generation | Sequence-based | Identity columns or sequence |
Use Case | Small to medium apps | Large-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
PormG.Models.BigIntegerField
— MethodBigIntegerField(; 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 fieldunique::Bool = false
: Whether values in this field must be unique across all recordsblank::Bool = false
: Whether the field can be left blank in formsnull::Bool = false
: Whether the database column can store NULL valuesdb_index::Bool = false
: Whether to create a database index on this fielddefault::Union{Int64, Nothing} = nothing
: Default value for the fieldeditable::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
- Large Identifiers: External API IDs, social media IDs
- Timestamps: Unix timestamps in milliseconds or microseconds
- Population Data: Country populations, large counts
- Financial Data: Large monetary values in smallest units
- Scientific Data: Large measurements, particle counts
- 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
PormG.Models.BooleanField
— MethodBooleanField(; 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 fieldunique::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 formsnull::Bool = false
: Whether the database column can store NULL valuesdb_index::Bool = false
: Whether to create a database index on this fielddefault::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
, acceptsNULL
/nothing
PormG.Models.CharField
— MethodCharField(; 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 fieldmax_length::Int = 250
: Maximum number of characters allowed (1-255)unique::Bool = false
: Whether values in this field must be unique across all recordsblank::Bool = false
: Whether the field can be left blank in formsnull::Bool = false
: Whether the database column can store NULL valuesdb_index::Bool = false
: Whether to create a database index on this fielddb_column::Union{String, Nothing} = nothing
: Custom database column name (defaults to field name)default::Union{String, Nothing} = nothing
: Default value for the fieldchoices::Union{NTuple{N, Tuple{AbstractString, AbstractString}}, Nothing} = nothing
: Restricted set of valid valueseditable::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:
- Tuple of Tuples:
(("value1", "Display 1"), ("value2", "Display 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
Feature | CharField | TextField |
---|---|---|
Length | Limited (1-255) | Unlimited |
Database Type | VARCHAR | TEXT |
Use Case | Short strings | Long content |
Indexing | Efficient | Less efficient |
Performance | Fast queries | Slower 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 contentEmailField
for email address validation- Database design best practices for string field sizing
PormG.Models.DateField
— MethodDateField(; 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 fieldunique::Bool = false
: Whether values in this field must be unique across all recordsblank::Bool = false
: Whether the field can be left blank in formsnull::Bool = false
: Whether the database column can store NULL valuesdb_index::Bool = false
: Whether to create a database index on this fielddefault::Union{String, Nothing} = nothing
: Default value for the field (YYYY-MM-DD format)editable::Bool = false
: Whether the field should be editable in formsauto_now::Bool = false
: Whether to automatically set to current date on every saveauto_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
PormG.Models.DateTimeField
— MethodDateTimeField(; 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
: Iftrue
, ensures field values are unique across the table. Default:false
blank::Bool
: Iftrue
, allows empty values in forms/validation. Default:false
null::Bool
: Iftrue
, allows NULL values in the database. Default:false
db_index::Bool
: Iftrue
, 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, ornothing
. Default:nothing
editable::Bool
: Iftrue
, field can be edited in forms. Default:false
auto_now::Bool
: Iftrue
, automatically updates to current datetime on every save. Default:false
auto_now_add::Bool
: Iftrue
, 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)```
PormG.Models.DecimalField
— MethodDecimalField(; 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
: Iftrue
, ensures field values are unique across the table. Default:false
blank::Bool
: Iftrue
, allows empty values in forms/validation. Default:false
null::Bool
: Iftrue
, allows NULL values in the database. Default:false
db_index::Bool
: Iftrue
, creates a database index for faster queries. Default:false
default::Union{Float64, Nothing}
: Default value for the field. Default:nothing
editable::Bool
: Iftrue
, 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
)
PormG.Models.EmailField
— MethodEmailField(; 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
: Iftrue
, ensures field values are unique across the table. Default:false
blank::Bool
: Iftrue
, allows empty values in forms/validation. Default:false
null::Bool
: Iftrue
, allows NULL values in the database. Default:false
db_index::Bool
: Iftrue
, creates a database index for faster queries. Default:false
default::Union{String, Nothing}
: Default email address. Default:nothing
editable::Bool
: Iftrue
, 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,
)
PormG.Models.FloatField
— MethodFloatField(; 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
: Iftrue
, ensures field values are unique across the table. Default:false
blank::Bool
: Iftrue
, allows empty values in forms/validation. Default:false
null::Bool
: Iftrue
, allows NULL values in the database. Default:false
db_index::Bool
: Iftrue
, creates a database index for faster queries. Default:false
default::Union{Float64, String, Int64, Nothing}
: Default value for the field. Default:nothing
editable::Bool
: Iftrue
, 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)
PormG.Models.ForeignKey
— MethodForeignKey(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 fieldprimary_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 formsnull::Bool = false
: Whether the database column can store NULL valuesdb_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 formspk_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 deletedon_update::Union{String, Nothing} = nothing
: Action when the referenced object's key is updateddeferrable::Bool = false
: Whether the constraint check can be deferred until transaction commitinitially_deferred::Bool = false
: Whether constraint checking is initially deferredhow::Union{String, Nothing} = nothing
: Join type for queries ("INNER JOIN", "LEFT JOIN", etc.)related_name::Union{String, Nothing} = nothing
: Name for the reverse relationdb_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 deletedRESTRICT
: Prevent deletion of referenced object if this object existsSET_NULL
: Set this field to NULL (requiresnull=true
)SET_DEFAULT
: Set this field to its default value (requiresdefault
to be set)SET
: Set this field to a specific valuePROTECT
: Raise an error to prevent deletionDO_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
oryour_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
PormG.Models.IDField
— MethodIDField(; 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 fieldprimary_key::Bool = true
: Whether this field is the primary key for the tableauto_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 recordsblank::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 valuesdb_index::Bool = true
: Whether to create a database index on this fielddefault::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 featuregenerated_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)
PormG.Models.ImageField
— MethodImageField(; 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
: Iftrue
, ensures field values are unique across the table. Default:false
blank::Bool
: Iftrue
, allows empty values in forms/validation. Default:false
null::Bool
: Iftrue
, allows NULL values in the database. Default:false
db_index::Bool
: Iftrue
, creates a database index for faster queries. Default:false
default::Union{String, Nothing}
: Default image path or URL. Default:nothing
editable::Bool
: Iftrue
, 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
)
PormG.Models.IntegerField
— MethodIntegerField(; 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 fieldunique::Bool = false
: Whether values in this field must be unique across all recordsblank::Bool = false
: Whether the field can be left blank in formsnull::Bool = false
: Whether the database column can store NULL valuesdb_index::Bool = false
: Whether to create a database index on this fielddefault::Union{Int64, Nothing} = nothing
: Default value for the fieldeditable::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
PormG.Models.Model_to_str
— MethodConverts 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()
)
PormG.Models.OneToOneField
— MethodOneToOneField(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 fieldprimary_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 formsnull::Bool = false
: Whether the database column can store NULL valuesdb_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 formspk_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 deletedon_update::Union{String, Nothing} = nothing
: Action when the referenced object's key is updateddeferrable::Bool = false
: Whether the constraint check can be deferred until transaction commitinitially_deferred::Bool = false
: Whether constraint checking is initially deferredhow::Union{String, Nothing} = nothing
: Join type for queries ("INNER JOIN", "LEFT JOIN", etc.)related_name::Union{String, Nothing} = nothing
: Name for the reverse relationdb_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 withUNIQUE
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 deletedRESTRICT
: Prevent deletion of referenced object if this object existsSET_NULL
: Set this field to NULL (requiresnull=true
)SET_DEFAULT
: Set this field to its default value (requiresdefault
to be set)SET
: Set this field to a specific valuePROTECT
: Raise an error to prevent deletionDO_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
PormG.Models.TextField
— MethodTextField(; 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
: Iftrue
, ensures field values are unique across the table. Default:false
blank::Bool
: Iftrue
, allows empty values in forms/validation. Default:false
null::Bool
: Iftrue
, allows NULL values in the database. Default:false
db_index::Bool
: Iftrue
, creates a database index for faster queries. Default:false
default::Union{String, Nothing}
: Default text content. Default:nothing
editable::Bool
: Iftrue
, 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"
)
PormG.Models.are_model_fields_equal
— Methodaremodelfieldsequal(newmodel::PormGModel, old_model::PormGModel) :: Bool
Compares the fields of two PormGModel
instances to determine if they are equal.
PormG.Models.format_string
— Methodformat_string(x)
Format the input x
as a string if it is of type String
, otherwise return x
as is.
PormG.Models.get_all_models
— MethodReturns 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
: Iftrue
, returns the model names as symbols. Iffalse
, returns the model instances.
Returns
A vector containing all the models defined in the module.
PormG.Models.validate_default
— Methodvalidatedefault(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.