@noormdev/sdk 1.0.0-alpha.35 → 1.0.0-alpha.36

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.
@@ -89,8 +89,10 @@ async function verifyDatabaseExists(Tedious, Tarn, config) {
89
89
  }
90
90
  }
91
91
  async function createMssqlConnection(config) {
92
- const Tedious = await import('tedious');
93
- const Tarn = await import('tarn');
92
+ const TediousImport = await import('tedious');
93
+ const TarnImport = await import('tarn');
94
+ const Tedious = TediousImport.default ?? TediousImport;
95
+ const Tarn = TarnImport.default ?? TarnImport;
94
96
  await verifyDatabaseExists(Tedious, Tarn, config);
95
97
  const db = new Kysely({
96
98
  dialect: new MssqlDialect({
@@ -117,5 +119,5 @@ async function createMssqlConnection(config) {
117
119
  }
118
120
 
119
121
  export { createMssqlConnection };
120
- //# sourceMappingURL=mssql-3NNVV77C.js.map
121
- //# sourceMappingURL=mssql-3NNVV77C.js.map
122
+ //# sourceMappingURL=mssql-NIABT3Z4.js.map
123
+ //# sourceMappingURL=mssql-NIABT3Z4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/connection/dialects/mssql-limit-plugin.ts","../../../src/core/connection/dialects/mssql.ts"],"names":[],"mappings":"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","file":"mssql-NIABT3Z4.js","sourcesContent":["/**\n * Kysely plugin that converts LIMIT to TOP for MSSQL.\n *\n * Kysely 0.28.x's MssqlQueryCompiler does not override visitLimit(),\n * so .limit(n) generates invalid `LIMIT n` SQL instead of `TOP(n)`.\n * This plugin transforms the query AST before compilation, converting\n * LimitNode to TopNode on SELECT queries.\n *\n * WHY: MSSQL does not support the LIMIT keyword. It uses TOP(n) for\n * simple row limiting and OFFSET...FETCH for pagination.\n *\n * @example\n * ```typescript\n * import { Kysely, MssqlDialect } from 'kysely'\n * import { MssqlLimitPlugin } from './mssql-limit-plugin'\n *\n * const db = new Kysely({\n * dialect: new MssqlDialect({...}),\n * plugins: [new MssqlLimitPlugin()],\n * })\n *\n * // .limit() now works correctly on MSSQL\n * await db.selectFrom('users').selectAll().limit(10).execute()\n * // SQL: SELECT TOP(10) * FROM \"users\"\n * ```\n */\nimport {\n OperationNodeTransformer,\n type KyselyPlugin,\n type PluginTransformQueryArgs,\n type PluginTransformResultArgs,\n type QueryResult,\n type UnknownRow,\n} from 'kysely';\n\nimport type { RootOperationNode } from 'kysely';\n\n/**\n * AST transformer that rewrites LimitNode → TopNode on SELECT queries.\n *\n * Only transforms when:\n * - The SELECT has a limit but no top already set\n * - The limit value is a ValueNode containing a number\n */\nclass LimitToTopTransformer extends OperationNodeTransformer {\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected override transformSelectQuery(node: any): any {\n\n // Let parent transform children first (handles subqueries)\n const transformed = super.transformSelectQuery(node);\n\n // Only convert if there's a limit and no top already\n if (!transformed.limit || transformed.top) {\n\n return transformed;\n\n }\n\n // Extract the numeric value from the LimitNode\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const limitOp = transformed.limit.limit as any;\n let value: number | bigint | undefined;\n\n if (limitOp?.kind === 'ValueNode' && (typeof limitOp.value === 'number' || typeof limitOp.value === 'bigint')) {\n\n value = limitOp.value;\n\n }\n\n // Can't convert non-literal limits\n if (value === undefined) {\n\n return transformed;\n\n }\n\n // Replace limit with top\n return {\n ...transformed,\n limit: undefined,\n top: {\n kind: 'TopNode',\n expression: value,\n },\n };\n\n }\n\n}\n\n/**\n * Kysely plugin that patches .limit() for MSSQL compatibility.\n *\n * Add to the Kysely instance via the plugins option:\n *\n * @example\n * ```typescript\n * new Kysely({ dialect, plugins: [new MssqlLimitPlugin()] })\n * ```\n */\nexport class MssqlLimitPlugin implements KyselyPlugin {\n\n readonly #transformer = new LimitToTopTransformer();\n\n transformQuery(args: PluginTransformQueryArgs): RootOperationNode {\n\n return this.#transformer.transformNode(args.node) as RootOperationNode;\n\n }\n\n async transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {\n\n return args.result;\n\n }\n\n}\n","/**\n * SQL Server (MSSQL) dialect adapter.\n *\n * Uses 'tedious' and 'tarn' packages for MSSQL connections.\n * Install with: npm install tedious tarn\n *\n * Verifies database existence via sys.databases before connecting\n * to the target database, avoiding cryptic ECONNRESET errors when\n * the database doesn't exist.\n */\nimport { Kysely, MssqlDialect, sql } from 'kysely';\nimport type { ConnectionConfig, ConnectionResult } from '../types.js';\nimport { MssqlLimitPlugin } from './mssql-limit-plugin.js';\n\n/**\n * Build tedious connection options from noorm config.\n *\n * Centralizes the tedious config so both the preflight check\n * and the real pool use the same settings.\n */\nfunction buildTediousConfig(\n Tedious: typeof import('tedious'),\n config: ConnectionConfig,\n database?: string,\n) {\n\n return new Tedious.Connection({\n server: config.host ?? 'localhost',\n authentication: {\n type: 'default',\n options: {\n userName: config.user,\n password: config.password,\n },\n },\n options: {\n port: config.port ?? 1433,\n database: database ?? config.database,\n trustServerCertificate: !config.ssl,\n encrypt: true,\n },\n });\n\n}\n\n/**\n * Verify the target database exists by querying sys.databases on master.\n *\n * Connects to 'master' first and checks sys.databases. Throws a clear\n * error if the database is missing, instead of letting tedious hang\n * with a cryptic ECONNRESET.\n */\nasync function verifyDatabaseExists(\n Tedious: typeof import('tedious'),\n Tarn: typeof import('tarn'),\n config: ConnectionConfig,\n): Promise<void> {\n\n const masterDb = new Kysely<unknown>({\n dialect: new MssqlDialect({\n tarn: {\n ...Tarn,\n options: {\n min: 0,\n max: 1,\n propagateCreateError: true,\n },\n },\n tedious: {\n ...Tedious,\n connectionFactory: () => buildTediousConfig(Tedious, config, 'master'),\n },\n }),\n plugins: [new MssqlLimitPlugin()],\n });\n\n try {\n\n const { rows } = await sql<{ name: string }>`\n SELECT name FROM sys.databases WHERE name = ${config.database}\n `.execute(masterDb);\n\n if (rows.length === 0) {\n\n throw new Error(\n `Database '${config.database}' does not exist on ${config.host ?? 'localhost'}:${config.port ?? 1433}`,\n );\n\n }\n\n }\n finally {\n\n await masterDb.destroy();\n\n }\n\n}\n\n/**\n * Create a SQL Server connection.\n *\n * Verifies the target database exists via master before opening\n * the connection pool. This avoids the tedious/tarn hang that\n * occurs when MSSQL rejects login for a non-existent database.\n *\n * @example\n * ```typescript\n * const conn = createMssqlConnection({\n * dialect: 'mssql',\n * host: 'localhost',\n * port: 1433,\n * database: 'myapp',\n * user: 'sa',\n * password: 'secret',\n * })\n * ```\n */\nexport async function createMssqlConnection(config: ConnectionConfig): Promise<ConnectionResult> {\n\n // Dynamic import to avoid compile-time dependency. Normalize CJS interop:\n // when bundled (tsup), the module's exports land under `.default`, so a\n // bare `Tarn.Pool` is undefined and kysely throws \"Pool is not a\n // constructor\". Mirror the postgres dialect's `pkg.default ?? pkg` guard.\n const TediousImport = await import('tedious');\n const TarnImport = await import('tarn');\n const Tedious = TediousImport.default ?? TediousImport;\n const Tarn = TarnImport.default ?? TarnImport;\n\n // Preflight: verify database exists via master\n await verifyDatabaseExists(Tedious, Tarn, config);\n\n const db = new Kysely<unknown>({\n dialect: new MssqlDialect({\n tarn: {\n ...Tarn,\n options: {\n min: config.pool?.min ?? 0,\n max: config.pool?.max ?? 10,\n propagateCreateError: true,\n },\n },\n tedious: {\n ...Tedious,\n connectionFactory: () => buildTediousConfig(Tedious, config),\n },\n }),\n plugins: [new MssqlLimitPlugin()],\n });\n\n return {\n db,\n dialect: 'mssql',\n destroy: () => db.destroy(),\n };\n\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noormdev/sdk",
3
- "version": "1.0.0-alpha.35",
3
+ "version": "1.0.0-alpha.36",
4
4
  "description": "Database schema & changeset manager SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/core/connection/dialects/mssql-limit-plugin.ts","../../../src/core/connection/dialects/mssql.ts"],"names":[],"mappings":"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","file":"mssql-3NNVV77C.js","sourcesContent":["/**\n * Kysely plugin that converts LIMIT to TOP for MSSQL.\n *\n * Kysely 0.28.x's MssqlQueryCompiler does not override visitLimit(),\n * so .limit(n) generates invalid `LIMIT n` SQL instead of `TOP(n)`.\n * This plugin transforms the query AST before compilation, converting\n * LimitNode to TopNode on SELECT queries.\n *\n * WHY: MSSQL does not support the LIMIT keyword. It uses TOP(n) for\n * simple row limiting and OFFSET...FETCH for pagination.\n *\n * @example\n * ```typescript\n * import { Kysely, MssqlDialect } from 'kysely'\n * import { MssqlLimitPlugin } from './mssql-limit-plugin'\n *\n * const db = new Kysely({\n * dialect: new MssqlDialect({...}),\n * plugins: [new MssqlLimitPlugin()],\n * })\n *\n * // .limit() now works correctly on MSSQL\n * await db.selectFrom('users').selectAll().limit(10).execute()\n * // SQL: SELECT TOP(10) * FROM \"users\"\n * ```\n */\nimport {\n OperationNodeTransformer,\n type KyselyPlugin,\n type PluginTransformQueryArgs,\n type PluginTransformResultArgs,\n type QueryResult,\n type UnknownRow,\n} from 'kysely';\n\nimport type { RootOperationNode } from 'kysely';\n\n/**\n * AST transformer that rewrites LimitNode → TopNode on SELECT queries.\n *\n * Only transforms when:\n * - The SELECT has a limit but no top already set\n * - The limit value is a ValueNode containing a number\n */\nclass LimitToTopTransformer extends OperationNodeTransformer {\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected override transformSelectQuery(node: any): any {\n\n // Let parent transform children first (handles subqueries)\n const transformed = super.transformSelectQuery(node);\n\n // Only convert if there's a limit and no top already\n if (!transformed.limit || transformed.top) {\n\n return transformed;\n\n }\n\n // Extract the numeric value from the LimitNode\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const limitOp = transformed.limit.limit as any;\n let value: number | bigint | undefined;\n\n if (limitOp?.kind === 'ValueNode' && (typeof limitOp.value === 'number' || typeof limitOp.value === 'bigint')) {\n\n value = limitOp.value;\n\n }\n\n // Can't convert non-literal limits\n if (value === undefined) {\n\n return transformed;\n\n }\n\n // Replace limit with top\n return {\n ...transformed,\n limit: undefined,\n top: {\n kind: 'TopNode',\n expression: value,\n },\n };\n\n }\n\n}\n\n/**\n * Kysely plugin that patches .limit() for MSSQL compatibility.\n *\n * Add to the Kysely instance via the plugins option:\n *\n * @example\n * ```typescript\n * new Kysely({ dialect, plugins: [new MssqlLimitPlugin()] })\n * ```\n */\nexport class MssqlLimitPlugin implements KyselyPlugin {\n\n readonly #transformer = new LimitToTopTransformer();\n\n transformQuery(args: PluginTransformQueryArgs): RootOperationNode {\n\n return this.#transformer.transformNode(args.node) as RootOperationNode;\n\n }\n\n async transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {\n\n return args.result;\n\n }\n\n}\n","/**\n * SQL Server (MSSQL) dialect adapter.\n *\n * Uses 'tedious' and 'tarn' packages for MSSQL connections.\n * Install with: npm install tedious tarn\n *\n * Verifies database existence via sys.databases before connecting\n * to the target database, avoiding cryptic ECONNRESET errors when\n * the database doesn't exist.\n */\nimport { Kysely, MssqlDialect, sql } from 'kysely';\nimport type { ConnectionConfig, ConnectionResult } from '../types.js';\nimport { MssqlLimitPlugin } from './mssql-limit-plugin.js';\n\n/**\n * Build tedious connection options from noorm config.\n *\n * Centralizes the tedious config so both the preflight check\n * and the real pool use the same settings.\n */\nfunction buildTediousConfig(\n Tedious: typeof import('tedious'),\n config: ConnectionConfig,\n database?: string,\n) {\n\n return new Tedious.Connection({\n server: config.host ?? 'localhost',\n authentication: {\n type: 'default',\n options: {\n userName: config.user,\n password: config.password,\n },\n },\n options: {\n port: config.port ?? 1433,\n database: database ?? config.database,\n trustServerCertificate: !config.ssl,\n encrypt: true,\n },\n });\n\n}\n\n/**\n * Verify the target database exists by querying sys.databases on master.\n *\n * Connects to 'master' first and checks sys.databases. Throws a clear\n * error if the database is missing, instead of letting tedious hang\n * with a cryptic ECONNRESET.\n */\nasync function verifyDatabaseExists(\n Tedious: typeof import('tedious'),\n Tarn: typeof import('tarn'),\n config: ConnectionConfig,\n): Promise<void> {\n\n const masterDb = new Kysely<unknown>({\n dialect: new MssqlDialect({\n tarn: {\n ...Tarn,\n options: {\n min: 0,\n max: 1,\n propagateCreateError: true,\n },\n },\n tedious: {\n ...Tedious,\n connectionFactory: () => buildTediousConfig(Tedious, config, 'master'),\n },\n }),\n plugins: [new MssqlLimitPlugin()],\n });\n\n try {\n\n const { rows } = await sql<{ name: string }>`\n SELECT name FROM sys.databases WHERE name = ${config.database}\n `.execute(masterDb);\n\n if (rows.length === 0) {\n\n throw new Error(\n `Database '${config.database}' does not exist on ${config.host ?? 'localhost'}:${config.port ?? 1433}`,\n );\n\n }\n\n }\n finally {\n\n await masterDb.destroy();\n\n }\n\n}\n\n/**\n * Create a SQL Server connection.\n *\n * Verifies the target database exists via master before opening\n * the connection pool. This avoids the tedious/tarn hang that\n * occurs when MSSQL rejects login for a non-existent database.\n *\n * @example\n * ```typescript\n * const conn = createMssqlConnection({\n * dialect: 'mssql',\n * host: 'localhost',\n * port: 1433,\n * database: 'myapp',\n * user: 'sa',\n * password: 'secret',\n * })\n * ```\n */\nexport async function createMssqlConnection(config: ConnectionConfig): Promise<ConnectionResult> {\n\n // Dynamic import to avoid compile-time dependency\n const Tedious = await import('tedious');\n const Tarn = await import('tarn');\n\n // Preflight: verify database exists via master\n await verifyDatabaseExists(Tedious, Tarn, config);\n\n const db = new Kysely<unknown>({\n dialect: new MssqlDialect({\n tarn: {\n ...Tarn,\n options: {\n min: config.pool?.min ?? 0,\n max: config.pool?.max ?? 10,\n propagateCreateError: true,\n },\n },\n tedious: {\n ...Tedious,\n connectionFactory: () => buildTediousConfig(Tedious, config),\n },\n }),\n plugins: [new MssqlLimitPlugin()],\n });\n\n return {\n db,\n dialect: 'mssql',\n destroy: () => db.destroy(),\n };\n\n}\n"]}