forge-sql-orm 2.0.12 → 2.0.14

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 CHANGED
@@ -81,7 +81,7 @@ Forge-SQL-ORM is designed to work with @forge/sql and requires some additional s
81
81
 
82
82
  ```sh
83
83
  npm install forge-sql-orm @forge/sql drizzle-orm momment -S
84
- npm install mysql2 drizzle-kit inquirer@8.0.0 -D
84
+ npm install forge-sql-orm-cli -D
85
85
  ```
86
86
 
87
87
  This will:
@@ -89,6 +89,7 @@ This will:
89
89
  - Install @forge/sql, the Forge database layer
90
90
  - Install Drizzle ORM and its MySQL driver
91
91
  - Install TypeScript types for MySQL
92
+ - Install forge-sql-orm-cli A command-line interface tool for managing Atlassian Forge SQL migrations and model generation with Drizzle ORM integration.
92
93
 
93
94
  ## Direct Drizzle Usage with Custom Driver
94
95
 
@@ -127,7 +128,7 @@ This approach gives you direct access to all Drizzle ORM features while still us
127
128
  1. **Generate initial schema from an existing database**
128
129
 
129
130
  ```sh
130
- npx forge-sql-orm generate:model --dbName testDb --output ./database/schema
131
+ npx forge-sql-orm-cli generate:model --dbName testDb --output ./database/schema
131
132
  ```
132
133
 
133
134
  _(This is done only once when setting up the project)_
@@ -135,7 +136,7 @@ This approach gives you direct access to all Drizzle ORM features while still us
135
136
  2. **Create the first migration**
136
137
 
137
138
  ```sh
138
- npx forge-sql-orm migrations:create --dbName testDb --entitiesPath ./database/schema --output ./database/migration
139
+ npx forge-sql-orm-cli migrations:create --dbName testDb --entitiesPath ./database/schema --output ./database/migration
139
140
  ```
140
141
 
141
142
  _(This initializes the database migration structure, also done once)_
@@ -152,7 +153,7 @@ This approach gives you direct access to all Drizzle ORM features while still us
152
153
  5. **Update the migration**
153
154
 
154
155
  ```sh
155
- npx forge-sql-orm migrations:update --dbName testDb --entitiesPath ./database/schema --output ./database/migration
156
+ npx forge-sql-orm-cli migrations:update --dbName testDb --entitiesPath ./database/schema --output ./database/migration
156
157
  ```
157
158
 
158
159
  - ⚠️ **Do NOT update schema before this step!**
@@ -165,7 +166,7 @@ This approach gives you direct access to all Drizzle ORM features while still us
165
166
  7. **Update the schema**
166
167
 
167
168
  ```sh
168
- npx forge-sql-orm generate:model --dbName testDb --output ./database/schema
169
+ npx forge-sql-orm-cli generate:model --dbName testDb --output ./database/schema
169
170
  ```
170
171
 
171
172
  8. **Repeat steps 4-7 as needed**
@@ -194,12 +195,12 @@ Before using Drop Migrations, ensure that:
194
195
 
195
196
  1. First, ensure your local schema matches the deployed database:
196
197
  ```bash
197
- npx forge-sql-orm generate:model --output ./database/schema
198
+ npx forge-sql-orm-cli generate:model --output ./database/schema
198
199
  ```
199
200
 
200
201
  2. Generate the drop migration:
201
202
  ```bash
202
- npx forge-sql-orm migrations:drop --entitiesPath ./database/schema --output ./database/migration
203
+ npx forge-sql-orm-cli migrations:drop --entitiesPath ./database/schema --output ./database/migration
203
204
  ```
204
205
 
205
206
  3. Deploy and run the migration in your Forge app:
@@ -214,7 +215,7 @@ Before using Drop Migrations, ensure that:
214
215
 
215
216
  4. After dropping all tables, you can create a new migration to recreate the schema:
216
217
  ```bash
217
- npx forge-sql-orm migrations:create --entitiesPath ./database/schema --output ./database/migration --force
218
+ npx forge-sql-orm-cli migrations:create --entitiesPath ./database/schema --output ./database/migration --force
218
219
  ```
219
220
  The `--force` parameter is required here because we're creating a new migration after dropping all tables.
220
221
 
