{"id":28829290,"url":"https://github.com/ballerina-platform/module-ballerinax-postgresql","last_synced_at":"2026-04-01T17:08:49.191Z","repository":{"id":36967384,"uuid":"323231589","full_name":"ballerina-platform/module-ballerinax-postgresql","owner":"ballerina-platform","description":"Ballerina PostgreSQL DB module","archived":false,"fork":false,"pushed_at":"2026-04-01T05:52:06.000Z","size":4093,"stargazers_count":108,"open_issues_count":1,"forks_count":27,"subscribers_count":65,"default_branch":"main","last_synced_at":"2026-04-01T08:20:32.262Z","etag":null,"topics":["ballerina","postgresql"],"latest_commit_sha":null,"homepage":"","language":"Ballerina","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ballerina-platform.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-12-21T04:37:50.000Z","updated_at":"2026-04-01T05:34:02.000Z","dependencies_parsed_at":"2023-02-19T15:16:23.700Z","dependency_job_id":"0e596ea2-ab68-4467-99b9-2658816af0d5","html_url":"https://github.com/ballerina-platform/module-ballerinax-postgresql","commit_stats":null,"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/ballerina-platform/module-ballerinax-postgresql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ballerina-platform%2Fmodule-ballerinax-postgresql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ballerina-platform%2Fmodule-ballerinax-postgresql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ballerina-platform%2Fmodule-ballerinax-postgresql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ballerina-platform%2Fmodule-ballerinax-postgresql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ballerina-platform","download_url":"https://codeload.github.com/ballerina-platform/module-ballerinax-postgresql/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ballerina-platform%2Fmodule-ballerinax-postgresql/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290538,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ballerina","postgresql"],"created_at":"2025-06-19T05:12:44.193Z","updated_at":"2026-04-01T17:08:49.184Z","avatar_url":"https://github.com/ballerina-platform.png","language":"Ballerina","funding_links":[],"categories":[],"sub_categories":[],"readme":"Ballerina PostgreSQL Library\n===================\n            \n  [![Build](https://github.com/ballerina-platform/module-ballerinax-postgresql/actions/workflows/build-timestamped-master.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-postgresql/actions/workflows/build-timestamped-master.yml)\n  [![codecov](https://codecov.io/gh/ballerina-platform/module-ballerinax-postgresql/branch/main/graph/badge.svg)](https://codecov.io/gh/ballerina-platform/module-ballerinax-postgresql)\n  [![Trivy](https://github.com/ballerina-platform/module-ballerinax-postgresql/actions/workflows/trivy-scan.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-postgresql/actions/workflows/trivy-scan.yml)\n  [![GraalVM Check](https://github.com/ballerina-platform/module-ballerinax-postgresql/actions/workflows/build-with-bal-test-graalvm.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-postgresql/actions/workflows/build-with-bal-test-graalvm.yml)\n  [![GitHub Last Commit](https://img.shields.io/github/last-commit/ballerina-platform/module-ballerinax-postgresql.svg)](https://github.com/ballerina-platform/module-ballerinax-postgresql/commits/main)\n  [![Github issues](https://img.shields.io/github/issues/ballerina-platform/ballerina-standard-library/module/postgresql.svg?label=Open%20Issues)](https://github.com/ballerina-platform/ballerina-standard-library/labels/module%2Fpostgresql)\n\nThis library provides the functionality required to access and manipulate data stored in a PostgreSQL database.\n\n### Prerequisite\nAdd the PostgreSQL driver as a dependency to the Ballerina project.\n\n\u003e**Note**: `ballerinax/postgresql` supports PostgrSQL driver versions above 42.2.18.\n\nYou can achieve this by importing the `ballerinax/postgresql.driver` module,\n ```ballerina\n import ballerinax/postgresql.driver as _;\n ```\n\n`ballerinax/postgresql.driver` package bundles the latest PostgreSQL driver JAR.\n\n\u003e**Tip**: GraalVM native build is supported when `ballerinax/postgresql` is used along with the `ballerinax/postgresql.driver`\n\nIf you want to add a PostgreSQL driver of a specific version, you can add it as a dependency in Ballerina.toml.\nFollow one of the following ways to add the JAR in the file:\n\n* Download the JAR and update the path\n    ```\n    [[platform.java21.dependency]]\n    path = \"PATH\"\n    ```\n\n* Add JAR with a maven dependency params\n    ```\n    [[platform.java21.dependency]]\n    groupId = \"org.postgresql\"\n    artifactId = \"postgresql\"\n    version = \"42.6.1\"\n    ```\n\n### Setup guide\n\n#### Change data capture\n\n1. **Enable Logical Replication**:\n   - Add the following lines to the PostgreSQL configuration file (`postgresql.conf`):\n     ```ini\n     wal_level = logical\n     max_replication_slots = 4\n     max_wal_senders = 4\n     ```\n   - Restart the PostgreSQL server to apply the changes:\n     ```bash\n     sudo service postgresql restart\n     ```\n\n### Client\nTo access a database, you must first create a\n[`postgresql:Client`](https://docs.central.ballerina.io/ballerinax/postgresql/latest#Client) object.\nThe examples for creating a PostgreSQL client can be found below.\n\n\u003e **Tip**: The client should be used throughout the application lifetime.\n\n#### Create a client\nThis example shows the different methods of creating a `postgresql:Client`.\n\nWhen the database is in the default username, the client can be created with an empty constructor, and thereby, the client will be initialized with the default properties.\n\n```ballerina\npostgresql:Client|sql:Error dbClient = new ();\n```\n\nThe `postgresql:Client` receives the host, username, password, database, and port. Since the properties are passed in the same order as they are defined\nin the `postgresql:Client`, you can pass them without named parameters.\n\n```ballerina\npostgresql:Client|sql:Error dbClient2 = \n                                new (\"localhost\", \"postgres\", \"postgres\", \n                                     \"postgres\", 5432);\n```\n\nIn the sample below, the `postgresql:Client` uses named parameters to pass the attributes since it is skipping some parameters in the constructor.\nFurther, the [`postgresql:Options`](https://docs.central.ballerina.io/ballerinax/postgresql/latest#Options)\nproperty is passed to configure the connection timeout in the PostgreSQL client.\n\n```ballerina\npostgresql:Options postgresqlOptions = {\n  connectTimeout: 10\n};\npostgresql:Client|sql:Error dbClient = \n                                new (username = \"postgres\", password = \"postgres\", \n                                     database = \"test\", options = postgresqlOptions);\n```\n\nSimilarly in the sample below, the `postgresql:Client` uses named parameters and it provides an unshared connection pool of the type of\n[`sql:ConnectionPool`](https://docs.central.ballerina.io/ballerina/sql/latest#ConnectionPool)\nto be used within the client.\nFor more details about connection pooling, see the [`sql` library](https://docs.central.ballerina.io/ballerina/sql/latest).\n\n```ballerina\npostgresql:Client|sql:Error dbClient4 = \n                                new (username = \"postgres\", password = \"postgres\",\n                                     connectionPool = {maxOpenConnections: 5});\n```\n\n#### Using SSL\nTo connect to the PostgreSQL server using an SSL connection, you must add the SSL configurations to the `postgresql:Options` when creating the `postgresql:Client`.\nFor the SSL Mode, you can select one of the following modes: `postgresql:PREFERRED`, `postgresql:REQUIRED`, `postgresql:DISABLE`, or `postgresql:ALLOW`, `postgresql:VERIFY_CA`, or `postgresql:VERIFY_IDENTITY` according to the requirement.\nThe key files must be provided in the `.p12` format.\n\n```ballerina\nstring clientStorePath = \"/path/to/keystore.p12\";\n\npostgresql:Options postgresqlOptions = {\n    ssl: {\n        mode: postgresql:ALLOW,\n        key: {\n            path: clientStorePath,\n            password: \"ballerina\"\n        }\n    }\n};\n```\n#### Connection pool handling\n\nAll database libraries share the same connection pooling concept and there are three possible scenarios for\nconnection pool handling. For its properties and possible values, see the [`sql:ConnectionPool`](https://docs.central.ballerina.io/ballerina/sql/latest#ConnectionPool).\n\n\u003e**Note**: Connection pooling is used to optimize opening and closing connections to the database. However, the pool comes with an overhead. It is best to configure the connection pool properties as per the application need to get the best performance.\n\n1. Global, shareable, default connection pool\n\n   If you do not provide the `connectionPool` field when creating the database client, a globally-shareable pool will be\n   created for your database unless a connection pool matching with the properties you provided already exists.\n\n    ```ballerina\n    postgresql:Client|sql:Error dbClient = \n                                    new (username = \"postgres\", password = \"postgres\", \n                                         database = \"test\");\n    ```\n\n2. Client-owned, unsharable connection pool\n\n   If you define the `connectionPool` field inline when creating the client with the `sql:ConnectionPool` type,\n   an unsharable connection pool will be created.\n\n    ```ballerina\n    postgresql:Client|sql:Error dbClient = \n                                    new (username = \"postgres\", password = \"postgres\", \n                                         database = \"test\", \n                                         connectionPool = { maxOpenConnections: 5 });\n    ```\n\n3. Local, shareable connection pool\n\n   If you create a record of the `sql:ConnectionPool` type and reuse that in the configuration of multiple clients,\n   for each set of clients that connects to the same database instance with the same set of properties, a shared\n   connection pool will be used.\n\n    ```ballerina\n    sql:ConnectionPool connPool = {maxOpenConnections: 5};\n    \n    postgresql:Client|sql:Error dbClient1 =\n                                    new (username = \"postgres\", password = \"postgres\", \n                                    database = \"test\", connectionPool = connPool);\n    postgresql:Client|sql:Error dbClient2 = \n                                    new (username = \"postgres\", password = \"postgres\", \n                                    database = \"test\", connectionPool = connPool);\n    postgresql:Client|sql:Error dbClient3 = \n                                    new (username = \"postgres\", password = \"postgres\",\n                                    database = \"example\", connectionPool = connPool);\n    ```\n\nFor more details about each property, see the [`postgresql:Client`](https://docs.central.ballerina.io/ballerinax/postgresql/latest#Client).\n\nThe [`postgresql:Client`](https://docs.central.ballerina.io/ballerinax/postgresql/latest#Client) references\n[`sql:Client`](https://docs.central.ballerina.io/ballerina/sql/latest#Client) and all the operations\ndefined by the `sql:Client` will be supported by the `postgresql:Client` as well.\n\n#### Close the client\n\nOnce all the database operations are performed, you can close the client you have created by invoking the `close()`\noperation. This will close the corresponding connection pool if it is not shared by any other database clients.\n\n\u003e **Note**: The client must be closed only at the end of the application lifetime (or closed for graceful stops in a service).\n\n```ballerina\nerror? e = dbClient.close();\n```\nor\n```ballerina\ncheck dbClient.close();\n```\n\n### Database operations\n\nOnce the client is created, database operations can be executed through that client. This library defines the interface\nand common properties that are shared among multiple database clients. It also supports querying, inserting, deleting,\nupdating, and batch updating data.\n\n#### Parameterized query\n\nThe `sql:ParameterizedQuery` is used to construct the SQL query to be executed by the client.\nYou can create a query with constant or dynamic input data as follows.\n\n*Query with constant values*\n\n```ballerina\nsql:ParameterizedQuery query = `SELECT * FROM students \n                                WHERE id \u003c 10 AND age \u003e 12`;\n```\n\n*Query with dynamic values*\n\n```ballerina\nint[] ids = [10, 50];\nint age = 12;\nsql:ParameterizedQuery query = `SELECT * FROM students \n                                WHERE id \u003c ${ids[0]} AND age \u003e ${age}`;\n```\n\nMoreover, the SQL package has `sql:queryConcat()` and `sql:arrayFlattenQuery()` util functions which make it easier\nto create a dynamic/constant complex query.\n\nThe `sql:queryConcat()` is used to create a single parameterized query by concatenating a set of parameterized queries.\nThe sample below shows how to concatenate queries.\n\n```ballerina\nint id = 10;\nint age = 12;\nsql:ParameterizedQuery query = `SELECT * FROM students`;\nsql:ParameterizedQuery query1 = ` WHERE id \u003c ${id} AND age \u003e ${age}`;\nsql:ParameterizedQuery sqlQuery = sql:queryConcat(query, query1);\n```\n\nA query with the `IN` operator can be created using the `sql:ParameterizedQuery` as shown below. Here you need to flatten the array and pass each element separated by a comma.\n\n```ballerina\nint[] ids = [1, 2, 3];\nsql:ParameterizedQuery query = `SELECT count(*) as total FROM DataTable \n                                WHERE row_id IN (${ids[0]}, ${ids[1]}, ${ids[2]})`;\n```\n\nThe `sql:arrayFlattenQuery()` util function is used to make the array flattening easier. It makes the inclusion of varying array elements into the query easier by flattening the array to return a parameterized query. You can construct the complex dynamic query with the `IN` operator by using both functions as shown below.\n\n```ballerina\nint[] ids = [1, 2];\nsql:ParameterizedQuery sqlQuery = \n                         sql:queryConcat(`SELECT * FROM DataTable WHERE id IN (`, \n                                          sql:arrayFlattenQuery(ids), `)`);\n```\n\n#### Create tables\n\nThis sample creates a table with three columns. The first column is a primary key of type `int`\nwhile the second column is of type `int` and the other is of type `varchar`.\nThe `CREATE` statement is executed via the `execute` remote method of the client.\n\n```ballerina\n// Create the ‘Students’ table with the ‘id’, ’name’, and ’age’ fields.\nsql:ExecutionResult result = \n                check dbClient-\u003eexecute(`CREATE TABLE student (\n                                           id INT SERIAL,\n                                           age INT, \n                                           name VARCHAR(255), \n                                           PRIMARY KEY (id)\n                                         )`);\n// A value of the `sql:ExecutionResult` type is returned for the `result`. \n```\n\n#### Insert data\n\nThese samples show the data insertion by executing an `INSERT` statement using the `execute` remote method\nof the client.\n\nIn this sample, the query parameter values are passed directly into the query statement of the `execute`\nremote method.\n\n```ballerina\nsql:ExecutionResult result = check dbClient-\u003eexecute(`INSERT INTO student(age, name)\n                                                        VALUES (23, 'john')`);\n```\n\nIn this sample, the parameter values, which are assigned to local variables are used to parameterize the SQL query in\nthe `execute` remote method. This type of parameterized SQL query can be used with any primitive Ballerina type\nsuch as `string`, `int`, `float`, or `boolean` and in that case, the corresponding SQL type of the parameter is derived\nfrom the type of the Ballerina variable that is passed.\n\n```ballerina\nstring name = \"Anne\";\nint age = 8;\n\nsql:ParameterizedQuery query = `INSERT INTO student(age, name)\n                                  VALUES (${age}, ${name})`;\nsql:ExecutionResult result = check dbClient-\u003eexecute(query);\n```\n\nIn this sample, the parameter values are passed as an `sql:TypedValue` to the `execute` remote method. Use the\ncorresponding subtype of the `sql:TypedValue` such as `sql:VarcharValue`, `sql:CharValue`, `sql:IntegerValue`, etc., when you need to\nprovide more details such as the exact SQL type of the parameter.\n\n```ballerina\nsql:VarcharValue name = new (\"James\");\nsql:IntegerValue age = new (10);\n\nsql:ParameterizedQuery query = `INSERT INTO student(age, name)\n                                  VALUES (${age}, ${name})`;\nsql:ExecutionResult result = check dbClient-\u003eexecute(query);\n```\n\n#### Insert data with auto-generated keys\n\nThis sample demonstrates inserting data while returning the auto-generated keys. It achieves this by using the\n`execute` remote method to execute the `INSERT` statement.\n\n```ballerina\nint age = 31;\nstring name = \"Kate\";\n\nsql:ParameterizedQuery query = `INSERT INTO student(age, name)\n                                  VALUES (${age}, ${name})`;\nsql:ExecutionResult result = check dbClient-\u003eexecute(query);\n\n//Number of rows affected by the execution of the query.\nint? count = result.affectedRowCount;\n\n//The integer or string generated by the database in response to a query execution.\nstring|int? generatedKey = result.lastInsertId;\n```\n\n#### Query data\n\nThese samples show how to demonstrate the different usages of the `query` operation to query the\ndatabase table and obtain the results as a stream.\n\n\u003e**Note**: When processing the stream, make sure to consume all fetched data or close the stream.\n\nThis sample demonstrates querying data from a table in a database.\nFirst, a type is created to represent the returned result set. This record can be defined as an open or a closed record\naccording to the requirement. If an open record is defined, the returned stream type will include both defined fields\nin the record and additional database columns fetched by the SQL query which are not defined in the record.\nNote the mapping of the database column to the returned record's property is case-insensitive if it is defined in the\nrecord (i.e., the `ID` column in the result can be mapped to the `id` property in the record). Additional column names\nare added to the returned record as in the SQL query. If the record is defined as a closed record, only the fields defined in the\nrecord are returned or gives an error when additional columns are present in the SQL query. Next, the `SELECT` query is executed\nvia the `query` remote method of the client. Once the query is executed, each data record can be retrieved by iterating through\nthe result set. The `stream` returned by the `SELECT` operation holds a pointer to the actual data in the database, and it\nloads data from the table only when it is accessed. This stream can be iterated only once.\n\n```ballerina\n// Define an open record type to represent the results.\ntype Student record {\n    int id;\n    int age;\n    string name;\n};\n\n// Select the data from the database table. The query parameters are passed \n// directly. Similar to the `execute` samples, parameters can be passed as\n// sub types of `sql:TypedValue` as well.\nint id = 10;\nint age = 12;\nsql:ParameterizedQuery query = `SELECT * FROM students\n                                WHERE id \u003c ${id} AND age \u003e ${age}`;\nstream\u003cStudent, sql:Error?\u003e resultStream = dbClient-\u003equery(query);\n\n// Iterating the returned table.\ncheck from Student student in resultStream\n    do {\n       // Can perform operations using the `student` record of type `Student`.\n    };\n```\n\nDefining the return type is optional and you can query the database without providing the result type. Hence,\nthe above sample can be modified as follows with an open record type as the return type. The property name in the open record\ntype will be the same as how the column is defined in the database.\n\n```ballerina\n// Select the data from the database table. The query parameters are passed \n// directly. Similar to the `execute` samples, parameters can be passed as \n// sub types of `sql:TypedValue` as well.\nint id = 10;\nint age = 12;\nsql:ParameterizedQuery query = `SELECT * FROM students\n                                WHERE id \u003c ${id} AND age \u003e ${age}`;\nstream\u003crecord{}, sql:Error?\u003e resultStream = dbClient-\u003equery(query);\n\n// Iterating the returned table.\ncheck from record{} student in resultStream\n    do {\n        // Can perform operations using the `student` record.\n        io:println(\"Student name: \", student.value[\"name\"]);\n    };\n```\n\nThere are situations in which you may not want to iterate through the database and in that case, you may decide\nto use the `queryRow()` operation. If the provided return type is a record, this method returns only the first row\nretrieved by the query as a record.\n\n```ballerina\nint id = 10;\nsql:ParameterizedQuery query = `SELECT * FROM students WHERE id = ${id}`;\nStudent retrievedStudent = check dbClient-\u003equeryRow(query);\n```\n\nThe `queryRow()` operation can also be used to retrieve a single value from the database (e.g., when querying using\n`COUNT()` and other SQL aggregation functions). If the provided return type is not a record (i.e., a primitive data type)\n, this operation will return the value of the first column of the first row retrieved by the query.\n\n```ballerina\nint age = 12;\nsql:ParameterizedQuery query = `SELECT COUNT(*) FROM students WHERE age \u003c ${age}`;\nint youngStudents = check dbClient-\u003equeryRow(query);\n```\n\n#### Update data\n\nThis sample demonstrates modifying data by executing an `UPDATE` statement via the `execute` remote method of\nthe client.\n\n```ballerina\nint age = 23;\nsql:ParameterizedQuery query = `UPDATE students SET name = 'John' WHERE age = ${age}`;\nsql:ExecutionResult result = check dbClient-\u003eexecute(query);\n```\n\n#### Delete data\n\nThis sample demonstrates deleting data by executing a `DELETE` statement via the `execute` remote method of\nthe client.\n\n```ballerina\nstring name = \"John\";\nsql:ParameterizedQuery query = `DELETE from students WHERE name = ${name}`;\nsql:ExecutionResult result = check dbClient-\u003eexecute(query);\n```\n\n#### Batch update data\n\nThis sample demonstrates how to insert multiple records with a single `INSERT` statement that is executed via the\n`batchExecute` remote method of the client. This is done by creating a `table` with multiple records and\nparameterized SQL query as same as the above `execute` operations.\n\n```ballerina\n// Create the table with the records that need to be inserted.\nvar data = [\n  { name: \"John\", age: 25 },\n  { name: \"Peter\", age: 24 },\n  { name: \"jane\", age: 22 }\n];\n\n// Do the batch update by passing the batches.\nsql:ParameterizedQuery[] batch = from var row in data\n                                 select `INSERT INTO students ('name', 'age')\n                                           VALUES (${row.name}, ${row.age})`;\nsql:ExecutionResult[] result = check dbClient-\u003ebatchExecute(batch);\n```\n\n#### Execute stored procedures\n\nThis sample demonstrates how to execute a stored procedure with a single `INSERT` statement that is executed via the\n`call` remote method of the client.\n\n```ballerina\nint uid = 10;\nsql:IntegerOutParameter insertId = new;\n\nsql:ProcedureCallResult result = \n                         check dbClient-\u003ecall(`call InsertPerson(${uid}, ${insertId})`);\nstream\u003crecord{}, sql:Error?\u003e? resultStr = result.queryResult;\nif resultStr is stream\u003crecord{}, sql:Error?\u003e {\n    check from record{} result in resultStr\n        do {\n            // Can perform operations using the `result` record.\n        };\n}\ncheck result.close();\n```\n\u003e**Note**: Once the results are processed, the `close` method on the `sql:ProcedureCallResult` must be called.\n\n\u003e**Note**: The default thread pool size used in Ballerina is: `the number of processors available * 2`. You can configure the thread pool size by using the `BALLERINA_MAX_POOL_SIZE` environment variable.\n\n### Change Data Capture Listener\n\nTo listen for change data capture (CDC) events from a Postgres database, you must create a [`postgresql:CdcListener`](https://docs.central.ballerina.io/ballerinax/postgresql/latest#CdcListener) object. The listener allows your Ballerina application to react to changes (such as inserts, updates, and deletes) in real time.\n\n#### Create a listener\n\nYou can create a CDC listener by specifying the required configurations such as host, port, username, password, and database name. Additional options can be provided using the [`cdc:Options`](https://docs.central.ballerina.io/ballerinax/cdc/latest#Options) record.\n\n```ballerina\nlistener postgresql:CdcListener cdcListener = new (database = {\n    username: \u003cusername\u003e,\n    password: \u003cpassword\u003e\n});\n```\n\n#### Implement a service to handle CDC events\n\nYou can attach a service to the listener to handle CDC events. The service can define remote methods for different event types such as `onRead`, `onCreate`, `onUpdate`, and `onDelete`.\n\n```ballerina\nservice on cdcListener {\n    remote function onRead(record{} after) returns cdc:Error? {\n        io:println(\"Insert event: \", after);\n    }\n\n    remote function onCreate(record{} after) returns cdc:Error? {\n        io:println(\"Insert event: \", after);\n    }\n\n    remote function onUpdate(record{} before, record{} after) returns cdc:Error? {\n        io:println(\"Update event - Before: \", before, \" After: \", after);\n    }\n\n    remote function onDelete(record{} before) returns error? {\n        io:println(\"Delete event: \", before);\n    }\n}\n```\n\n## Issues and projects \n\nIssues and Projects tabs are disabled for this repository as this is part of the Ballerina Standard Library. To report bugs, request new features, start new discussions, view project boards, etc, visit the Ballerina Standard Library [parent repository](https://github.com/ballerina-platform/ballerina-standard-library). \n\nThis repository only contains the source code for the package.\n\n## Building from the source\n\n### Set up the prerequisites\n\n1. Download and install Java SE Development Kit (JDK) version 11 (from one of the following locations).\n   * [Oracle](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html)\n   * [OpenJDK](https://adoptium.net/)\n\n2. Download and install [Docker](https://www.docker.com/get-started).\n   \n3. Export your Github Personal access token with the read package permissions as follows.\n        \n        export packageUser=\u003cUsername\u003e\n        export packagePAT=\u003cPersonal access token\u003e\n\n### Building the source\n\nExecute the commands below to build from the source.\n\n1. To build the library:\n\n        ./gradlew clean build\n        \n2. To run the integration tests:\n\n        ./gradlew clean test\n\n3. To build the package without tests:\n\n        ./gradlew clean build -x test\n\n4. To run only specific tests:\n\n        ./gradlew clean build -Pgroups=\u003cComma separated groups/test cases\u003e\n\n   **Tip**: The following groups of test cases are available.\n\n   Groups | Test Cases\n   ---| ---\n   connection | connection-init\n   pool | pool\n   execute | execute-basic \u003cbr\u003e execute-params\n   batch-execute | batch-execute \n   query | query\u003cbr\u003equery-simple-params\n   procedures | procedures\n   functions | functions\n\n5. To disable some specific groups during the test:\n\n        ./gradlew clean build -Pdisable-groups=\u003cComma separated groups/test cases\u003e\n\n6. To debug the tests:\n\n        ./gradlew clean build -Pdebug=\u003cport\u003e\n\n7. To debug the package with the Ballerina language:\n\n        ./gradlew clean build -PbalJavaDebug=\u003cport\u003e   \n\n8. Publish ZIP artifact to the local `.m2` repository:\n   ```\n   ./gradlew clean build publishToMavenLocal\n   ```\n9. Publish the generated artifacts to the local Ballerina central repository:\n   ```\n   ./gradlew clean build -PpublishToLocalCentral=true\n   ```\n\n## Contribute to Ballerina\n\nAs an open source project, Ballerina welcomes contributions from the community. \n\nFor more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md).\n\n## Code of conduct\n\nAll contributors are encouraged to read the [Ballerina Code of Conduct](https://ballerina.io/code-of-conduct).\n\n## Useful links\n\n* For more information go to the [`postgresql` library](https://lib.ballerina.io/ballerinax/postgresql/latest).\n* For example demonstrations of the usage, go to [Ballerina By Examples](https://ballerina.io/learn/by-example/#database-access).\n* Chat live with us via our [Discord server](https://discord.gg/ballerinalang).\n* Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fballerina-platform%2Fmodule-ballerinax-postgresql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fballerina-platform%2Fmodule-ballerinax-postgresql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fballerina-platform%2Fmodule-ballerinax-postgresql/lists"}