<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sushmitha B</title>
    <description>The latest articles on DEV Community by Sushmitha B (@sushmitha_b_06c9646d9a20a).</description>
    <link>https://dev.to/sushmitha_b_06c9646d9a20a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2043317%2F8e7476ab-d819-4a17-8b31-cdeac1070fd7.jpeg</url>
      <title>DEV Community: Sushmitha B</title>
      <link>https://dev.to/sushmitha_b_06c9646d9a20a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sushmitha_b_06c9646d9a20a"/>
    <language>en</language>
    <item>
      <title>This Single-Line Command Reduced Our Database Object Management Efforts</title>
      <dc:creator>Sushmitha B</dc:creator>
      <pubDate>Sun, 08 Sep 2024 17:08:11 +0000</pubDate>
      <link>https://dev.to/sushmitha_b_06c9646d9a20a/this-single-line-command-reduced-our-database-object-management-efforts-10f8</link>
      <guid>https://dev.to/sushmitha_b_06c9646d9a20a/this-single-line-command-reduced-our-database-object-management-efforts-10f8</guid>
      <description>&lt;p&gt;Managing SQL tasks manually can be tedious, so we developed a custom command to simplify these tasks. &lt;/p&gt;

&lt;p&gt;By integrating this tool into our workflow, we have significantly improved our productivity and minimized the risk of human error in SQL task management.&lt;/p&gt;

&lt;h1&gt;
  
  
  Managing Many Triggers: The Hidden Chaos in Complex Deployments
&lt;/h1&gt;

&lt;p&gt; As the volume of SQL components like triggers, functions, and materialized views grows, scattered or unstructured storage can complicate tracking changes, leading to deployment errors and inconsistencies.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Pain of Handling SQL Manually
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inconsistency:&lt;/strong&gt; Deploying a SQL trigger manually across multiple environments risks errors and inconsistencies. Missing a step or making a mistake can lead to conflicting and unexpected application issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error-prone:&lt;/strong&gt; Executing complex SQL scripts manually increases the risk of typos or missed parameters. This can result in deployment fails, broken functionality, or data loss.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without a centralized solution, manual updates become inefficient and risky, making it difficult to keep all environments synchronized and reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Losing the Trigger SQL:  A Reconstruction Challenge
&lt;/h2&gt;

&lt;p&gt;Losing the original SQL scripts can be a major setback, can face the task of reconstructing the exact logic and syntax.&lt;/p&gt;

&lt;p&gt;While it's possible to recover them with multiple ways like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT tgname AS trigger_name, 
       tgenabled AS enabled, 
       pg_get_triggerdef(t.oid) AS definition
FROM pg_trigger t
JOIN pg_class c ON c.oid = t.tgrelid
WHERE c.relname = 'attendance_data2';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the process can be time-consuming and distracting, this not only slow down progress but also redirect valuable effort away from core development tasks.&lt;/p&gt;

&lt;p&gt;This could affect the fast-paced environment where speed often takes precedence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Version Control Woes: The Struggle to Revert and Recover
&lt;/h3&gt;

&lt;p&gt;Without a centralized version control system for SQL scripts, tracking modifications becomes a challenge. there is a struggle to identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who made changes&lt;/li&gt;
&lt;li&gt;When changes were made&lt;/li&gt;
&lt;li&gt;Why changes were made&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Introducing Sync Triggers: A Streamlined Approach
&lt;/h3&gt;

&lt;p&gt;In order to make the SQL management easier &lt;br&gt;
we are using custom management command with manage.py commandline interface,where it  offers a powerful solution to simplify SQL component deployment and maintenance. &lt;/p&gt;

&lt;p&gt;By consolidating all SQL scripts into a single command, we gain centralized control over SQL logic.&lt;/p&gt;

&lt;p&gt;We are using &lt;code&gt;PL/Python&lt;/code&gt; it is a procedural language extension for PostgreSQL that allows us to write database functions in Python.&lt;/p&gt;
&lt;h2&gt;
  
  
  What &lt;code&gt;Sync Triggers&lt;/code&gt; Does: Makies Your Task Easy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automates SQL Deployment:&lt;/strong&gt; Sync Triggers automates the deployment process, ensuring all scripts are applied correctly to the target database.&lt;/p&gt;

&lt;p&gt;Dependencies can be managed in more organised way, ensures that they are applied correctly to all objects.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Centralized Repository:&lt;/strong&gt; Encourages storing all SQL scripts in a single, designated directory. This central repository makes it easier to locate, manage, and version control your SQL logic.&lt;/p&gt;

&lt;p&gt;This organization can also help prevent accidental deletions or modifications and increases the readability and understanding.&lt;br&gt;
    &lt;br&gt;
This can quickly find the specific SQL component need, saving time and effort.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Version Control Integration:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As we are centralising the files in directory, is then tracked by Git or other version control system, meaning any changes made to the SQL scripts are automatically recorded. &lt;/p&gt;

&lt;p&gt;this also provides the rollback machanism, reseting the state of the entire repository to a desired state, which overcomes from unintended changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Language Flexibility:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Utilizing &lt;code&gt;PL/Python&lt;/code&gt; extension for PostgreSQL, which is basically python language, as it is familiar, writing logic becomes easier, its rich libraries can easily be integrated.&lt;/p&gt;

&lt;p&gt;Suited for tasks that go beyond basic database operations, such as interacting with external systems or using advanced data structures.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Benefits: Minimized Obstacles and Enhanced Efficiency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Improved Consistency&lt;/strong&gt;&lt;br&gt;
    Ensures uniform application of SQL scripts and dependencies across different environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streamlined Workflows&lt;/strong&gt;&lt;br&gt;