@@ -535,22 +536,7 @@ The `ForgeSqlOrmOptions` object allows customization of ORM behavior:
535
536
 
536
537
  ## CLI Commands
537
538
 
538
- ```sh
539
- $ npx forge-sql-orm --help
540
-
541
- Usage: forge-sql-orm [options] [command]
542
-
543
- Options:
544
- -V, --version Output the version number
545
- -h, --help Display help for command
546
-
547
- Commands:
548
- generate:model [options] Generate Drizzle models from the database
549
- migrations:create [options] Generate an initial migration for the entire database
550
- migrations:update [options] Generate a migration to update the database schema
551
- migrations:drop [options] Generate a migration to drop all tables
552
- help [command] Display help for a specific command
553
- ```
539
+ Documentation [here](forge-sql-orm-cli/README.md)
554
540
 
555
541
  ## Web Triggers for Migrations
556
542
 
@@ -2,12 +2,12 @@
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
3
  const drizzleOrm = require("drizzle-orm");
4
4
  const moment = require("moment");
5
- const table = require("drizzle-orm/table");
6
5
  const sql = require("drizzle-orm/sql/sql");
7
6
  const sql$1 = require("@forge/sql");
8
7
  const mysqlProxy = require("drizzle-orm/mysql-proxy");
9
8
  const mysqlCore = require("drizzle-orm/mysql-core");
10
9
  const moment$1 = require("moment/moment.js");
