mssql driver SQL Server uses, so FabricDialectMSSQLDialect: parameter binding (@p1), [bracket] quoting,TOP, OFFSET/FETCH, MERGE upserts, multi-rowVALUES and catalog introspection are all inherited.DISTRIBUTION, no storage-index choice and no PARTITION, while OFFSET/FETCH,MERGE, sp_rename and CREATE OR ALTER — which the pool lacks — all exist.| Property | Value |
|---|---|
| Dialect name | fabric |
| Extends | MSSQLDialect |
| Driver | mssql (tedious) |
| Default port | 1433 |
| Cloud SDK | @azure/identity (Entra only) |
| Local runtime | none — hosted service only |
$ npm install ts-prorm-orm mssql$ pnpm add ts-prorm-orm mssql$ yarn add ts-prorm-orm mssql$ bun add ts-prorm-orm mssqlmssql is the same driver the mssql dialect uses.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'fabric',
host: 'abc123.datawarehouse.fabric.microsoft.com',
database: 'Sales', // the warehouse
dialectOptions: {
entra: true, // DefaultAzureCredential
},
});import { DataTypes } from 'ts-prorm-orm';
const User = db.define('User', {
id: { type: DataTypes.INTEGER(), primaryKey: true, autoIncrement: true },
email: { type: DataTypes.STRING(255), allowNull: false, unique: true },
name: { type: DataTypes.STRING(100) },
}, { timestamps: false });
await db.sync(); // CREATE TABLE — see Generated SQL below[!NOTE] Why timestamps: false
A DEFAULT on column "createdAt" is not supported by Microsoft Fabric Data Warehouse. Fabric has no default constraints. Supply the value on INSERT, or use COPY INTO’s per-column default when loading.
import { Op } from 'ts-prorm-orm';
await User.create({ email: 'ada@example.com', name: 'Ada' });
const page = await User.findAll({
where: { name: { [Op.like]: 'A%' } },
order: [['id', 'ASC']],
limit: 20,
offset: 40,
});import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'fabric',
host: 'abc123.datawarehouse.fabric.microsoft.com',
database: 'Sales',
dialectOptions: {
entra: true, // DefaultAzureCredential: env, workload/managed identity, Azure CLI
},
});@azure/identity installed next to the driver.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'fabric',
host: 'abc123.datawarehouse.fabric.microsoft.com',
database: 'Sales',
dialectOptions: {
entra: { credential: { type: 'managed-identity', clientId: process.env.AZURE_CLIENT_ID } },
},
});@azure/identity installed next to the driver.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'fabric',
host: 'abc123.datawarehouse.fabric.microsoft.com',
database: 'Sales',
dialectOptions: {
entra: {
credential: {
type: 'client-secret',
tenantId: process.env.AZURE_TENANT_ID!,
clientId: process.env.AZURE_CLIENT_ID!,
clientSecret: process.env.AZURE_CLIENT_SECRET!,
},
},
},
});@azure/identity installed next to the driver.query(), captured with the driver stubbed out. The model layer inlines the values.db.sync() for the model in the Quick start:CREATE TABLEawait User.create({ email: 'ada@example.com', name: 'Ada' });
await User.update({ name: 'Grace' }, { where: { email: 'ada@example.com' } });
await User.destroy({ where: { id: 1 } });await User.upsert({ id: 1, email: 'ada@example.com', name: 'Ada Lovelace' });MERGE statementupsert() also reads the row by primary key before and after the write, to return the instance.await User.findAll({
where: { name: { [Op.like]: 'A%' } },
order: [['id', 'ASC']],
limit: 20,
offset: 40,
});await db.transaction(async (t) => {
await User.create({ email: 'grace@example.com', name: 'Grace' }, { transaction: t });
await User.update({ name: 'Grace Hopper' }, { where: { email: 'grace@example.com' }, transaction: t });
});[!WARNING] No savepoints
Nested transactions need savepoints, and fabric has none. Run the work in a single transaction, or restructure it so nothing nests.
STRING → VARCHAR(255), auto-increment INTEGER → INT, BOOLEAN → BIT, DATE → DATETIME2(6), UUID → UNIQUEIDENTIFIER, JSON → VARCHAR(MAX). The type comparison lines the major engines up side by side.authenticationDefaultAzureCredential (environment, workload identity,import { Prorm } from 'ts-prorm-orm';
const db = new Prorm({
dialect: 'fabric',
host: 'abc123.datawarehouse.fabric.microsoft.com', // the warehouse's SQL connection string
database: 'Sales', // the warehouse
dialectOptions: {
authentication: {
type: 'azure-active-directory-service-principal-secret',
options: { clientId, clientSecret, tenantId },
},
},
});authentication.types: azure-active-directory-default (default),-service-principal-secret, -access-token, -password, -msi-vm,-msi-app-service. TLS is on and the certificate is verified by default.cloud-auth token providers instead, passentra (true, or { credential } — the scope ishttps://database.windows.net/.default) or any tokenProvider; the token istediousAuth(), so each new pooled connection gets a currententra, tokenProvider or authentication.connect() (and its retry loop) builds the pool. FabricresolvePoolConfig hook to remove user/password, addauthentication block (and beforeConnect for token providers), and pinencrypt: true, trustServerCertificate: false. Construction throws if theFabricDialect extends MSSQLDialect (mssql) andObject.getOwnPropertyNames(FabricDialect.prototype),| Area | Overridden |
|---|---|
| Connection and execution | resolvePoolConfig, startTransaction |
| DML builders | buildDeleteQuery, buildInsertQuery, buildSelectQuery, buildUpdateQuery, buildUpsertQuery, bulkInsert |
| Types | buildFabricColumnSql, getDataTypeSql |
| DDL and schema | addColumn, addForeignKey, addIndex, buildClusterBy, buildConstraintStatement, buildCreateTableStatements, buildCtasSql, changeColumn, createColumnstoreIndex, createComputedColumn, createConstraint, createDatabaseSQL, createExpressionIndex, createFulltextIndex, createIdentityColumn, createIndex, createMaterializedView, createPartialIndex, createPartitionedTable, createSavepointSQL, createSchema, createSequence, createSpatialIndex, createStatisticsSQL, createTable, createTableAs, createTrigger, disableSystemVersioning, dropDatabaseSQL, dropSequence, dropTemporalTable, dropTrigger, refreshMaterializedView, renameTable |
| Introspection | assertColumnName, assertNoReturning, assertObjectName, hasSequence, hasTrigger, listSequences, tableRef |
| Other | buildCloneTableSql, buildCopyIntoSql, buildCredential, buildReseedIdentitySql, cloneTable, commentColumn, commentTable, copyInto, fabricCollate, fractionalPrecision, insert, nextSequenceValue, noIndexes, noSpatial, releaseSavepointSQL, rollbackToSavepointSQL, stAsText, stContains, stDWithin, stDistance, stGeomFromText, stIntersects, stWithin, updateStatisticsSQL, wroteMax |
| Model type | Fabric column |
|---|---|
STRING(n) / TEXT / ENUM / JSON | VARCHAR(n) / VARCHAR(MAX) / VARCHAR(255) / VARCHAR(MAX) — never NVARCHAR (the warehouse collation is UTF-8) |
CHAR(n) | CHAR(n) |
INTEGER / BIGINT / one-byte INTEGER | INT / BIGINT / SMALLINT (no TINYINT) |
FLOAT / DOUBLE / DECIMAL(p,s) | REAL / FLOAT / DECIMAL(p,s) |
BOOLEAN | BIT |
DATE / DATEONLY / TIME | DATETIME2(6) / DATE / TIME(6) — precision 0–6 is required, 7 does not exist |
BLOB / UUID | VARBINARY(MAX) / UNIQUEIDENTIFIER |
NVARCHAR, NCHAR,NTEXT, TEXT, IMAGE, TINYINT, DATETIME, SMALLDATETIME,DATETIMEOFFSET, MONEY, SMALLMONEY, XML, GEOMETRY, GEOGRAPHY, JSON,VECTOR, SQL_VARIANT, HIERARCHYID, ROWVERSION, BINARY, and aDATETIME2/TIME precision above 6.CREATE TABLE. PRIMARY KEY andUNIQUE exist only as NONCLUSTERED … NOT ENFORCED, FOREIGN KEY only asNOT ENFORCED, all added afterwards with ALTER TABLE. createTable() buildsawait db.dialect.createTable(
'Orders',
{
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
customerId: { type: DataTypes.BIGINT, references: { table: 'Customers', field: 'id' } },
},
{ schema: 'dbo', clusterBy: ['customerId'] },
);buildCreateTableStatements() returns the statements without sending them.IDENTITY is BIGINT only, with no seed or increment. An INTEGERautoIncrement key is widened to BIGINT (every value still fits); any otherclusterBy emits WITH (CLUSTER BY (...)) — one to four columns.addColumn accepts only nullable columns; changeColumn emitsALTER COLUMN (a preview feature in Fabric).db.dialect.buildSelectQuery({
tableName: 'Sales',
forTimestampAsOf: new Date('2024-03-13T19:39:35.28Z'),
});
// SELECT * FROM [Sales] OPTION (FOR TIMESTAMP AS OF '2024-03-13T19:39:35.280')Date is rendered in UTC with three fractional digits; a string must beYYYY-MM-DDTHH:MM:SS[.fff], anything else is refused.db.dialect.buildCtasSql(
'Recent',
{ tableName: 'Sales', where: { region: 'EU' } },
{ clusterBy: ['region'] },
);
// CREATE TABLE [Recent] WITH (CLUSTER BY ([region])) AS SELECT * FROM [Sales] WHERE [region] = 'EU'order and forTimestampAsOf are refused (a table has no order; todb.dialect.buildCloneTableSql('Employee', 'EmployeeUSA', { at: '2023-05-23T14:24:10' });
// CREATE TABLE [Employee] AS CLONE OF [EmployeeUSA] AT '2023-05-23T14:24:10'db.dialect.buildCopyIntoSql('Sales', {
schema: 'dbo',
from: 'https://acct.blob.core.windows.net/c/sales/*.parquet',
fileType: 'PARQUET',
credential: { identity: 'Shared Access Signature', secret: sas },
});default, CSV fieldNumber, JSONL jsonPath),FILE_TYPE (CSV/PARQUET/JSONL), CREDENTIAL (SAS, storage account key,ERRORFILE[_CREDENTIAL], MAXERRORS, COMPRESSION,FIELDQUOTE, FIELDTERMINATOR, ROWTERMINATOR, FIRSTROW, DATEFORMAT,ENCODING, PARSER_VERSION, MATCH_COLUMN_COUNT and IDENTITY_INSERT.https://; every enumerated option is checked.db.dialect.buildReseedIdentitySql('DimProduct', 'dbo'); // DBCC CHECKIDENT('dbo.DimProduct', RESEED)
db.dialect.createStatisticsSQL('Sales', 'st_region', ['region']);
db.dialect.updateStatisticsSQL('Sales');| Asked for | Why |
|---|---|
DEFAULT, CHECK, ON DELETE/ON UPDATE | No default or check constraints; keys are unenforced |
Any index (addIndex, partial, expression, columnstore, full-text, spatial) | Tables are Delta Parquet; use clusterBy |
| Sequences, triggers, computed columns | Not in Fabric |
| Materialized/indexed views, partitioned tables | Not in Fabric |
Temporal tables, FOR SYSTEM_TIME | Use forTimestampAsOf / clone at |
returning on any DML (the OUTPUT clause) | Not in Fabric |
| Recursive CTEs, lock hints | Not in Fabric (table-level locking, snapshot isolation) |
An isolation level other than SNAPSHOT | Fabric ignores it; refused rather than silently not honoured |
| Savepoints | Not supported |
CREATE DATABASE / DROP DATABASE | A warehouse is a Fabric item (portal / REST API) |
| Table/column comments | No sp_addextendedproperty |
Multi-column CREATE STATISTICS | Not supported manually |
Table/schema names with /, \, a trailing ., or over 128 characters | Not storable |
Adding a NOT NULL or IDENTITY column to an existing table | Recreate with CTAS |
capabilitiesOf() (src/transaction-support.ts),whereSupportOf() (src/query-builders/expression-render.ts),sqlObjectCapabilitiesOf() (src/sql-objects/capabilities.ts) and the| Capability | fabric |
|---|---|
| Transactions atomic | yes |
| Savepoints | no — a nested transaction() throws |
| Isolation | up to SERIALIZABLE; native levels SNAPSHOT |
| Transaction modes | read-only no; deferrable no; constraint deferral no |
| RETURNING | refused — The OUTPUT clause (returning on INSERT) is not supported by Microsoft Fabric Data Warehouse. Re-select the rows after the statement. IDENTITY values are uniqu |
| Upsert | MERGE INTO … WHEN MATCHED / WHEN NOT MATCHED |
| JSON column | VARCHAR(MAX) (JSONB → VARCHAR(MAX)) |
| Vector column | refused — The VECTOR data type is not supported by Microsoft Fabric Data Warehouse. There is no equivalent. |
| Array column | refused — The ARRAY data type is not supported by Microsoft Fabric Data Warehouse. Neither Fabric nor SQL Server has it; store it as VARCHAR (JSON or text) or VARBINARY, |
| WHERE builder | 18 operator keys; $and/$or/$not; $exists: yes; $in subquery: no; expression operands: no |
| SQL objects | family mssql: triggers no; procedures yes; functions multiStatement; materialized views emulated (indexedView); sequences yes; enums check; RLS no |
| Streaming | queryStream() present; LISTEN absent; createExtension() present |
tests/dialects/fabric.test.ts exercises the dialect with a mocked driver, so nothing touches a server.