Simplifies the deployment process, reducing the chances of delays or bottlenecks&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conflict Resolution&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;DROP&lt;/code&gt; statement removes any existing functions, preventing conflicts and ensuring that the new function can be created without interference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplified Iteration and Updates&lt;/strong&gt; &lt;br&gt;
Making updates or iterating on SQL logic is straightforward.&lt;/p&gt;
&lt;h3&gt;
  
  
  How Can You Implement: Straightforward SQL Execution
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def sync_trigger(trigger_file, database_name):
    with open(trigger_file) as f:
        trigger_sql = f.read()
    with connections[database_name].cursor() as cursor:
        cursor.execute(trigger_sql)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;construct a function to read the SQL file and executes its content on the specified database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Command(BaseCommand):

    def add_arguments(self, parser):
        parser.add_argument(
            "--tdb",
            action="store_true",
            help="Applies synctriggers to t-DB",
        )
        parser.add_argument(
            "--pdb",
            action="store_true",
            help="Applies synctriggers to p-DB",
        )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add_argument function defines the command-line arguments that can be used as custom commands&lt;br&gt;
those are flags for the command as parameter which proceeds with respected db&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; def handle(self, *args, **options):

        database_name = "default"
        if options["tdb"]:
            database_name = "default"
        if options["pdb"]:
            database_name = "prod"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This performs the logical operations of applying triggers,&lt;/p&gt;

&lt;p&gt;specifies the database associated with perticular flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; triggers = sorted(
            filter(os.path.isfile, list(Path("ic/triggers").glob("*.sql")))
        )
        for trigger in triggers:
            print("Executing ", trigger)
            sync_trigger(trigger, database_name)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Specify directory in which the executable files are located&lt;/p&gt;

&lt;p&gt;Then iterates over each file in directory.&lt;/p&gt;

&lt;h4&gt;
  
  
  End Goal: Key Functions And Outcomes
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;python3 manage.py synctriggers --testdb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When custom management command is run,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;manage.py&lt;/code&gt; sets up the Django environment and runs the synctriggers Python function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;synctriggers.py&lt;/code&gt; checks the flag was provided, based on the flag execution is done.&lt;/li&gt;
&lt;li&gt;The script searches the specified folder for SQL trigger files.&lt;/li&gt;
&lt;li&gt;For each trigger file, it reads the SQL code, and executes it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Understanding &lt;code&gt;manage.py&lt;/code&gt;: Creating Custom Commands
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import sys
def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'karma_models.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This sets up the Django environment by defining the &lt;code&gt;DJANGO_SETTINGS_MODULE&lt;/code&gt; variable to project's settings module &lt;code&gt;karma_models.settings&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Imports &lt;code&gt;execute_from_command_line&lt;/code&gt; from &lt;code&gt;django.core.management&lt;/code&gt; module, which processes the arguments passed in &lt;code&gt;sys.argv&lt;/code&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Calls &lt;code&gt;execute_from_command_line(sys.argv)&lt;/code&gt; to parse and run the appropriate management command synctriggers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Folder structure: Centralised Management of SQL Functions
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk44fawal6wzrwsyk5my.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk44fawal6wzrwsyk5my.png" alt="image" width="462" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This structure demonstrates centralized management of database triggers and functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  One file example: Applying The Concept
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
CREATE OR REPLACE FUNCTION update_target_table_on_check_in(
    user_id TEXT,
    time_of_attendance TIMESTAMP WITH TIME ZONE
)
RETURNS VOID
LANGUAGE plpython3u
AS
$$
    insert_query = """
    INSERT INTO target_table (
        user_id, 
        attendance_date, 
        check_in_count, 
        created_at, 
        updated_at
    ) 
    VALUES (%s, %s, %s, %s, %s)
    """
    current_timestamp = plpy.execute("SELECT CURRENT_TIMESTAMP")[0]["current_timestamp"]

    values = [
        user_id,                      
        time_of_attendance.date(),     
        1,                            
        current_timestamp,            
        current_timestamp             
    ]
    plpy.execute(insert_query % tuple(values))

    return None
$$;

DROP TRIGGER IF EXISTS trigger_update_target_table ON primary_table;

CREATE TRIGGER trigger_update_target_table
AFTER INSERT ON primary_table
FOR EACH ROW
EXECUTE FUNCTION update_target_table_on_check_in(
    NEW.userid,
    NEW.time_of_attendance
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;target_table:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhz9ow7g044i4p2j0gz9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhz9ow7g044i4p2j0gz9d.png" alt="image" width="534" height="56"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;primary_table:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpo2p8bhmqu0qxzei5bi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpo2p8bhmqu0qxzei5bi.png" alt="image" width="800" height="25"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a PostgreSQL function that inserts a new record into the &lt;code&gt;target_table&lt;/code&gt; table whenever there is a new entry in the &lt;code&gt;primary_table&lt;/code&gt; table. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;DROP TRIGGER IF EXISTS&lt;/code&gt; statement removes any triggers from the table if it exists, preventing conflicts when creating a new trigger with the same name.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CREATE TRIGGER&lt;/code&gt; statement defines a trigger that is executed after a specific event occurs on a specified table. The &lt;code&gt;EXECUTE FUNCTION&lt;/code&gt; clause specifies the function that should be called to perform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhancing SQL Management Efficiency
&lt;/h3&gt;

&lt;p&gt;By this approach, we have moved away from the tedious, error-prone process of managing SQL scripts.&lt;/p&gt;

&lt;p&gt;By centralizing triggers and functions, integrating version control, and automating deployments, we’ve achieved consistency across environments.&lt;/p&gt;

&lt;p&gt;This feature can be further customized based on needs, such as adding Automated Rollbacks, Logging and Monitoring, and a Dry Run Mode (preview simulation).&lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>custom</category>
    </item>
  </channel>
</rss>