10
+ const table = require("drizzle-orm/table");
11
11
  const parseDateTime = (value, format) => {
12
12
  const m = moment(value, format, true);
13
13
  if (!m.isValid()) {
@@ -131,12 +131,12 @@ function generateDropTableStatements(tables) {
131
131
  dropStatements.push(`DELETE FROM __migrations;`);
132
132
  return dropStatements;
133
133
  }
134
- function mapSelectTableToAlias(table2, aliasMap) {
134
+ function mapSelectTableToAlias(table2, uniqPrefix, aliasMap) {
135
135
  const { columns, tableName } = getTableMetadata(table2);
136
136
  const selectionsTableFields = {};
137
137
  Object.keys(columns).forEach((name) => {
138
138
  const column = columns[name];
139
- const uniqName = `a_${tableName}_${column.name}`;
139
+ const uniqName = `a_${uniqPrefix}_${tableName}_${column.name}`.toLowerCase();
140
140
  const fieldAlias = drizzleOrm.sql.raw(uniqName);
141
141
  selectionsTableFields[name] = drizzleOrm.sql`${column} as \`${fieldAlias}\``;
142
142
  aliasMap[uniqName] = column;
@@ -146,13 +146,13 @@ function mapSelectTableToAlias(table2, aliasMap) {
146
146
  function isDrizzleColumn(column) {
147
147
  return column && typeof column === "object" && "table" in column;
148
148
  }
149
- function mapSelectAllFieldsToAlias(selections, name, fields, aliasMap) {
149
+ function mapSelectAllFieldsToAlias(selections, name, uniqName, fields, aliasMap) {
150
150
  if (drizzleOrm.isTable(fields)) {
151
- selections[name] = mapSelectTableToAlias(fields, aliasMap);
151
+ selections[name] = mapSelectTableToAlias(fields, uniqName, aliasMap);
152
152
  } else if (isDrizzleColumn(fields)) {
153
153
  const column = fields;
154
- const uniqName = `a_${table.getTableName(column.table)}_${column.name}`;
155
- let aliasName = drizzleOrm.sql.raw(uniqName);
154
+ const uniqAliasName = `a_${uniqName}_${column.name}`.toLowerCase();
155
+ let aliasName = drizzleOrm.sql.raw(uniqAliasName);
156
156
  selections[name] = drizzleOrm.sql`${column} as \`${aliasName}\``;
157
157
  aliasMap[uniqName] = column;
158
158
  } else if (sql.isSQLWrapper(fields)) {
@@ -160,7 +160,7 @@ function mapSelectAllFieldsToAlias(selections, name, fields, aliasMap) {
160
160
  } else {
161
161
  const innerSelections = {};
162
162
  Object.entries(fields).forEach(([iname, ifields]) => {
163
- mapSelectAllFieldsToAlias(innerSelections, iname, ifields, aliasMap);
163
+ mapSelectAllFieldsToAlias(innerSelections, iname, `${uniqName}_${iname}`, ifields, aliasMap);
164
164
  });
165
165
  selections[name] = innerSelections;
166
166
  }
@@ -173,7 +173,7 @@ function mapSelectFieldsWithAlias(fields) {
173
173
  const aliasMap = {};
174
174
  const selections = {};
175
175
  Object.entries(fields).forEach(([name, fields2]) => {
176
- mapSelectAllFieldsToAlias(selections, name, fields2, aliasMap);
176
+ mapSelectAllFieldsToAlias(selections, name, name, fields2, aliasMap);
177
177
  });
178
178
  return { selections, aliasMap };
179
179
  }
@@ -218,7 +218,11 @@ function transformObject(obj, selections, aliasMap) {
218
218
  if (alias && aliasMap[alias]) {
219
219
  result[key] = transformValue(value, alias, aliasMap);
220
220
  } else if (selection && typeof selection === "object" && !sql.isSQLWrapper(selection)) {
221
- result[key] = transformObject(value, selection, aliasMap);
221
+ result[key] = transformObject(
222
+ value,
223
+ selection,
224
+ aliasMap
225
+ );
222
226
  } else {
223
227
  result[key] = value;
224
228
  }
@@ -227,9 +231,38 @@ function transformObject(obj, selections, aliasMap) {
227
231
  }
228
232
  function applyFromDriverTransform(rows, selections, aliasMap) {
229
233
  return rows.map((row) => {
230
- return transformObject(row, selections, aliasMap);
234
+ const transformed = transformObject(
235
+ row,
236
+ selections,
237
+ aliasMap
238
+ );
239
+ return processNullBranches(transformed);
231
240
  });
232
241
  }
242
+ function processNullBranches(obj) {
243
+ if (obj === null || typeof obj !== "object" || obj === void 0) {
244
+ return obj;
245
+ }
246
+ const result = {};
247
+ let allNull = true;
248
+ for (const [key, value] of Object.entries(obj)) {
249
+ if (value === null || value === void 0) {
250
+ result[key] = null;
251
+ continue;
252
+ }
253
+ if (typeof value === "object" && (value !== null || value !== void 0)) {
254
+ const processed = processNullBranches(value);
255
+ result[key] = processed;
256
+ if (processed !== null) {
257
+ allNull = false;
258
+ }
259
+ } else {
260
+ result[key] = value;
261
+ allNull = false;
262
+ }
263
+ }
264
+ return allNull ? null : result;
265
+ }
233
266
  class ForgeSQLCrudOperations {
234
267
  forgeOperations;
235
268
  options;
@@ -620,13 +653,10 @@ function createAliasedSelectBuilder(db, fields, selectFn) {
620
653
  };
621
654
  }
622
655
  if (prop === "then") {
623
- return (onfulfilled, onrejected) => target.execute().then(
624
- (rows) => {
625
- const transformed = applyFromDriverTransform(rows, selections, aliasMap);
626
- return onfulfilled?.(transformed);
627
- },
628
- onrejected
629
- );
656
+ return (onfulfilled, onrejected) => target.execute().then((rows) => {
657
+ const transformed = applyFromDriverTransform(rows, selections, aliasMap);
658
+ return onfulfilled?.(transformed);
659
+ }, onrejected);
630
660
  }
631
661
  const value = Reflect.get(target, prop, receiver);
632
662
  if (typeof value === "function") {
@@ -671,7 +701,9 @@ class ForgeSQLORMImpl {
671
701
  if (newOptions.logRawSqlQuery) {
672
702
  console.debug("Initializing ForgeSQLORM...");
673
703
  }
674
- this.drizzle = patchDbWithSelectAliased(mysqlProxy.drizzle(forgeDriver, { logger: newOptions.logRawSqlQuery }));
704
+ this.drizzle = patchDbWithSelectAliased(
705
+ mysqlProxy.drizzle(forgeDriver, { logger: newOptions.logRawSqlQuery })
706
+ );
675
707
  this.crudOperations = new ForgeSQLCrudOperations(this, newOptions);
676
708
  this.fetchOperations = new ForgeSQLSelectOperations(newOptions);
677
709
  } catch (error) {