### Example SQL with pg_hint_plan and GUC Settings Source: https://docs.ent-framework.net/advanced/query-planner-hints This is an example of the SQL query that Ent Framework generates when using the raw prepend hint with 'pg_hint_plan' and other GUC settings. It shows the custom hint, temporary GUC settings, the actual SELECT statement, and the subsequent RESET commands. This structure ensures a single transaction and round-trip to the server. ```sql /*+IndexScan(comments comments_created_at_idx)*/ SET LOCAL search_path TO sh0123; SET LOCAL work_mem TO 10MB; SET LOCAL statement_timeout TO 20s; SELECT ... FROM comments WHERE topic_id=? ORDER BY created_at DESC LIMIT 100; RESET statement_timeout; RESET work_mem; SELECT pg_last_wal_replay_lsn(); ``` -------------------------------- ### Querying Debug Views Example (SQL) Source: https://docs.ent-framework.net/scalability/shards-rebalancing-and-pg-microsharding-tool An example `psql` session demonstrating how to query a debug view (`users`) to retrieve data from all microshards, including those on remote PostgreSQL nodes. This query is for debugging purposes only. ```sql $ psql postgres=# SELECT shard, email FROM users WHERE created_at > now() - '1 hour'::interval; -- Prints all recent users from all microshards, including -- the microshards on other PosgreSQL nodes! Use for -- debugging purposes only. ``` -------------------------------- ### Example Migration File List (Happy Path) Source: https://docs.ent-framework.net/advanced/database-schema-migrations Illustrates a typical scenario where new migration version files are appended chronologically to an existing list, leading to a smooth application process by the pg-mig tool. ```shell 20231017204837.do-something.sh 20241201204837.change-other-thing.sh 20241202001000.and-one-more-thing.sh ``` ```shell 20241202002000.their-thing.sh.up.sql ``` ```shell 20231017204837.do-something.sh.up.sql 20241201204837.change-other-thing.sh.up.sql 20241202001000.and-one-more-thing.sh.up.sql 20241202002000.their-thing.sh.up.sql <-- new version pulled ``` -------------------------------- ### Install Microshard Schema - pg-microsharding CLI Source: https://docs.ent-framework.net/scalability/shards-rebalancing-and-pg-microsharding-tool Command to install a new microshard schema using the pg-microsharding CLI. It allows specifying the schema name format and connection details (DSN) for the PostgreSQL server(s). ```bash pg-microsharding install [--schema-name-fmt=SCHEMA_NAME_FMT] [--dsn=DSN | --dsns=DNS1,DSN2,...] ``` -------------------------------- ### Basic Ent Select Call with Custom PostgreSQL Options Source: https://docs.ent-framework.net/advanced/postgresql-specific-features Demonstrates a basic select call in TypeScript using the Ent Framework, passing custom options for PostgreSQL-specific features. This example shows the initial setup before detailing the custom object structure. ```typescript const comments = await EntComment.select( vc, { creator_id: "101" }, 20, undefined, // order custom, // untyped, but of type SelectInputCustom ); ``` -------------------------------- ### Batching load() Calls with Ent Framework Source: https://docs.ent-framework.net/getting-started/automatic-batching-examples Demonstrates how multiple EntTopic.loadX() calls within a Promise.all() block are automatically batched into a single SQL query. This reduces the number of database round trips for read operations. ```typescript await Promise.all([ EntTopic.loadX(vc, "123"), EntTopic.loadX(vc, "456"), EntTopic.loadX(vc, "789"), ]); ``` -------------------------------- ### Optimized Comment Loading with Helper Methods (TypeScript) Source: https://docs.ent-framework.net/getting-started/n%2B1-selects-solution This TypeScript example shows how to add helper methods like `topic()` and `creator()` to Ent classes to simplify data loading. These methods, when used with `mapJoin`, still leverage Ent Framework's automatic batching for efficient database interaction. ```typescript class EntComment extends ... { async topic() { return EntTopic.loadX(this.vc, this.topic_id); } async creator() { return EntUser.loadX(this.vc, this.creator_id); } } class EntTopic extends ... { async creator() { return EntUser.loadX(this.vc, this.creator_id); } } app.get("/comments", async (req, res) => { const commentIDs = String(req.query.ids).split(","); res.json( await mapJoin(commentIDs, async (commentID) => { const comment = await EntComment.loadX(req.vc, commentID); const topic = await comment.topic(); const [commentCreator, topicCreator] = await Promise.all([ comment.creator(), topic.creator(), ]); return { comment, commentCreator, topic, topicCreator }; }) ); }); ``` -------------------------------- ### pg-microsharding Configuration File Setup Source: https://docs.ent-framework.net/scalability/shards-rebalancing-and-pg-microsharding-tool Defines how to export configuration values from a `pg-microsharding.config.ts` file, providing an alternative to environment variables. It derives connection details from the Ent Framework cluster configuration. ```javascript import { cluster } from "ents/cluster"; export default async function(action: "apply" | "undo" | string) { const islands = cluster.options.islands(); return { PGDSNS: islands .map((island) => island.nodes.map(({ host }) => host) .flat() .join(","), PGPORT: 5432, // we don't want to use pgbouncer port here PGUSER: firstNode.user, PGPASSWORD: firstNode.password, PGDATABASE: firstNode.database, PGSSLMODE: firstNode.ssl ? "prefer" : undefined, MIGRATE_CMD: "yarn -s pg-mig", }; } ``` -------------------------------- ### Get Shard Client using cluster.shardByNo() Source: https://docs.ent-framework.net/scalability/sharding-low-level-api Illustrates how to obtain a `Shard` instance by its number using `cluster.shardByNo()` and then acquire a PostgreSQL client (`pgClient`) for either the master or a replica using `shard.client()`. It also shows how to use a `Timeline` object for automatic replication lag tracking. ```typescript import { MASTER } from "ent-framework"; const shard = cluster.shardByNo(42); const pgClient = await shard.client(MASTER); // Using Timeline for replication lag tracking const timeline = vc.timeline(shard, "users"); const pgClientWithTimeline = await shard.client(timeline); ``` -------------------------------- ### SQL Table Schema for Topics with Tags Source: https://docs.ent-framework.net/advanced/loaders-and-custom-batching Defines the 'topics' table schema in PostgreSQL, including an array of text for tags and a GIN index for efficient searching on this array field. This schema is crucial for the subsequent data retrieval examples. ```sql CREATE TABLE topics( id bigserial PRIMARY KEY, tags text[] NOT NULL DEFAULT '{}', slug varchar(64) NOT NULL UNIQUE, creator_id bigint NOT NULL, subject text DEFAULT NULL ); CREATE INDEX topics_tags ON topics USING gin(tags); ``` -------------------------------- ### Batching insertReturning() Calls with Ent Framework Source: https://docs.ent-framework.net/getting-started/automatic-batching-examples Shows how multiple EntTopic.insertReturning() calls, even when nested within functions, are batched. It explains that while inserting and then loading data results in two SQL queries (INSERT and SELECT), the framework batches these operations efficiently. ```typescript await Promise.all([ EntTopic.insertReturning(vc, { ... }), EntTopic.insertReturning(vc, { ... }), EntTopic.insertReturning(vc, { ... }), ]); ``` ```typescript async function insertTopicsBatch(n: number) { await mapJoin(range(n), async (i) => EntTopic.insertReturning(vc, { ... })); } ... await Promise.all([ insertTopicsBatch(42), insertTopicsBatch(101), ]); ``` -------------------------------- ### Example Migration File List (Explicit Conflict) Source: https://docs.ent-framework.net/advanced/database-schema-migrations Demonstrates an explicit merge conflict where a new migration version file is introduced in the middle of the existing chronological order, causing the pg-mig tool to refuse execution and providing a specific error message. ```shell 20231017204837.do-something.sh 20241201204837.change-other-thing.sh 20241202001000.and-one-more-thing.sh <-- you work on this ``` ```shell 20231017204837.do-something.sh.up.sql 20241201204837.change-other-thing.sh.up.sql 20241202000000.middle-thing.sh.up.sql <-- new version pulled 20241202001000.and-one-more-thing.sh.up.sql ``` -------------------------------- ### Use a Custom Loader for Batched Topic Retrieval in TypeScript Source: https://docs.ent-framework.net/advanced/loaders-and-custom-batching This TypeScript example illustrates how to utilize a custom `TopicSimpleLoader` within the Ent Framework. It defines a `getTopic` function that leverages the loader and shows how multiple calls to `getTopic` within `mapJoin` are batched into a single database query for efficiency. ```typescript async function getTopic(vc: VC, id: string) { const topic = await vc.loader(TopicSimpleLoader).load(id); return topic; } ... // The following calls will be batched into 1 SELECT query. await mapJoin([id1, id2, ...], async (id) => getTopic(vc, id)); ``` -------------------------------- ### Install PostgreSQL Stored Functions: pg-microsharding install Source: https://docs.ent-framework.net/scalability/shards-rebalancing-and-pg-microsharding-tool Installs or upgrades the pg-microsharding stored functions into your PostgreSQL database. This can be done manually via the CLI or by including specific SQL files in your database migrations. ```APIDOC ## pg-microsharding install ### Description Installs the pg-microsharding stored functions into the PostgreSQL database. This can be performed using the CLI command or by executing the provided SQL migration files. ### Method CLI Command / SQL Execution ### Endpoint N/A (CLI Tool / SQL Script) ### Parameters #### CLI Arguments - **install** - Command to initiate the installation. #### SQL Files - **sql/pg-microsharding-up.sql**: Script to install or upgrade the library. - **sql/pg-microsharding-down.sql**: Script to uninstall the library. ### Request Example #### CLI ```bash pg-microsharding install ``` #### SQL Migration (Up) ```sql -- mig/20250628100000.add-pg-microsharding.public.up.sql CREATE SCHEMA microsharding; SET search_path TO microsharding; \ir ../pg-microsharding/sql/pg-microsharding-up.sql ``` ### Response #### Success Response (Database operations complete without errors) #### Response Example (No specific JSON response for CLI commands or SQL execution in this context) ``` -------------------------------- ### Show Cluster Layout with pg-microsharding list Source: https://docs.ent-framework.net/scalability/shards-rebalancing-and-pg-microsharding-tool Demonstrates the command-line usage for listing the cluster layout of pg-microsharding. It shows the basic command and mentions options like `--json` for JSON output and `--verbose` for detailed statistics. ```bash pg-microsharding list ``` -------------------------------- ### Install pg-microsharding Stored Functions API Source: https://docs.ent-framework.net/scalability/shards-rebalancing-and-pg-microsharding-tool Installs or upgrades the pg-microsharding library's stored functions into a PostgreSQL database. This can be done via a command-line action or by executing provided SQL scripts for up and down migrations. It supports installing into a dedicated schema or the 'public' schema. ```bash pg-microsharding install ``` ```sql -- mig/20250628100000.add-pg-microsharding.public.up.sql CREATE SCHEMA microsharding; SET search_path TO microsharding; \ir ../pg-microsharding/sql/pg-microsharding-up.sql ``` ```sql -- mig/20250628100000.add-pg-microsharding.public.dn.sql SET search_path TO microsharding; \ir ../pg-microsharding/sql/pg-microsharding-down.sql DROP SCHEMA microsharding; ``` -------------------------------- ### pg-mig Command Line Usage Source: https://docs.ent-framework.net/advanced/database-schema-migrations Demonstrates the command-line interface for the pg-mig tool, outlining various options for database migration management. These options include specifying migration directories, host configurations, user credentials, database names, and controlling migration behavior like undoing, creating, listing, and parallel execution. ```bash pg-mig [--migdir=path/to/my-migrations/directory] [--hosts=host1,host2,...] [--hosts=host[:port][/db],...] [--hosts=postgres://[user][:password][@]host[:port][/db],...] [--port=5432] [--user=user-that-can-apply-ddl] [--pass=password] [--db=my-database-name] [--createdb] [--undo=20191107201239.my-migration-name.sh] [--make=my-migration-name@sh] [--list | --list=digest] [--parallelism=8] [--dry] ``` -------------------------------- ### Configure Ent Framework Cluster with Custom Pool Source: https://docs.ent-framework.net/scalability/sharding-low-level-api Demonstrates how to initialize the Ent Framework `Cluster` with custom `islands`, `createClient` configuration (including substituting the default node-postgres Pool with a custom `pg.Pool` instance), and a `ShardNamer`. ```typescript import pg from "pg"; export const cluster = new Cluster({ islands: async () => [ { no: 0, nodes: [ { name: "abc-writer-1", config: { host: "...", ... } }, { name: "abc-reader-2", config: { host: "...", ... } }, ], }, { no: 1, nodes: [ { name: "abc-writer-3", config: { host: "...", ... } }, { name: "abc-reader-4", config: { host: "...", ... } }, ], }, ], createClient: (node) => new PgClient({ ...node, createPool: (config) => new pg.Pool(config), } satisfies PgClientOptions), shardNamer: new ShardNamer({ nameFormat: "sh%04d", discoverQuery: "SELECT unnest FROM unnest(microsharding.microsharding_list_active_shards())", }), ..., }); ``` -------------------------------- ### UUID v4 Generation Example Source: https://docs.ent-framework.net/scalability/locating-a-shard-id-format Provides an example of a UUID v4 format generated by the `id_gen_uuid()` function. The format includes environment and microshard information at the beginning, followed by randomly generated digits. This function is useful for primary keys when UUID format is desired. ```text 10246xxx-xxxx-4xxx-Nxxx-xxxxxxxxxxxx ``` -------------------------------- ### Create Database Tables (SQL) Source: https://docs.ent-framework.net/getting-started/connect-to-a-database This SQL script defines the schema for tables used in the Ent Framework, including 'users', 'topics', 'comments', 'organizations', and 'organization_users'. These tables store application data such as user information, discussion topics, comments, and organization details. ```sql CREATE TABLE users( id bigserial PRIMARY KEY, email varchar(256) NOT NULL UNIQUE, is_admin boolean NOT NULL DEFAULT FALSE ); CREATE TABLE topics( id bigserial PRIMARY KEY, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, slug varchar(64) NOT NULL UNIQUE, creator_id bigint NOT NULL, subject text DEFAULT NULL ); CREATE TABLE comments( id bigserial PRIMARY KEY, created_at timestamptz NOT NULL, topic_id bigint REFERENCES topics, creator_id bigint NOT NULL, message text NOT NULL ); CREATE TABLE organizations( id bigserial PRIMARY KEY, name text NOT NULL UNIQUE ); CREATE TABLE organization_users( id bigserial PRIMARY KEY, organization_id bigint REFERENCES organizations, user_id bigint REFERENCES users, UNIQUE (organization_id, user_id) ); ``` -------------------------------- ### afterInsert Trigger Example Source: https://docs.ent-framework.net/getting-started/triggers This trigger executes after a successful insert operation. It can be used for auxiliary tasks. However, failures in this trigger do not roll back the database operation. ```typescript afterInsert: [ async (vc, { input }) => { ... }, ], ``` -------------------------------- ### Create and Use VC Principal for Loading Ents Source: https://docs.ent-framework.net/advanced/vc-flavors Demonstrates the initial creation of a guest VC, loading an EntUser with specific criteria, and subsequently using the VC to load other Ents like EntTopic and EntComment. It highlights that Ents carry the VC used for their loading, with potential downgrading based on privacy configurations. ```typescript const guestVC = VC.createGuestPleaseDoNotUseCreationPointsMustBeLimited(); const user = await EntUser.loadX(guestVC.toOmniDangerous(), { email: session.user.email, }); vc = user.vc; const user = await EntUser.loadX(vc, vc.principal); const topic = await EntTopic.loadX(user.vc, topicID); const comments = await EntComment.select(topic.vc, ...); ``` -------------------------------- ### beforeUpdate Trigger Example in TypeScript Source: https://docs.ent-framework.net/getting-started/triggers Demonstrates a beforeUpdate trigger in TypeScript. It adds an entry to Kafka and updates a slug if the subject changes, ensuring the slug is unique. ```typescript beforeUpdate: [ async (vc, { oldRow, input, newRow }) => { await addToKafka(this.name, newRow.id); if (newRow.subject !== oldRow.subject) { // Notice that newRow.subject is a non-optional // string property, whilst input.slug is optional // (i.e. string | undefined). let slug = slugufy(newRow.subject); if (await EntTopic.exists(vc, { slug })) { slug += `-${Date.now()}`; } input.slug = slug; } }, ], ... await topic.updateReturningX({ subject: "Hello" }); ``` -------------------------------- ### Ent Framework Data Insertion Example Source: https://docs.ent-framework.net/advanced/custom-field-refactoring Illustrates how to insert data into an Ent Topic, specifically for the 'actors' field, using the `ActorsV1` format. ```typescript const topic = await EntTopic.insertReturning(vc, { ..., actors: { editor_ids: ["42"], viewer_ids: [] }, }); ``` -------------------------------- ### Create New Migration File with pg-mig Source: https://docs.ent-framework.net/advanced/database-schema-migrations Command to create a new pair of empty migration files (.up.sql and .dn.sql) with a specified name and schema prefix using pg-mig. ```shell pg-mig --make=my-migration-name@sh ``` -------------------------------- ### afterMutation Trigger Example Source: https://docs.ent-framework.net/getting-started/triggers This trigger executes after any successful mutation (insert, update, or delete). It receives the operation type and the affected row, but not the input object. Failures here are not transactional. ```typescript afterMutation: [ async (vc, { op, newOrOldRow }) => { ... }, ], ``` -------------------------------- ### Define Initial Schema in SQL Source: https://docs.ent-framework.net/advanced/database-schema-migrations These SQL snippets define the structure for an initial database migration. The 'up' file contains `CREATE TABLE` statements, while the 'dn' file contains the corresponding `DROP TABLE` statement for rollback. These files are intended to be edited and applied by pg-mig. ```sql -- 20251203493744.initial.public.up.sql CREATE TABLE users( id bigserial PRIMARY KEY, email varchar(256) NOT NULL ); ``` ```sql -- 20251203493744.initial.public.dn.sql DROP TABLE users; ``` -------------------------------- ### afterUpdate Trigger Example Source: https://docs.ent-framework.net/getting-started/triggers This trigger executes after a successful update operation. It receives the old and new row data but not the input object. Failures here do not affect the database transaction. ```typescript afterUpdate: [ async (vc, { oldRow, newRow }) => { ... }, ], ``` -------------------------------- ### SQL Expressions: ANY and IN Builders Source: https://docs.ent-framework.net/architecture/jit-in-sql-queries-batching Demonstrates utility methods for constructing SQL expressions like ANY('{values}') and IN('values'). These are part of PgRunner and help in dynamically building SQL queries based on input data. ```typescript createAnyBuilder() { return (vals: string[]) => `ANY('{${vals.join(',')}}')`; } createInBuilder() { return (vals: string[]) => `IN('${vals.join("', '")}')`; } ``` -------------------------------- ### Next.js Server Component for User Welcome Message Source: https://docs.ent-framework.net/getting-started/vc-viewer-context-and-principal This Next.js server component fetches the user's session using `getServerSession()`. If a session exists, it displays a welcome message with the user's name; otherwise, it prompts the user to sign in. It relies on the next-auth library for session management. ```typescript import { getServerSession } from "next-auth"; export default async function Home() { const session = await getServerSession(); return session ? (