@huluwz/pg-ethiopian-calendar 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # @huluwz/pg-ethiopian-calendar
2
+
3
+ Ethiopian calendar functions for PostgreSQL. Works on any PostgreSQL including managed services (Neon, Supabase, Railway, AWS RDS).
4
+
5
+ [![npm](https://img.shields.io/npm/v/@huluwz/pg-ethiopian-calendar)](https://www.npmjs.com/package/@huluwz/pg-ethiopian-calendar)
6
+ [![License](https://img.shields.io/badge/license-PostgreSQL-blue)](LICENSE)
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @huluwz/pg-ethiopian-calendar
12
+ ```
13
+
14
+ ## Quick Start
15
+
16
+ ```bash
17
+ # Generate migration (auto-detects ORM)
18
+ npx ethiopian-calendar init
19
+
20
+ # Or specify ORM
21
+ npx ethiopian-calendar init prisma
22
+ npx ethiopian-calendar init drizzle
23
+ npx ethiopian-calendar init typeorm
24
+ ```
25
+
26
+ Then run your ORM's migration command.
27
+
28
+ ## SQL Functions
29
+
30
+ ```sql
31
+ -- Current Ethiopian date (two ways)
32
+ SELECT to_ethiopian_date(); -- '2018-04-23'
33
+ SELECT to_ethiopian_date(NOW()); -- same
34
+
35
+ -- Specific date
36
+ SELECT to_ethiopian_date('2024-01-01'::timestamp); -- '2016-04-23'
37
+
38
+ -- Ethiopian → Gregorian
39
+ SELECT from_ethiopian_date('2016-04-23'); -- '2024-01-01 00:00:00'
40
+
41
+ -- Current Ethiopian timestamp (with time)
42
+ SELECT to_ethiopian_timestamp(); -- '2018-04-23 14:30:00'
43
+
44
+ -- Check version
45
+ SELECT ethiopian_calendar_version(); -- '1.1.0'
46
+ ```
47
+
48
+ ## Generated Columns
49
+
50
+ ```sql
51
+ CREATE TABLE orders (
52
+ id SERIAL PRIMARY KEY,
53
+ created_at TIMESTAMP DEFAULT NOW(),
54
+ created_at_ethiopian TIMESTAMP GENERATED ALWAYS AS
55
+ (to_ethiopian_timestamp(created_at)) STORED
56
+ );
57
+ ```
58
+
59
+ ## With Prisma
60
+
61
+ ```typescript
62
+ const order = await prisma.order.create({
63
+ data: { name: 'Test' }
64
+ });
65
+ console.log(order.createdAtEthiopian); // auto-populated
66
+ ```
67
+
68
+ ## With Drizzle
69
+
70
+ ```typescript
71
+ import { sql } from 'drizzle-orm';
72
+
73
+ export const orders = pgTable('orders', {
74
+ id: serial('id').primaryKey(),
75
+ createdAt: timestamp('created_at').defaultNow(),
76
+ createdAtEthiopian: timestamp('created_at_ethiopian')
77
+ .generatedAlwaysAs(sql`to_ethiopian_timestamp(created_at)`),
78
+ });
79
+ ```
80
+
81
+ ## API
82
+
83
+ ```typescript
84
+ import { getSql, VERSION, detectOrm } from '@huluwz/pg-ethiopian-calendar';
85
+
86
+ getSql(); // Full SQL content
87
+ detectOrm(); // Auto-detect installed ORM
88
+ VERSION; // '1.1.0'
89
+ ```
90
+
91
+ ## Supported ORMs
92
+
93
+ - Prisma
94
+ - Drizzle
95
+ - TypeORM
96
+ - Raw SQL
97
+
98
+ ## Links
99
+
100
+ - [GitHub](https://github.com/HuluWZ/pg-ethiopian-calendar)
101
+ - [Documentation](https://github.com/HuluWZ/pg-ethiopian-calendar#readme)
102
+
103
+ ## License
104
+
105
+ PostgreSQL License
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI for Ethiopian Calendar PostgreSQL migrations
4
+ * @example npx ethiopian-calendar init prisma
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":";AACA;;;GAGG"}
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * CLI for Ethiopian Calendar PostgreSQL migrations
5
+ * @example npx ethiopian-calendar init prisma
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ const fs_1 = require("fs");
9
+ const path_1 = require("path");
10
+ const index_1 = require("../index");
11
+ const fmt = {
12
+ reset: "\x1b[0m",
13
+ bold: "\x1b[1m",
14
+ red: "\x1b[31m",
15
+ green: "\x1b[32m",
16
+ yellow: "\x1b[33m",
17
+ blue: "\x1b[34m",
18
+ cyan: "\x1b[36m",
19
+ };
20
+ const log = console.log;
21
+ const print = {
22
+ info: (msg) => log(`${fmt.blue}ℹ${fmt.reset} ${msg}`),
23
+ success: (msg) => log(`${fmt.green}✔${fmt.reset} ${msg}`),
24
+ error: (msg) => log(`${fmt.red}✖${fmt.reset} ${msg}`),
25
+ };
26
+ const DROP_FUNCTIONS_SQL = `
27
+ DROP FUNCTION IF EXISTS pg_ethiopian_to_datetime(timestamp);
28
+ DROP FUNCTION IF EXISTS pg_ethiopian_to_timestamp(timestamp);
29
+ DROP FUNCTION IF EXISTS pg_ethiopian_from_date(text);
30
+ DROP FUNCTION IF EXISTS pg_ethiopian_to_date(timestamp);
31
+ DROP FUNCTION IF EXISTS ethiopian_calendar_version();
32
+ DROP FUNCTION IF EXISTS current_ethiopian_date();
33
+ DROP FUNCTION IF EXISTS to_ethiopian_datetime(timestamp);
34
+ DROP FUNCTION IF EXISTS to_ethiopian_timestamp();
35
+ DROP FUNCTION IF EXISTS to_ethiopian_timestamp(timestamp);
36
+ DROP FUNCTION IF EXISTS from_ethiopian_date(text);
37
+ DROP FUNCTION IF EXISTS to_ethiopian_date();
38
+ DROP FUNCTION IF EXISTS to_ethiopian_date(timestamp);
39
+ DROP FUNCTION IF EXISTS _ethiopian_to_jdn(integer, integer, integer);
40
+ DROP FUNCTION IF EXISTS _jdn_to_ethiopian(integer);
41
+ DROP FUNCTION IF EXISTS _jdn_to_gregorian(integer);
42
+ DROP FUNCTION IF EXISTS _gregorian_to_jdn(integer, integer, integer);
43
+ `.trim();
44
+ function generateTypeOrmMigration(sql) {
45
+ const className = `EthiopianCalendar${Date.now()}`;
46
+ return `import { MigrationInterface, QueryRunner } from "typeorm";
47
+
48
+ export class ${className} implements MigrationInterface {
49
+ async up(queryRunner: QueryRunner): Promise<void> {
50
+ await queryRunner.query(\`${sql.replace(/`/g, "\\`")}\`);
51
+ }
52
+
53
+ async down(queryRunner: QueryRunner): Promise<void> {
54
+ await queryRunner.query(\`${DROP_FUNCTIONS_SQL}\`);
55
+ }
56
+ }
57
+ `;
58
+ }
59
+ function writeMigration(orm, outputPath) {
60
+ const dir = (0, path_1.dirname)(outputPath);
61
+ if (!(0, fs_1.existsSync)(dir)) {
62
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
63
+ }
64
+ const sql = (0, index_1.getSql)();
65
+ const content = orm === "typeorm" ? generateTypeOrmMigration(sql) : sql;
66
+ (0, fs_1.writeFileSync)(outputPath, content);
67
+ }
68
+ const VALID_ORMS = ["prisma", "drizzle", "typeorm", "raw"];
69
+ const NEXT_STEPS = {
70
+ prisma: ["npx prisma migrate dev"],
71
+ drizzle: ["npx drizzle-kit migrate"],
72
+ typeorm: ["npx typeorm migration:run -d src/data-source.ts"],
73
+ raw: ["psql -d DATABASE -f ethiopian_calendar.sql"],
74
+ };
75
+ function showHelp() {
76
+ log(`
77
+ ${fmt.cyan}${fmt.bold}Ethiopian Calendar for PostgreSQL${fmt.reset} ${fmt.yellow}v${index_1.VERSION}${fmt.reset}
78
+
79
+ ${fmt.bold}Usage:${fmt.reset}
80
+ npx ethiopian-calendar init [orm]
81
+ npx ethiopian-calendar version
82
+ npx ethiopian-calendar migrations
83
+
84
+ ${fmt.bold}ORMs:${fmt.reset}
85
+ prisma, drizzle, typeorm, raw
86
+
87
+ ${fmt.bold}Examples:${fmt.reset}
88
+ npx ethiopian-calendar init ${fmt.cyan}# auto-detect${fmt.reset}
89
+ npx ethiopian-calendar init prisma
90
+ `);
91
+ }
92
+ function showVersion() {
93
+ log(`${fmt.bold}v${index_1.VERSION}${fmt.reset}`);
94
+ log(`\nCheck database: ${fmt.cyan}SELECT ethiopian_calendar_version();${fmt.reset}\n`);
95
+ }
96
+ function showMigrations() {
97
+ const migrations = (0, index_1.listMigrations)();
98
+ log(`\n${fmt.bold}Available Upgrades:${fmt.reset}`);
99
+ if (migrations.length === 0) {
100
+ log(" None\n");
101
+ }
102
+ else {
103
+ migrations.forEach((m) => log(` ${m.from} → ${m.to}`));
104
+ log("");
105
+ }
106
+ }
107
+ function initMigration(ormArg) {
108
+ let orm;
109
+ if (ormArg) {
110
+ if (!VALID_ORMS.includes(ormArg)) {
111
+ print.error(`Unknown ORM: ${ormArg}`);
112
+ log(`\nSupported: ${VALID_ORMS.join(", ")}\n`);
113
+ process.exit(1);
114
+ }
115
+ orm = ormArg;
116
+ print.info(`Using: ${orm}`);
117
+ }
118
+ else {
119
+ print.info("Detecting ORM...");
120
+ const detected = (0, index_1.detectOrm)();
121
+ if (!detected) {
122
+ print.error("No ORM detected");
123
+ log(`\nSpecify one: npx ethiopian-calendar init <${VALID_ORMS.join("|")}>\n`);
124
+ process.exit(1);
125
+ }
126
+ orm = detected;
127
+ print.success(`Detected: ${orm}`);
128
+ }
129
+ const outputPath = (0, index_1.getMigrationPath)(orm);
130
+ try {
131
+ writeMigration(orm, outputPath);
132
+ print.success(`Created: ${outputPath}`);
133
+ }
134
+ catch (err) {
135
+ print.error(`Failed: ${err instanceof Error ? err.message : err}`);
136
+ process.exit(1);
137
+ }
138
+ log(`\n${fmt.bold}Next:${fmt.reset} ${NEXT_STEPS[orm][0]}`);
139
+ log(`\n${fmt.bold}Functions:${fmt.reset}`);
140
+ log(` to_ethiopian_date() → text ${fmt.cyan}# current date${fmt.reset}`);
141
+ log(` to_ethiopian_date(timestamp) → text`);
142
+ log(` from_ethiopian_date(text) → timestamp`);
143
+ log(` to_ethiopian_timestamp() → timestamp ${fmt.cyan}# current timestamp${fmt.reset}`);
144
+ log(` to_ethiopian_timestamp(ts) → timestamp\n`);
145
+ }
146
+ const [cmd, arg] = process.argv.slice(2);
147
+ switch (cmd) {
148
+ case undefined:
149
+ case "help":
150
+ case "--help":
151
+ case "-h":
152
+ showHelp();
153
+ break;
154
+ case "version":
155
+ case "--version":
156
+ case "-v":
157
+ showVersion();
158
+ break;
159
+ case "migrations":
160
+ showMigrations();
161
+ break;
162
+ case "init":
163
+ initMigration(arg);
164
+ break;
165
+ default:
166
+ print.error(`Unknown command: ${cmd}`);
167
+ showHelp();
168
+ process.exit(1);
169
+ }
170
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export declare const VERSION = "1.1.0";
2
+ export type SupportedORM = "prisma" | "drizzle" | "typeorm" | "raw";
3
+ /** Returns the full SQL migration content */
4
+ export declare function getSql(): string;
5
+ /** Returns path to the SQL migration file */
6
+ export declare function getSqlPath(): string;
7
+ /** Returns path to ORM-specific documentation */
8
+ export declare function getDocsPath(orm: SupportedORM): string;
9
+ /** Checks if an ORM package is installed */
10
+ export declare function isOrmInstalled(orm: Exclude<SupportedORM, "raw">): boolean;
11
+ /** Auto-detects installed ORM, returns null if none found */
12
+ export declare function detectOrm(): Exclude<SupportedORM, "raw"> | null;
13
+ /** Returns the migration output path for the specified ORM */
14
+ export declare function getMigrationPath(orm: SupportedORM, name?: string): string;
15
+ /** Returns path to version upgrade migration, or null if not found */
16
+ export declare function getUpgradePath(from: string, to: string): string | null;
17
+ /** Returns upgrade migration SQL content, or null if not found */
18
+ export declare function getUpgradeSql(from: string, to: string): string | null;
19
+ export interface Migration {
20
+ from: string;
21
+ to: string;
22
+ path: string;
23
+ }
24
+ /** Lists all available upgrade migrations */
25
+ export declare function listMigrations(): Migration[];
26
+ /** SQL query to check installed version in database */
27
+ export declare function getVersionCheckSql(): string;
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,CAAC;AAWpE,6CAA6C;AAC7C,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED,6CAA6C;AAC7C,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAErD;AAED,4CAA4C;AAC5C,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,OAAO,CAOzE;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,IAAI,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,IAAI,CAG/D;AAOD,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,SAAuB,GAAG,MAAM,CASvF;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGtE;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGrE;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,IAAI,SAAS,EAAE,CAY5C;AAED,uDAAuD;AACvD,wBAAgB,kBAAkB,IAAI,MAAM,CAK3C"}
package/dist/index.js ADDED
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VERSION = void 0;
4
+ exports.getSql = getSql;
5
+ exports.getSqlPath = getSqlPath;
6
+ exports.getDocsPath = getDocsPath;
7
+ exports.isOrmInstalled = isOrmInstalled;
8
+ exports.detectOrm = detectOrm;
9
+ exports.getMigrationPath = getMigrationPath;
10
+ exports.getUpgradePath = getUpgradePath;
11
+ exports.getUpgradeSql = getUpgradeSql;
12
+ exports.listMigrations = listMigrations;
13
+ exports.getVersionCheckSql = getVersionCheckSql;
14
+ const fs_1 = require("fs");
15
+ const path_1 = require("path");
16
+ exports.VERSION = "1.1.0";
17
+ const ORM_PACKAGES = {
18
+ prisma: "@prisma/client",
19
+ drizzle: "drizzle-orm",
20
+ typeorm: "typeorm",
21
+ };
22
+ const SQL_DIR = (0, path_1.join)((0, path_1.dirname)(__dirname), "sql");
23
+ const DOCS_DIR = (0, path_1.join)((0, path_1.dirname)(__dirname), "docs");
24
+ /** Returns the full SQL migration content */
25
+ function getSql() {
26
+ return (0, fs_1.readFileSync)((0, path_1.join)(SQL_DIR, "ethiopian_calendar.sql"), "utf8");
27
+ }
28
+ /** Returns path to the SQL migration file */
29
+ function getSqlPath() {
30
+ return (0, path_1.join)(SQL_DIR, "ethiopian_calendar.sql");
31
+ }
32
+ /** Returns path to ORM-specific documentation */
33
+ function getDocsPath(orm) {
34
+ return (0, path_1.join)(DOCS_DIR, `${orm}.md`);
35
+ }
36
+ /** Checks if an ORM package is installed */
37
+ function isOrmInstalled(orm) {
38
+ try {
39
+ require.resolve(ORM_PACKAGES[orm]);
40
+ return true;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ }
46
+ /** Auto-detects installed ORM, returns null if none found */
47
+ function detectOrm() {
48
+ const orms = Object.keys(ORM_PACKAGES);
49
+ return orms.find(isOrmInstalled) ?? null;
50
+ }
51
+ /** Generates timestamp for migration filenames */
52
+ function timestamp() {
53
+ return new Date().toISOString().replace(/[-:T]/g, "").slice(0, 14);
54
+ }
55
+ /** Returns the migration output path for the specified ORM */
56
+ function getMigrationPath(orm, name = "ethiopian_calendar") {
57
+ const ts = timestamp();
58
+ const paths = {
59
+ prisma: (0, path_1.join)("prisma", "migrations", `${ts}_${name}`, "migration.sql"),
60
+ drizzle: (0, path_1.join)("drizzle", `${ts}_${name}.sql`),
61
+ typeorm: (0, path_1.join)("src", "migrations", `${ts}-${name}.ts`),
62
+ raw: `${name}.sql`,
63
+ };
64
+ return paths[orm];
65
+ }
66
+ /** Returns path to version upgrade migration, or null if not found */
67
+ function getUpgradePath(from, to) {
68
+ const file = (0, path_1.join)(SQL_DIR, "migrations", `${from}_to_${to}.sql`);
69
+ return (0, fs_1.existsSync)(file) ? file : null;
70
+ }
71
+ /** Returns upgrade migration SQL content, or null if not found */
72
+ function getUpgradeSql(from, to) {
73
+ const file = getUpgradePath(from, to);
74
+ return file ? (0, fs_1.readFileSync)(file, "utf8") : null;
75
+ }
76
+ /** Lists all available upgrade migrations */
77
+ function listMigrations() {
78
+ const dir = (0, path_1.join)(SQL_DIR, "migrations");
79
+ if (!(0, fs_1.existsSync)(dir))
80
+ return [];
81
+ const pattern = /^(\d+\.\d+\.\d+)_to_(\d+\.\d+\.\d+)\.sql$/;
82
+ return (0, fs_1.readdirSync)(dir)
83
+ .map((file) => {
84
+ const match = file.match(pattern);
85
+ return match ? { from: match[1], to: match[2], path: (0, path_1.join)(dir, file) } : null;
86
+ })
87
+ .filter((m) => m !== null);
88
+ }
89
+ /** SQL query to check installed version in database */
90
+ function getVersionCheckSql() {
91
+ return `SELECT COALESCE(
92
+ (SELECT proname FROM pg_proc WHERE proname = 'ethiopian_calendar_version' LIMIT 1),
93
+ NULL
94
+ )::text AS installed, '${exports.VERSION}' AS latest;`;
95
+ }
96
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ # Using Ethiopian Calendar with Drizzle ORM
2
+
3
+ ## Quick Setup
4
+
5
+ ```bash
6
+ # Install the package
7
+ npm install @huluwz/pg-ethiopian-calendar
8
+
9
+ # Generate migration
10
+ npx ethiopian-calendar init drizzle
11
+
12
+ # Apply migration
13
+ npx drizzle-kit migrate
14
+ ```
15
+
16
+ ## Manual Setup
17
+
18
+ If you prefer to set up manually:
19
+
20
+ ### 1. Create Migration File
21
+
22
+ Copy the SQL from `node_modules/@huluwz/pg-ethiopian-calendar/sql/ethiopian_calendar.sql` to your Drizzle migrations folder (e.g., `drizzle/0001_ethiopian_calendar.sql`)
23
+
24
+ ### 2. Apply Migration
25
+
26
+ ```bash
27
+ npx drizzle-kit migrate
28
+ # or
29
+ npx drizzle-kit push
30
+ ```
31
+
32
+ ## Usage Examples
33
+
34
+ ### Schema with Generated Columns
35
+
36
+ ```typescript
37
+ import { pgTable, serial, timestamp, text } from 'drizzle-orm/pg-core'
38
+ import { sql } from 'drizzle-orm'
39
+
40
+ export const orders = pgTable('orders', {
41
+ id: serial('id').primaryKey(),
42
+ customerName: text('customer_name').notNull(),
43
+ createdAt: timestamp('created_at').defaultNow(),
44
+
45
+ // Generated column - Ethiopian date calculated automatically
46
+ createdAtEthiopian: timestamp('created_at_ethiopian')
47
+ .generatedAlwaysAs(sql`to_ethiopian_timestamp(created_at)`),
48
+ })
49
+ ```
50
+
51
+ ### Using in Queries
52
+
53
+ ```typescript
54
+ import { db } from './db'
55
+ import { orders } from './schema'
56
+ import { sql } from 'drizzle-orm'
57
+
58
+ // Insert - Ethiopian date is auto-generated
59
+ const [order] = await db.insert(orders)
60
+ .values({ customerName: 'Abebe Kebede' })
61
+ .returning()
62
+
63
+ console.log(order.createdAtEthiopian) // Ethiopian timestamp!
64
+
65
+ // Get current Ethiopian date
66
+ const result = await db.execute(
67
+ sql`SELECT current_ethiopian_date() as today`
68
+ )
69
+
70
+ // Convert a specific date
71
+ const converted = await db.execute(
72
+ sql`SELECT to_ethiopian_date('2026-01-01'::timestamp) as ethiopian`
73
+ )
74
+
75
+ // Filter by Ethiopian date
76
+ const filtered = await db
77
+ .select()
78
+ .from(orders)
79
+ .where(sql`to_ethiopian_date(created_at) = '2018-04-23'`)
80
+ ```
81
+
82
+ ### Creating Table with Raw SQL
83
+
84
+ If you prefer to create the table in a migration:
85
+
86
+ ```sql
87
+ CREATE TABLE orders (
88
+ id SERIAL PRIMARY KEY,
89
+ customer_name TEXT NOT NULL,
90
+ created_at TIMESTAMP DEFAULT NOW(),
91
+ created_at_ethiopian TIMESTAMP GENERATED ALWAYS AS
92
+ (to_ethiopian_timestamp(created_at)) STORED
93
+ );
94
+ ```
95
+
96
+ ### Functional Index
97
+
98
+ ```typescript
99
+ import { index } from 'drizzle-orm/pg-core'
100
+ import { sql } from 'drizzle-orm'
101
+
102
+ // In your schema or migration
103
+ export const ordersEthiopianIdx = index('idx_orders_ethiopian')
104
+ .on(sql`to_ethiopian_date(created_at)`)
105
+ ```
106
+
107
+ Or in raw SQL:
108
+
109
+ ```sql
110
+ CREATE INDEX idx_orders_ethiopian
111
+ ON orders (to_ethiopian_date(created_at));
112
+ ```
113
+
114
+ ## Available Functions
115
+
116
+ | Function | Description |
117
+ |----------|-------------|
118
+ | `to_ethiopian_date(timestamp)` | Convert to Ethiopian date string (YYYY-MM-DD) |
119
+ | `from_ethiopian_date(text)` | Convert Ethiopian date to Gregorian timestamp |
120
+ | `to_ethiopian_timestamp(timestamp)` | Convert preserving time (for generated columns) |
121
+ | `current_ethiopian_date()` | Get current Ethiopian date |
122
+
123
+ ## Using sql Template
124
+
125
+ All functions can be used with Drizzle's `sql` template:
126
+
127
+ ```typescript
128
+ import { sql } from 'drizzle-orm'
129
+
130
+ // In select
131
+ const result = await db.select({
132
+ id: orders.id,
133
+ ethiopianDate: sql<string>`to_ethiopian_date(${orders.createdAt})`,
134
+ }).from(orders)
135
+
136
+ // In where
137
+ const filtered = await db.select()
138
+ .from(orders)
139
+ .where(sql`to_ethiopian_date(${orders.createdAt}) > '2018-01-01'`)
140
+ ```
141
+
142
+ ## Links
143
+
144
+ - [GitHub Repository](https://github.com/HuluWZ/pg-ethiopian-calendar)
145
+ - [NPM Package](https://www.npmjs.com/package/@huluwz/pg-ethiopian-calendar)
146
+ - [Drizzle ORM Docs](https://orm.drizzle.team/)
147
+