@formancy/data-sqlserver 0.0.0-stage → 0.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/LICENSE.md +156 -0
- package/NOTICE +9 -0
- package/README.md +550 -2
- package/dist/index.d.mts +115 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2797 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["SQL","SQL","SQL","named","column","DEFINITION_MOVED","named"],"sources":["../src/discovery/account.ts","../src/discovery/catalog.ts","../src/discovery/checks.ts","../src/discovery/access.ts","../src/discovery/types.ts","../src/discovery/columns.ts","../src/discovery/foreign-keys.ts","../src/discovery/keys.ts","../src/discovery/objects.ts","../src/discovery/visibility.ts","../src/discovery/referenced-by.ts","../src/discovery/row-security.ts","../src/version.ts","../src/discovery/discover.ts","../src/adapter.ts","../src/sql/statement.ts","../src/sql/values.ts","../src/sql/quote.ts","../src/sql/order.ts","../src/sql/search.ts","../src/sql/filters.ts","../src/lookups/statements.ts","../src/lookups/lookups.ts","../src/records/definition.ts","../src/records/statements.ts","../src/records/delete.ts","../src/records/errors.ts","../src/records/list.ts","../src/records/records.ts","../src/connect.ts"],"sourcesContent":["import type { DiscoveryAccount } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\n\n/**\n * Whose snapshot this is (0027).\n *\n * USER_NAME() is the database principal every permission and every security\n * predicate is evaluated for, and so the one the fingerprint carries.\n * ORIGINAL_LOGIN() is who connected, for a person reading the report: a login\n * mapped to a user of another name reports both (B13), and `sa` -- or any\n * member of sysadmin, or the database's owner -- is `dbo` in the database.\n * ORIGINAL_LOGIN rather than SUSER_SNAME, which an EXECUTE AS would change.\n */\nconst SQL = 'select user_name() as [user], original_login() as login'\n\nexport async function readAccount(pool: ConnectionPool): Promise<DiscoveryAccount> {\n const result = await pool.request().query<{ user: string | null; login: string | null }>(SQL)\n const row = result.recordset[0]\n // A NULL is not reached on a connection with a database context; it is\n // passed on as empty, and createSnapshot refuses an account without a name.\n return { user: row?.user ?? '', login: row?.login ?? '' }\n}\n","import type { CoverageAspect } from '@formancy/data-core'\nimport mssql from 'mssql'\nimport type { ConnectionPool, IRecordSet } from 'mssql'\n\n/**\n * A gap found while reading one concern, before the object it belongs to has\n * a name: the concern knows the object_id, the assembler knows the ref.\n */\nexport interface ObjectGap {\n objectId: number\n aspect: CoverageAspect\n detail: string\n}\n\n/** What one catalog concern found, by object_id, and what it could not read. */\nexport interface Found<T> {\n byObject: Map<number, T>\n gaps: ObjectGap[]\n}\n\n/** The objects discovery describes, of sys.objects `o`: user tables and views. Shared with the root's definition (0041). */\nexport const DESCRIBED_OBJECT = `o.type in ('U', 'V') and o.is_ms_shipped = 0`\n\n/**\n * Runs one catalog query over the tables and views in scope.\n *\n * Each schema is bound as its own parameter, `@schema0`, `@schema1`, and the\n * query text receives only those generated names: a schema name is a value\n * and never part of the statement, whatever it contains. A list of\n * parameters rather than one JSON or delimited parameter, because OPENJSON and\n * STRING_SPLIT need compatibility level 130 and a customer's database is often\n * older than its server.\n *\n * `scoped` is a subquery of the object_ids in scope: user tables and views\n * whose schema the database's own collation matches to a scope name. Matching\n * by the database's rules, not by exact spelling, because on a\n * case-insensitive database `SALES` IS `sales`, and reporting it absent would\n * be the silent answer.\n */\nexport async function queryScope<Row>(\n pool: ConnectionPool,\n schemas: readonly string[],\n sql: (scoped: string, schemaList: string) => string,\n): Promise<IRecordSet<Row>> {\n const request = pool.request()\n const names = schemas.map((schema, index) => {\n // nvarchar(max), never nvarchar(128): a declared length shorter than the\n // value is truncated, and a truncated name can match a different schema.\n request.input(`schema${String(index)}`, mssql.NVarChar(mssql.MAX), schema)\n return `@schema${String(index)}`\n })\n const schemaList = names.join(', ')\n const scoped = `(select o.object_id from sys.objects o join sys.schemas s on s.schema_id = o.schema_id\n where ${DESCRIBED_OBJECT} and s.name in (${schemaList}))`\n const result = await request.query<Row>(sql(scoped, schemaList))\n return result.recordset\n}\n\n/** Rows grouped by a key, each group in the order the query returned it. */\nexport function groupBy<Row, Key>(rows: readonly Row[], key: (row: Row) => Key): Map<Key, Row[]> {\n const groups = new Map<Key, Row[]>()\n for (const row of rows) {\n const group = groups.get(key(row))\n if (group === undefined) groups.set(key(row), [row])\n else group.push(row)\n }\n return groups\n}\n\nexport const byObjectId = (row: { object_id: number }): number => row.object_id\n","import type { CheckMeta } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport type { Found, ObjectGap } from './catalog.js'\nimport { byObjectId, groupBy, queryScope } from './catalog.js'\n\ninterface CheckRow {\n object_id: number\n name: string\n definition: string | null\n is_disabled: boolean\n is_not_trusted: boolean\n}\n\n/**\n * Check constraints, with the expression as SQL Server stored it -- which is\n * not as it was written: `status in ('draft', 'placed', 'shipped')` comes back\n * as `([status]='shipped' OR [status]='placed' OR [status]='draft')`.\n *\n * `enforced` is not `is_disabled`: ALTER TABLE … NOCHECK CONSTRAINT stops the\n * check for new rows. `validated` is not `is_not_trusted`, which WITH NOCHECK\n * sets and which disabling sets too, so a disabled check is never validated;\n * a WITH NOCHECK one is enforced and not validated, and only `is_disabled`\n * tells the two apart (0026). `is_not_for_replication` is not read: it exempts\n * a replication agent's writes, which are not a form's.\n */\nconst SQL = (scoped: string): string => `\n select cc.parent_object_id as object_id, cc.name, cc.definition, cc.is_disabled, cc.is_not_trusted\n from sys.check_constraints cc\n where cc.parent_object_id in ${scoped}`\n\nexport async function readChecks(pool: ConnectionPool, schemas: readonly string[]): Promise<Found<CheckMeta[]>> {\n const rows = await queryScope<CheckRow>(pool, schemas, SQL)\n const gaps: ObjectGap[] = []\n const byObject = new Map<number, CheckMeta[]>()\n for (const [objectId, group] of groupBy(rows, byObjectId)) {\n byObject.set(\n objectId,\n group.map((row) => {\n // A check always has an expression. NULL is SQL Server declining to\n // show it to an account without VIEW DEFINITION.\n if (row.definition === null) {\n gaps.push({ objectId, aspect: 'checks', detail: `${row.name}: the expression is hidden without VIEW DEFINITION` })\n }\n return { name: row.name, expression: row.definition, enforced: !row.is_disabled, validated: !row.is_not_trusted }\n }),\n )\n }\n return { byObject, gaps }\n}\n","import type { ColumnAccess, ObjectAccess } from '@formancy/data-core'\n\n/**\n * The object a column belongs to, as HAS_PERMS_BY_NAME must be given it:\n * QUOTENAME'd, schema and name each. The function PARSES the name, so a raw\n * `it's [odd]` answers NULL (measured, B7), and a name that parses as a\n * different object would answer for that one.\n */\nconst OBJECT = `quotename(object_schema_name(c.object_id)) + N'.' + quotename(object_name(c.object_id))`\n\n/**\n * What the account may do with each column, as the server's own privilege\n * check answers it (0027): spliced into the columns query, so every column\n * the list holds has an answer -- never a column without one, which\n * `createSnapshot` would refuse as taken before 0027. That is all one read\n * buys. HAS_PERMS_BY_NAME looks the column up by name when it runs, and a\n * name that does not exist answers 0, not NULL: a concurrent rename can\n * therefore report a granted column as not granted (measured in review on\n * mssql/server:2022-latest, 2026-10-09: 4 wrong of 394 checks run against\n * 400 sp_rename round trips). That fails closed -- the\n * form leaves out or does not write a column it could have -- and drift\n * review sees the column's access come back at the next snapshot.\n *\n * SELECT and UPDATE are asked per column, because SQL Server grants and\n * denies both per column, and HAS_PERMS_BY_NAME applies the precedence the\n * server applies: a column DENY under a table GRANT is a no, a column GRANT\n * under a table DENY a yes, and a later table GRANT removes an earlier column\n * DENY (each measured against a real read, B8). INSERT is asked of the object:\n * the server refuses a column list on an INSERT grant or deny (1020), so every\n * column of an object the account may insert into is insertable.\n *\n * The column is QUOTENAME'd too. HAS_PERMS_BY_NAME parses the sub-securable\n * as an identifier: `group` happens to answer either way, `it's [odd]` raw is\n * NULL and quoted is the right answer (B7). A misparse is not always NULL --\n * a column that does not exist answers 0 -- so quoting is the defence, and\n * the NULL check below catches only the misparse that shows.\n */\nexport const ACCESS_COLUMNS = `${OBJECT} as access_object,\n has_perms_by_name(${OBJECT}, N'OBJECT', N'SELECT', quotename(c.name), N'COLUMN') as can_select,\n has_perms_by_name(${OBJECT}, N'OBJECT', N'INSERT') as can_insert,\n has_perms_by_name(${OBJECT}, N'OBJECT', N'UPDATE', quotename(c.name), N'COLUMN') as can_update`\n\nexport interface AccessRow {\n /** The securable name the checks were given, for an error that has to name it. */\n access_object: string | null\n name: string\n can_select: number | null\n can_insert: number | null\n can_update: number | null\n}\n\nfunction held(row: AccessRow, capability: keyof ColumnAccess, answer: number | null): boolean {\n // NULL is HAS_PERMS_BY_NAME saying it could not resolve what it was asked\n // about. Read as \"no\", it would be a privilege the snapshot denies for a\n // reason nobody can see; this adapter quotes every name, so a NULL is a\n // defect here, and it says which name.\n if (answer === null) {\n throw new Error(`HAS_PERMS_BY_NAME could not resolve column ${row.name} of ${row.access_object ?? '(unnamed object)'} for ${capability.toUpperCase()}`)\n }\n return answer === 1\n}\n\n/** One column's access from the row the columns query returned. */\nexport function toAccess(row: AccessRow): ColumnAccess {\n return {\n select: held(row, 'select', row.can_select),\n insert: held(row, 'insert', row.can_insert),\n update: held(row, 'update', row.can_update),\n }\n}\n\n/**\n * Whether the account may DELETE from an object of sys.objects `o` in\n * schema `s`, as the server's own check answers it (0049), spliced into the\n * objects query so every object has an answer. QUOTENAME'd, schema and name\n * each, for the reason `OBJECT` above gives. Grants through a role count as\n * the server counts them, and a DENY wins over a GRANT as it does there.\n *\n * DELETE alone deletes nothing by a key: a WHERE or an OUTPUT that names a\n * column needs SELECT on it too, which the columns' access says. Measured on\n * mcr.microsoft.com/mssql/server:2022-latest (16.0.4295.3), 2026-10-11 (P1):\n * a user with DELETE and no SELECT runs `delete … where 1 = 0` and is refused\n * 229 for `where id = 1`; given SELECT on id, `where id = 1` and `output\n * deleted.id` run, and `output deleted.v` is refused 230. Over every table of\n * the fixture, as the owner, the reader and a writer granted DELETE on order\n * and order_line, each answer here was the one `delete … where 1 = 0` got\n * (`discovery-access.integration.test.ts`); a view that cannot be updated is\n * refused 4405 before any privilege is asked, so a view's answer is its\n * grant's.\n */\nexport const OBJECT_ACCESS = `quotename(s.name) + N'.' + quotename(o.name) as access_object,\n has_perms_by_name(quotename(s.name) + N'.' + quotename(o.name), N'OBJECT', N'DELETE') as can_delete`\n\nexport interface ObjectAccessRow {\n access_object: string | null\n can_delete: number | null\n}\n\n/** An object's access from the row the objects query returned. A NULL is a name the check could not resolve: a defect, said, as for a column. */\nexport function toObjectAccess(row: ObjectAccessRow): ObjectAccess {\n if (row.can_delete === null) throw new Error(`HAS_PERMS_BY_NAME could not resolve ${row.access_object ?? '(unnamed object)'} for DELETE`)\n return { delete: row.can_delete === 1 }\n}\n","import type { NormalizedType, TextLengthUnit } from '@formancy/data-core'\n\n/** What sys.columns and sys.types say about one column's type. */\nexport interface TypeFacts {\n /** sys.types.name for the column's user_type_id; `null` when the type is hidden from this account. */\n typeName: string | null\n typeSchema: string | null\n isUserDefined: boolean | null\n /**\n * The system type behind it, from sys.types for the column's system_type_id.\n * `null` for CLR types -- geography, geometry, hierarchyid -- whose\n * system_type_id 240 names no row in sys.types.\n */\n systemName: string | null\n /** In bytes, and -1 for max. */\n maxLength: number\n precision: number\n scale: number\n /**\n * COLLATIONPROPERTY(collation, 'CodePage') of the column's own collation:\n * 65001 for a UTF-8 one, 1252 for the Latin1 ones, 932 for Japanese. `null`\n * for a type with no collation, and for a collation the server cannot name.\n */\n codePage: number | null\n}\n\nexport interface ColumnType {\n /** As the database spells it, for a person reading a report. */\n databaseType: string\n type: NormalizedType\n /** The column's declared type is a user-defined type this account cannot see. */\n hidden: boolean\n}\n\nconst UNSUPPORTED: NormalizedType = { kind: 'unsupported' }\n\ntype Normalize = (facts: TypeFacts) => NormalizedType\n\nconst length = (bytes: number, bytesPerUnit: number): number | null => (bytes === -1 ? null : bytes / bytesPerUnit)\nconst integer = (min: string, max: string): Normalize => () => ({ kind: 'integer', min, max })\nconst decimal: Normalize = (facts) => ({ kind: 'decimal', precision: facts.precision, scale: facts.scale })\nconst timestamp = (withTimeZone: boolean): Normalize => (facts) => ({ kind: 'timestamp', withTimeZone, precision: facts.scale })\n\n/** The code page of every UTF-8 collation. */\nconst UTF8_CODE_PAGE = 65001\n\n/** char and varchar count bytes: of UTF-8 under a UTF-8 collation, of the code page under any other, and a NULL code page is the weaker claim. */\nconst byteUnit = (facts: TypeFacts): TextLengthUnit => (facts.codePage === UTF8_CODE_PAGE ? 'utf8-bytes' : 'code-page-bytes')\n/** nchar and nvarchar count UTF-16 code units, two bytes each, under every collation, a UTF-8 one included. */\nconst codeUnits = (): TextLengthUnit => 'utf16-code-units'\n\nconst text =\n (unit: (facts: TypeFacts) => TextLengthUnit, bytesPerUnit: number, fixedLength: boolean): Normalize =>\n (facts) => ({ kind: 'text', maxLength: length(facts.maxLength, bytesPerUnit), lengthUnit: unit(facts), fixedLength })\nconst binary =\n (fixedLength: boolean): Normalize =>\n (facts) => ({ kind: 'binary', maxLength: length(facts.maxLength, 1), fixedLength })\n\n/**\n * The system types this adapter has a normalised meaning for. Anything else --\n * xml, sql_variant, the CLR types, the deprecated text/ntext/image, a type a\n * later server adds -- is `unsupported`: reported, never dropped (0004).\n *\n * The lengths are the catalog's BYTES turned into the unit the type counts,\n * and the unit is said (0026): nchar and nvarchar store UTF-16 code units, two\n * bytes each, so nvarchar(200) is 400 in sys.columns and 200 here. char and\n * varchar count bytes -- of UTF-8 under a UTF-8 collation, where é is two,\n * and of the collation's code page under any other, which is one per\n * character on 1252 and one or two on 932.\n *\n * binary(n) is fixed: it pads a shorter value with zero bytes to n, so 0x01\n * written to binary(4) reads 0x01000000. varbinary keeps what it is given.\n *\n * Temporal precision is the catalog's scale for every temporal type, which is\n * the number of fractional-second digits the server writes. For datetime that\n * is 3 though it keeps 1/300 s, and for smalldatetime 0 though it keeps whole\n * minutes; the contract has no way to say either, and 0007 records the choice.\n *\n * A Map rather than an object, so that a CLR type somebody named `toString`\n * finds nothing here rather than Object.prototype.toString.\n */\nconst BY_SYSTEM_TYPE: ReadonlyMap<string, Normalize> = new Map<string, Normalize>([\n ['bit', () => ({ kind: 'boolean' })],\n ['tinyint', integer('0', '255')],\n ['smallint', integer('-32768', '32767')],\n ['int', integer('-2147483648', '2147483647')],\n ['bigint', integer('-9223372036854775808', '9223372036854775807')],\n ['decimal', decimal],\n ['numeric', decimal],\n // The catalog's own precision and scale: 19,4 and 10,4. The contract's\n // decimal cannot say that money stops at 922,337,203,685,477.5807; a value\n // past it is refused by the server, loudly.\n ['money', decimal],\n ['smallmoney', decimal],\n // float(1..24) is catalogued as real and float(25..53) as float.\n ['float', () => ({ kind: 'float', bits: 64 })],\n ['real', () => ({ kind: 'float', bits: 32 })],\n ['date', () => ({ kind: 'date' })],\n ['time', (facts) => ({ kind: 'time', precision: facts.scale })],\n ['datetime2', timestamp(false)],\n ['datetimeoffset', timestamp(true)],\n ['datetime', timestamp(false)],\n ['smalldatetime', timestamp(false)],\n ['char', text(byteUnit, 1, true)],\n ['varchar', text(byteUnit, 1, false)],\n ['nchar', text(codeUnits, 2, true)],\n ['nvarchar', text(codeUnits, 2, false)],\n ['uniqueidentifier', () => ({ kind: 'uuid' })],\n ['binary', binary(true)],\n ['varbinary', binary(false)],\n // rowversion's catalog name is its deprecated synonym, timestamp. It is a\n // counter, never a clock.\n ['timestamp', () => ({ kind: 'rowversion' })],\n])\n\n/** The suffix a system type is declared with, from the catalog's numbers. */\nfunction suffix(systemName: string, facts: TypeFacts): string {\n switch (systemName) {\n case 'char':\n case 'varchar':\n case 'binary':\n case 'varbinary':\n return `(${facts.maxLength === -1 ? 'max' : String(facts.maxLength)})`\n case 'nchar':\n case 'nvarchar':\n return `(${facts.maxLength === -1 ? 'max' : String(facts.maxLength / 2)})`\n case 'decimal':\n case 'numeric':\n return `(${String(facts.precision)},${String(facts.scale)})`\n case 'time':\n case 'datetime2':\n case 'datetimeoffset':\n return `(${String(facts.scale)})`\n default:\n return ''\n }\n}\n\n/**\n * How a person would recognise the declared type: `nvarchar(200)`, an alias\n * type by its qualified name, `sysname` as itself, and `rowversion` rather\n * than the catalog's `timestamp`, which reads as a clock and is not one.\n */\nfunction spell(facts: TypeFacts, systemName: string | null): string {\n if (facts.typeName === null) return systemName === null ? 'unknown' : systemName + suffix(systemName, facts)\n if (facts.isUserDefined === true) return facts.typeSchema === null ? facts.typeName : `${facts.typeSchema}.${facts.typeName}`\n if (facts.typeName === 'timestamp') return 'rowversion'\n if (facts.typeName !== systemName) return facts.typeName\n return facts.typeName + suffix(facts.typeName, facts)\n}\n\n/**\n * A column's type, normalised from what this account can see of it.\n *\n * The system type comes from the column's system_type_id, which is visible\n * even when the declared user-defined type is not: a type is a securable of\n * its own, and an account may read a table without any permission on the type\n * of one of its columns. Normalising from the declared type would lose that\n * column's meaning; joining to it would lose the column.\n */\nexport function normalizeType(facts: TypeFacts): ColumnType {\n const systemName = facts.systemName ?? facts.typeName\n const normalize = systemName === null ? undefined : BY_SYSTEM_TYPE.get(systemName)\n return {\n databaseType: spell(facts, systemName),\n type: normalize === undefined ? UNSUPPORTED : normalize(facts),\n hidden: facts.typeName === null,\n }\n}\n","import type { ColumnMeta, DescribedColumn, Generation } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport type { AccessRow } from './access.js'\nimport { ACCESS_COLUMNS, toAccess } from './access.js'\nimport type { Found, ObjectGap } from './catalog.js'\nimport { byObjectId, groupBy, queryScope } from './catalog.js'\nimport { normalizeType } from './types.js'\n\n/** A column's definition, as the definition's columns are read (0041): everything discovery reads of it but its access and its comment. */\nexport interface ColumnDefinitionRow {\n object_id: number\n column_id: number\n name: string\n type_name: string | null\n type_schema: string | null\n is_user_defined: boolean | null\n system_name: string | null\n max_length: number\n precision: number\n scale: number\n /** The code page of the column's collation; `null` for a type that has none, and for a collation the server does not know. */\n code_page: number | null\n is_nullable: boolean\n is_identity: boolean\n is_computed: boolean\n generated_always_type: number\n default_object_id: number\n default_definition: string | null\n}\n\ninterface ColumnRow extends ColumnDefinitionRow, AccessRow {\n default_name: string | null\n comment: string | null\n}\n\n/**\n * Columns, their types, how they are generated, their defaults and comments.\n *\n * Every join is a LEFT join, because each joined row is something this account\n * may not be allowed to see while it may see the column: the declared type\n * (a user-defined type is a securable of its own), the default's definition,\n * the comment. An inner join would drop the column, and a dropped column reads\n * as a table that never had it.\n *\n * A default is read through OBJECT_DEFINITION rather than\n * sys.default_constraints, because a default bound with the deprecated\n * sp_bindefault is a default too and is not a constraint. Both are NULL\n * without VIEW DEFINITION. Identity and computed come from sys.columns' own\n * flags: sys.identity_columns and sys.computed_columns add the seed, the\n * increment and the expression, none of which the contract carries.\n *\n * The code page is read from the column's own collation, never the\n * database's: a column may be declared under any collation, and the fixture's\n * UTF-8 varchar sits in a database whose default is code page 1252. It says\n * what a char or varchar length counts (0026).\n *\n * And what the account may do with each column, in the same statement\n * (access.ts, 0027).\n */\nconst SQL = (scoped: string): string => `\n select ${COLUMN_DEFINITION},\n object_name(c.default_object_id) as default_name,\n cast(ep.value as nvarchar(max)) as comment,\n ${ACCESS_COLUMNS}\n from ${COLUMN_SOURCE}\n left join sys.extended_properties ep\n on ep.class = 1 and ep.major_id = c.object_id and ep.minor_id = c.column_id and ep.name = N'MS_Description'\n where c.object_id in ${scoped}\n order by c.object_id, c.column_id`\n\n/**\n * What a column's definition is read from, of sys.columns `c`: its type, how\n * it is generated, its default. Shared with the root's definition (0041),\n * which reads exactly these, so a fact added here is the definition's too;\n * discovery adds the access, the comment and the default's name.\n */\nexport const COLUMN_DEFINITION = `c.object_id, c.column_id, c.name,\n t.name as type_name, schema_name(t.schema_id) as type_schema, t.is_user_defined,\n st.name as system_name,\n c.max_length, c.precision, c.scale,\n convert(int, collationproperty(c.collation_name, 'CodePage')) as code_page,\n c.is_nullable, c.is_identity, c.is_computed, c.generated_always_type,\n c.default_object_id,\n object_definition(c.default_object_id) as default_definition`\n\nexport const COLUMN_SOURCE = `sys.columns c\n left join sys.types t on t.user_type_id = c.user_type_id\n left join sys.types st on st.user_type_id = c.system_type_id`\n\n/** The name sys.types gives rowversion's system type: its deprecated synonym. */\nconst ROWVERSION_SYSTEM_TYPE = 'timestamp'\n\n/** One bracketed name as SQL Server stores it in a definition, a `]` inside it doubled. */\nconst BRACKETED = String.raw`\\[(?:[^\\]]|\\]\\])+\\]`\n\n/**\n * A default that is exactly the next value of one sequence, as SQL Server\n * stores the definition: `(NEXT VALUE FOR [schema].[name])`, however it was\n * written. One that computes with the value has more around it.\n */\nconst NEXT_VALUE = new RegExp(String.raw`^\\(NEXT VALUE FOR (?:${BRACKETED}\\.){0,2}${BRACKETED}\\)$`, 'i')\n\n/**\n * How the column gets its value.\n *\n * IDENTITY is `identity-always`: an insert that names it is refused (544)\n * unless IDENTITY_INSERT is on, which needs ALTER on the table, and an update\n * of it is refused outright (8102). SQL Server has no BY DEFAULT identity; a\n * default of NEXT VALUE FOR a sequence is what takes its place, and behaves as\n * PostgreSQL's does: it numbers a row an insert leaves out, takes a value\n * given to it, and a value given by hand collides with the sequence later\n * (2627, measured). It is `identity-by-default`, and keeps its default (0026).\n * Its definition is read without VIEW DEFINITION only as NULL, and then the\n * column cannot be told from an ordinary default: it is `none`, and the\n * snapshot's `defaults` gap says the definition was hidden.\n *\n * A period column (GENERATED ALWAYS AS ROW START or END) is written by the\n * database and refused in an insert, which is what `computed` tells a form\n * generator; `none` would offer it as an input.\n */\nfunction generation(row: ColumnDefinitionRow): Generation {\n if (row.is_identity) return 'identity-always'\n if (row.system_name === ROWVERSION_SYSTEM_TYPE) return 'rowversion'\n if (row.is_computed || row.generated_always_type !== 0) return 'computed'\n if (row.default_definition !== null && NEXT_VALUE.test(row.default_definition)) return 'identity-by-default'\n return 'none'\n}\n\n/**\n * A column as its definition describes it, without access, comment or gaps:\n * what the root's description reports of it (0041), and what discovery\n * reports with those added.\n */\nexport function describedColumn(row: ColumnDefinitionRow): DescribedColumn {\n const { databaseType, type } = typed(row)\n return {\n name: row.name,\n ordinal: row.column_id,\n databaseType,\n type,\n nullable: row.is_nullable,\n hasDefault: row.default_object_id !== 0,\n defaultExpression: row.default_definition,\n generated: generation(row),\n }\n}\n\nfunction typed(row: ColumnDefinitionRow): ReturnType<typeof normalizeType> {\n return normalizeType({\n typeName: row.type_name,\n typeSchema: row.type_schema,\n isUserDefined: row.is_user_defined,\n systemName: row.system_name,\n maxLength: row.max_length,\n precision: row.precision,\n scale: row.scale,\n codePage: row.code_page,\n })\n}\n\nfunction toColumn(row: ColumnRow, gaps: ObjectGap[]): ColumnMeta {\n const column = describedColumn(row)\n if (typed(row).hidden) {\n gaps.push({\n objectId: row.object_id,\n aspect: 'columns',\n detail:\n column.type.kind === 'unsupported'\n ? `${row.name}: its type is hidden from this account, so it is reported as unsupported`\n : `${row.name}: its user-defined type is hidden from this account, so it is reported as its base type ${column.databaseType}`,\n })\n }\n // A default always has a definition. NULL means this account may not read\n // it -- SQL Server returns NULL rather than refusing -- and that is a gap,\n // not an absence.\n if (column.hasDefault && row.default_definition === null) {\n gaps.push({\n objectId: row.object_id,\n aspect: 'defaults',\n detail: `${row.name}: the definition of its default ${row.default_name ?? '(unnamed)'} is hidden without VIEW DEFINITION`,\n })\n }\n return { ...column, comment: row.comment, access: toAccess(row) }\n}\n\nexport async function readColumns(pool: ConnectionPool, schemas: readonly string[]): Promise<Found<ColumnMeta[]>> {\n const rows = await queryScope<ColumnRow>(pool, schemas, SQL)\n const gaps: ObjectGap[] = []\n const byObject = new Map<number, ColumnMeta[]>()\n for (const [objectId, group] of groupBy(rows, byObjectId)) {\n byObject.set(objectId, group.map((row) => toColumn(row, gaps)))\n }\n return { byObject, gaps }\n}\n","import type { ForeignKeyMeta, ForeignKeyTarget, ReferentialAction } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport type { Found, ObjectGap } from './catalog.js'\nimport { byObjectId, groupBy, queryScope } from './catalog.js'\n\nexport interface ForeignKeyRow {\n object_id: number\n key_id: number\n name: string\n is_disabled: boolean\n is_not_trusted: boolean\n delete_referential_action: number\n update_referential_action: number\n referenced_schema: string | null\n referenced_name: string | null\n column_name: string\n referenced_column: string | null\n}\n\n/**\n * Foreign keys, one row per column pair, in constraint_column_id order -- the\n * pairing of a composite key.\n *\n * The target is LEFT joined, because what SQL Server shows an account that\n * may read the referencing table and not the referenced one is precise and\n * partial: the key, its flags, its own columns, and a referenced_object_id\n * whose OBJECT_NAME is NULL and whose columns COL_NAME cannot name. An inner\n * join would drop the key -- \"no relationship\", the one wrong answer -- so the\n * key is reported with an unknown target and a gap says why.\n */\nexport const FOREIGN_KEYS_SQL = (scoped: string): string => `\n select fk.parent_object_id as object_id, fk.object_id as key_id, fk.name, fk.is_disabled, fk.is_not_trusted,\n fk.delete_referential_action, fk.update_referential_action,\n rs.name as referenced_schema, ro.name as referenced_name,\n pc.name as column_name, rc.name as referenced_column\n from sys.foreign_keys fk\n join sys.foreign_key_columns fkc on fkc.constraint_object_id = fk.object_id\n join sys.columns pc on pc.object_id = fkc.parent_object_id and pc.column_id = fkc.parent_column_id\n left join sys.objects ro on ro.object_id = fk.referenced_object_id\n left join sys.schemas rs on rs.schema_id = ro.schema_id\n left join sys.columns rc on rc.object_id = fkc.referenced_object_id and rc.column_id = fkc.referenced_column_id\n where fk.parent_object_id in ${scoped}\n order by fk.parent_object_id, fk.object_id, fkc.constraint_column_id`\n\n/** sys.foreign_keys' *_referential_action codes. SQL Server has no RESTRICT. */\nconst ACTIONS: readonly ReferentialAction[] = ['no-action', 'cascade', 'set-null', 'set-default']\n\nexport function action(code: number, name: string): ReferentialAction {\n const found = ACTIONS[code]\n // Unreached on the servers tested: SQL Server 2022 has exactly these four.\n // A later one with a fifth fails loudly here rather than being reported as\n // the nearest thing.\n if (found === undefined) throw new Error(`${name} has referential action ${String(code)}, which this adapter does not know`)\n return found\n}\n\n/**\n * The target, or `null` when any part of it is hidden: a schema and a name\n * and every paired column, or nothing. Half a target -- a table without its\n * columns -- would pair the key with the wrong columns downstream.\n */\nfunction target(rows: readonly ForeignKeyRow[]): ForeignKeyTarget | null {\n const [first] = rows as [ForeignKeyRow, ...ForeignKeyRow[]]\n const columns: string[] = []\n for (const row of rows) {\n if (row.referenced_column === null) return null\n columns.push(row.referenced_column)\n }\n if (first.referenced_schema === null || first.referenced_name === null) return null\n return { table: { schema: first.referenced_schema, name: first.referenced_name }, columns }\n}\n\nfunction toForeignKey(rows: readonly ForeignKeyRow[], gaps: ObjectGap[]): ForeignKeyMeta {\n const [first] = rows as [ForeignKeyRow, ...ForeignKeyRow[]]\n const references = target(rows)\n if (references === null) {\n gaps.push({\n objectId: first.object_id,\n aspect: 'foreign-keys',\n detail: `${first.name} references a table this account cannot see: the key and its own columns are visible, the name of its target and of the target's columns are not`,\n })\n }\n\n return {\n name: first.name,\n columns: rows.map((row) => row.column_name),\n references,\n onUpdate: action(first.update_referential_action, first.name),\n onDelete: action(first.delete_referential_action, first.name),\n // A disabled key is not checked for new rows, and SQL Server marks it\n // untrusted as well; WITH NOCHECK leaves it enabled and untrusted.\n enforced: !first.is_disabled,\n validated: !first.is_not_trusted,\n }\n}\n\nexport async function readForeignKeys(pool: ConnectionPool, schemas: readonly string[]): Promise<Found<ForeignKeyMeta[]>> {\n const rows = await queryScope<ForeignKeyRow>(pool, schemas, FOREIGN_KEYS_SQL)\n const gaps: ObjectGap[] = []\n const byObject = new Map<number, ForeignKeyMeta[]>()\n for (const [objectId, group] of groupBy(rows, byObjectId)) byObject.set(objectId, foreignKeysOf(group, gaps))\n return { byObject, gaps }\n}\n\n/** One object's foreign keys from its rows, in the query's order: discovery's, and the root's description's (0041), which keeps no gaps. */\nexport function foreignKeysOf(rows: readonly ForeignKeyRow[], gaps: ObjectGap[]): ForeignKeyMeta[] {\n return [...groupBy(rows, (row) => row.key_id).values()].map((keyRows) => toForeignKey(keyRows, gaps))\n}\n","import type { KeyMeta } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport { byObjectId, groupBy, queryScope } from './catalog.js'\n\nexport interface KeyRow {\n object_id: number\n key_id: number\n name: string\n is_primary_key: boolean\n column_name: string\n}\n\nexport interface Keys {\n primaryKey: KeyMeta | null\n uniqueKeys: KeyMeta[]\n}\n\n/**\n * Primary keys and unique constraints, each in its key order.\n *\n * key_ordinal, never column_id: a composite key declared (tenant_id,\n * customer_no) over columns created the other way round pairs by the key's\n * order, and a foreign key into it pairs by the same. Ordered by numbers only,\n * so the database's collation never decides an order here.\n *\n * Unique constraints only, not unique indexes: a unique index may be filtered,\n * and a filtered index is not a key.\n */\nexport const KEYS_SQL = (scoped: string): string => `\n select kc.parent_object_id as object_id, kc.object_id as key_id, kc.name,\n cast(case kc.type when 'PK' then 1 else 0 end as bit) as is_primary_key,\n c.name as column_name\n from sys.key_constraints kc\n join sys.index_columns ic on ic.object_id = kc.parent_object_id and ic.index_id = kc.unique_index_id\n join sys.columns c on c.object_id = ic.object_id and c.column_id = ic.column_id\n where kc.parent_object_id in ${scoped} and ic.key_ordinal > 0\n order by kc.parent_object_id, kc.object_id, ic.key_ordinal`\n\n/**\n * Each table's keys, by object_id. Keys of a table this account can see are\n * visible with it, so there is never a gap to report here.\n */\nexport async function readKeys(pool: ConnectionPool, schemas: readonly string[]): Promise<Map<number, Keys>> {\n const rows = await queryScope<KeyRow>(pool, schemas, KEYS_SQL)\n const byObject = new Map<number, Keys>()\n for (const [objectId, group] of groupBy(rows, byObjectId)) byObject.set(objectId, keysOf(group))\n return byObject\n}\n\n/** One object's keys from its rows, in the query's order: discovery's, and the root's description's (0041). */\nexport function keysOf(rows: readonly KeyRow[]): Keys {\n const keys: Keys = { primaryKey: null, uniqueKeys: [] }\n for (const keyRows of groupBy(rows, (row) => row.key_id).values()) {\n const [first] = keyRows as [KeyRow, ...KeyRow[]]\n const key: KeyMeta = { name: first.name, columns: keyRows.map((row) => row.column_name) }\n if (first.is_primary_key) keys.primaryKey = key\n else keys.uniqueKeys.push(key)\n }\n return keys\n}\n","import type { ObjectMeta } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport type { ObjectAccessRow } from './access.js'\nimport { OBJECT_ACCESS, toObjectAccess } from './access.js'\nimport { queryScope } from './catalog.js'\n\ninterface ObjectRow extends ObjectAccessRow {\n object_id: number\n schema_name: string\n object_name: string\n kind: 'table' | 'view'\n comment: string | null\n}\n\n/**\n * The tables and views in scope, with their MS_Description and whether the\n * account may delete from each (access.ts, 0049).\n *\n * Only what this account holds some permission on: SQL Server filters\n * sys.objects without a word. Whether that filter can have hidden anything is\n * the schemas concern's question, not this one's.\n *\n * Comments are extended properties, and an account that can see the object\n * can see them: no gap is needed for comments, which was found by asking a\n * real server as a reader with SELECT only.\n */\n/** An object's kind, of sys.objects `o`: discovery's mapping, and the root's definition's (0041). `o.type` is char(2), so 'V' is compared as 'V '. */\nexport const OBJECT_KIND = `case o.type when 'V' then 'view' else 'table' end`\n\nconst SQL = (scoped: string): string => `\n select o.object_id, s.name as schema_name, o.name as object_name,\n ${OBJECT_KIND} as kind,\n cast(ep.value as nvarchar(max)) as comment,\n ${OBJECT_ACCESS}\n from sys.objects o\n join sys.schemas s on s.schema_id = o.schema_id\n left join sys.extended_properties ep\n on ep.class = 1 and ep.major_id = o.object_id and ep.minor_id = 0 and ep.name = N'MS_Description'\n where o.object_id in ${scoped}`\n\n/** An object before its row security and what refers to it are known: those are other concerns' (row-security.ts, referenced-by.ts). */\nexport type ObjectFound = Omit<ObjectMeta, 'rowSecurity' | 'referencedBy'>\n\n/** Each object in scope, by object_id, with nothing attached yet. */\nexport async function readObjects(pool: ConnectionPool, schemas: readonly string[]): Promise<Map<number, ObjectFound>> {\n const rows = await queryScope<ObjectRow>(pool, schemas, SQL)\n return new Map(\n rows.map((row) => [\n row.object_id,\n {\n ref: { schema: row.schema_name, name: row.object_name },\n kind: row.kind,\n comment: row.comment,\n columns: [],\n primaryKey: null,\n uniqueKeys: [],\n foreignKeys: [],\n checks: [],\n access: toObjectAccess(row),\n },\n ]),\n )\n}\n","import type { CoverageGap } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport { queryScope } from './catalog.js'\n\ninterface SchemaRow {\n name: string\n can_view_definitions: number | null\n}\n\n/**\n * Whether this account can see every object in each schema of the scope.\n *\n * SQL Server lists in sys.objects only the securables an account holds some\n * permission on, so a table the reader may not touch is simply not there.\n * VIEW DEFINITION on the schema is what lifts that filter -- on its own,\n * without any data access -- so a schema where the account lacks it gets a\n * gap: the object list may be short, and nothing in it says by how much.\n *\n * sys.schemas itself is not filtered: an account sees every schema, including\n * ones it holds nothing in. A scope name with no schema behind it is therefore\n * established as absent and needs no gap. The gap names the schema as the\n * catalog spells it, which on a case-insensitive database may not be how the\n * scope does: `SALES` finds `sales`, and the gap is about `sales` (0027).\n *\n * HAS_PERMS_BY_NAME parses the name it is given, so it gets QUOTENAME's\n * output: given `it's [odd]` raw it returns NULL, which would read as \"may not\n * see\" for a schema the account can see perfectly well.\n */\nconst SCHEMAS_SQL = (_scoped: string, schemaList: string): string => `\n select s.name, has_perms_by_name(quotename(s.name), 'SCHEMA', 'VIEW DEFINITION') as can_view_definitions\n from sys.schemas s\n where s.name in (${schemaList})`\n\n/**\n * Who a DENY row binds: the account itself, or a role it is in -- which is how\n * a DBA usually denies, and a row that names the role.\n */\nconst BINDS_ME = `(p.grantee_principal_id = database_principal_id() or is_member(user_name(p.grantee_principal_id)) = 1)`\n\n/**\n * Objects this account is denied VIEW DEFINITION on, which therefore vanish\n * from sys.objects even under a schema-level grant that HAS_PERMS_BY_NAME\n * still reports. The account can read its own DENY rows -- made to it or to a\n * role it is in -- but not the denied object's name or schema, so they are\n * counted rather than placed: any of them may be in scope. CONTROL is counted\n * too, because denying it denies everything it implies.\n *\n * A condition on `sys.database_permissions p`, exported, as `DENIED_SCHEMAS`\n * and `VIEWS_DATABASE` are, for the delete's guard (0050): the batch that\n * refuses a delete its account can no longer see every key of, and the\n * snapshot's `referenced-by` gap, read the one condition.\n */\nexport const DENIED_OBJECTS = `p.class = 1 and p.state = 'D' and p.permission_name in ('VIEW DEFINITION', 'CONTROL')\n and ${BINDS_ME}\n and object_name(p.major_id) is null`\n\nconst DENIED_OBJECTS_SQL = `\n select count(*) as hidden\n from sys.database_permissions p\n where ${DENIED_OBJECTS}`\n\n/**\n * Schemas this account is denied VIEW DEFINITION or CONTROL on (class 3).\n * A schema in scope already answers for itself through HAS_PERMS_BY_NAME\n * above; this count is for row security, because a security policy lives in\n * a schema of its own and may filter a table in any other. Measured (B10f):\n * with VIEW DEFINITION on the database and a deny on the policy's schema, the\n * database check still says yes, the policy is not listed, and the object\n * count above is 0 -- so without this count, a policy that applies would read\n * as none.\n *\n * Only a deny the server applies is counted. A DENY binds no sysadmin and no\n * dbo, yet one made to `public` matches BINDS_ME for them through IS_MEMBER,\n * and the owner, who sees every policy, would be told it is denied a schema.\n * HAS_PERMS_BY_NAME applies the exemption and the deny's precedence, so a\n * schema whose definitions the account can still see is not counted.\n */\nexport const DENIED_SCHEMAS = `p.class = 3 and p.state = 'D' and p.permission_name in ('VIEW DEFINITION', 'CONTROL')\n and ${BINDS_ME}\n and has_perms_by_name(quotename(schema_name(p.major_id)), N'SCHEMA', N'VIEW DEFINITION') = 0`\n\nconst DENIED_SCHEMAS_SQL = `\n select count(*) as hidden\n from sys.database_permissions p\n where ${DENIED_SCHEMAS}`\n\n/**\n * Whether the account may view every definition in the database, which is\n * what lists to it every object of every schema -- and so every security\n * policy, which lives in a schema of its own and filters a table in any\n * other (0027, B10b), and every foreign key, which is on a table in any\n * schema and refers to one in scope (0049, P2). VIEW SECURITY DEFINITION\n * shows no policy at all (B10d). The database is QUOTENAME'd:\n * HAS_PERMS_BY_NAME parses it, and in a database named `it's [odd] db` the\n * raw name answers NULL (B9).\n */\nexport const VIEWS_DATABASE = `has_perms_by_name(quotename(db_name()), N'DATABASE', N'VIEW DEFINITION')`\n\nconst DATABASE_SQL = `select ${VIEWS_DATABASE} as can_view_definitions`\n\n/** VIEW DEFINITION or CONTROL denies that bind this account, by securable class. */\nexport interface Denials {\n objects: number\n schemas: number\n}\n\nexport interface Visibility {\n gaps: CoverageGap[]\n denied: Denials\n /** VIEW DEFINITION on the database. */\n canViewDatabase: boolean\n}\n\n/**\n * Why this account may not see every definition in the database, or nothing\n * when it may: what row security (0027) and what refers to a table (0049)\n * are established by, because a security policy and a foreign key each live\n * on an object of any schema. Established takes VIEW DEFINITION on the\n * database and no VIEW DEFINITION or CONTROL deny on an object or a schema\n * binding the account -- a denied object, or an object in a denied schema,\n * is not listed even under the database grant (B10e, B10f; for a key, P2).\n * `lists` names what the database grant lists, for the sentence.\n */\nexport function unseenDefinitions(visibility: Visibility, lists: string): string[] {\n const reasons: string[] = []\n if (!visibility.canViewDatabase) reasons.push(`this account lacks VIEW DEFINITION on the database, which is what lists every ${lists}`)\n if (visibility.denied.objects > 0) reasons.push(`this account is denied VIEW DEFINITION or CONTROL on ${String(visibility.denied.objects)} object(s)`)\n if (visibility.denied.schemas > 0) reasons.push(`this account is denied VIEW DEFINITION or CONTROL on ${String(visibility.denied.schemas)} schema(s)`)\n return reasons\n}\n\nexport async function readObjectVisibility(pool: ConnectionPool, schemas: readonly string[]): Promise<Visibility> {\n const [rows, deniedObjects, deniedSchemas, database] = await Promise.all([\n queryScope<SchemaRow>(pool, schemas, SCHEMAS_SQL),\n pool.request().query<{ hidden: number }>(DENIED_OBJECTS_SQL),\n pool.request().query<{ hidden: number }>(DENIED_SCHEMAS_SQL),\n pool.request().query<{ can_view_definitions: number | null }>(DATABASE_SQL),\n ])\n const gaps: CoverageGap[] = rows\n .filter((row) => row.can_view_definitions !== 1)\n .map((row) => ({\n subject: { kind: 'schema', schema: row.name },\n aspect: 'objects',\n detail: `without VIEW DEFINITION on schema ${row.name}, the catalog lists only the tables and views this account holds a permission on, so one it cannot see is absent without trace`,\n }))\n const denied: Denials = { objects: deniedObjects.recordset[0]?.hidden ?? 0, schemas: deniedSchemas.recordset[0]?.hidden ?? 0 }\n if (denied.objects > 0) {\n gaps.push({\n subject: { kind: 'scope' },\n aspect: 'objects',\n detail: `this account is denied VIEW DEFINITION on ${String(denied.objects)} object(s) it therefore cannot see, and the catalog does not say which schema they are in: any of them may be in scope`,\n })\n }\n return { gaps, denied, canViewDatabase: database.recordset[0]?.can_view_definitions === 1 }\n}\n","import type { CoverageGap, InboundKey, ReferentialAction } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport type { Found, ObjectGap } from './catalog.js'\nimport { byObjectId, groupBy, queryScope } from './catalog.js'\nimport { action } from './foreign-keys.js'\nimport type { Visibility } from './visibility.js'\nimport { unseenDefinitions } from './visibility.js'\n\ninterface InboundRow {\n /** The referenced object: a table in scope. */\n object_id: number\n key_id: number\n name: string\n referring_schema: string\n referring_name: string\n is_disabled: boolean\n delete_referential_action: number\n update_referential_action: number\n column_name: string\n referenced_column: string\n}\n\n/**\n * Every foreign key the catalog shows that refers to a table in scope, from a\n * table in any schema, one row per column pair in constraint_column_id order\n * (0049). Joined, not LEFT joined: a key is listed to an account exactly when\n * it may see the table the key is on, and then it sees that table's columns,\n * and the referenced table is one in scope; what the account cannot see is\n * the whole key, which the gap below says.\n */\nconst INBOUND_SQL = (scoped: string): string => `\n select fk.referenced_object_id as object_id, fk.object_id as key_id, fk.name,\n schema_name(po.schema_id) as referring_schema, po.name as referring_name,\n fk.is_disabled, fk.delete_referential_action, fk.update_referential_action,\n pc.name as column_name, rc.name as referenced_column\n from sys.foreign_keys fk\n join sys.objects po on po.object_id = fk.parent_object_id\n join sys.foreign_key_columns fkc on fkc.constraint_object_id = fk.object_id\n join sys.columns pc on pc.object_id = fkc.parent_object_id and pc.column_id = fkc.parent_column_id\n join sys.columns rc on rc.object_id = fkc.referenced_object_id and rc.column_id = fkc.referenced_column_id\n where fk.referenced_object_id in ${scoped}\n order by fk.referenced_object_id, fk.object_id, fkc.constraint_column_id`\n\nfunction toInbound(rows: readonly InboundRow[]): InboundKey {\n const [first] = rows as [InboundRow, ...InboundRow[]]\n const actionOf = (code: number): ReferentialAction => action(code, first.name)\n return {\n table: { schema: first.referring_schema, name: first.referring_name },\n name: first.name,\n columns: rows.map((row) => row.column_name),\n referencedColumns: rows.map((row) => row.referenced_column),\n onDelete: actionOf(first.delete_referential_action),\n onUpdate: actionOf(first.update_referential_action),\n // As on the referring side (foreign-keys.ts): a disabled key is neither checked nor acted on.\n enforced: !first.is_disabled,\n }\n}\n\ninterface EdgeRow {\n /** The node table in scope that a clause of the constraint connects. */\n object_id: number\n name: string\n edge_schema: string\n edge_name: string\n delete_action: string\n}\n\n/**\n * Every edge constraint that connects a node table in scope, from an edge\n * table in any schema: one row per constraint and node table, whichever end\n * of a clause the node is.\n *\n * An edge constraint is not a foreign key -- sys.foreign_keys does not list\n * it -- yet a delete of a node acts through it. Measured on 16.0.4295.3,\n * 2026-10-11 (`discovery.integration.test.ts`): ON DELETE CASCADE removes\n * the edges that connect the node, from either end, and NO ACTION refuses\n * the delete with 547 while one does. This release describes neither the\n * edge nor its constraint, so each is a `referenced-by` gap on the node.\n * sys.edge_constraints is filtered as sys.foreign_keys is: measured the same\n * day, a constraint on an edge table in another schema is listed under VIEW\n * DEFINITION on the database and not under VIEW DEFINITION on the node's\n * schema alone -- where `referencedByGaps` already gives its scope gap.\n */\nconst EDGES_SQL = (scoped: string): string => `\n select distinct n.object_id, ec.name, schema_name(e.schema_id) as edge_schema, e.name as edge_name,\n ec.delete_referential_action_desc as delete_action\n from sys.edge_constraints ec\n join sys.edge_constraint_clauses cl on cl.object_id = ec.object_id\n join sys.objects e on e.object_id = ec.parent_object_id\n join sys.objects n on n.object_id in (cl.from_object_id, cl.to_object_id)\n where n.object_id in ${scoped}`\n\nfunction edgeGap(row: EdgeRow): ObjectGap {\n return {\n objectId: row.object_id,\n aspect: 'referenced-by',\n detail: `edge constraint ${row.name} of ${row.edge_schema}.${row.edge_name} connects this node table, ON DELETE ${row.delete_action}, so a delete of its rows acts on that table's edges or is refused by them; this release lists foreign keys, not edge constraints`,\n }\n}\n\n/**\n * Every key the catalog shows that refers to each table in scope, by the\n * referenced table's object_id, and a gap on each node table an edge\n * constraint connects.\n */\nexport async function readReferencedBy(pool: ConnectionPool, schemas: readonly string[]): Promise<Found<InboundKey[]>> {\n const [rows, edges] = await Promise.all([queryScope<InboundRow>(pool, schemas, INBOUND_SQL), queryScope<EdgeRow>(pool, schemas, EDGES_SQL)])\n const byObject = new Map<number, InboundKey[]>()\n for (const [objectId, group] of groupBy(rows, byObjectId)) byObject.set(objectId, [...groupBy(group, (row) => row.key_id).values()].map(toInbound))\n return { byObject, gaps: edges.map(edgeGap) }\n}\n\n/**\n * The gap that says what refers to a table may be short, or none (0049).\n *\n * SQL Server lists a foreign key only to an account that may see the table\n * the key is on, and that table may be in any schema. Measured on\n * 16.0.4295.3, 2026-10-11 (P2), with a key from another schema onto\n * sales.order: the owner and a database VIEW DEFINITION grantee see it; a\n * grantee of VIEW DEFINITION on sales alone, the reader, and a database\n * grantee denied VIEW DEFINITION on the other schema or on its table do\n * not -- the reader sees not even fk_order_line_order. So the lists are\n * complete exactly where row security is established, by the one rule\n * `unseenDefinitions` holds, and otherwise ONE gap on the scope says why: a\n * key the account cannot see may refer to any table in scope. The gap is\n * there only when some object is described, as row security's is: it\n * explains an answer, and an account that sees nothing gave none.\n */\nexport function referencedByGaps(described: number, visibility: Visibility): CoverageGap[] {\n const reasons = unseenDefinitions(visibility, 'foreign key on a table in any schema')\n if (reasons.length === 0 || described === 0) return []\n return [{ subject: { kind: 'scope' }, aspect: 'referenced-by', detail: `${reasons.join('; ')}, so a key on a table it cannot see may refer to any table in scope` }]\n}\n","import type { CoverageGap, RowSecurity } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport { queryScope } from './catalog.js'\nimport type { Visibility } from './visibility.js'\nimport { unseenDefinitions } from './visibility.js'\n\n/**\n * The objects in scope an enabled security policy has a predicate on, filter\n * or block. Positive evidence, and it needs nothing more: a policy this\n * account can see that targets a table applies to it, because SQL Server\n * exempts nobody from an enabled policy -- dbo and sysadmin included. A\n * disabled policy filters nothing and is not counted.\n */\nconst POLICED_SQL = (scoped: string): string => `\n select distinct pr.target_object_id as object_id\n from sys.security_predicates pr\n join sys.security_policies p on p.object_id = pr.object_id\n where p.is_enabled = 1 and pr.target_object_id in ${scoped}`\n\n/** The object_ids in scope that an enabled policy this account can see targets. */\nexport async function readPolicies(pool: ConnectionPool, schemas: readonly string[]): Promise<ReadonlySet<number>> {\n const policed = await queryScope<{ object_id: number }>(pool, schemas, POLICED_SQL)\n return new Set(policed.map((row) => row.object_id))\n}\n\nexport interface RowSecurityFound {\n of(objectId: number): RowSecurity\n gaps: CoverageGap[]\n}\n\n/**\n * Each object's row security, and the gap that explains an `unknown` (0027).\n *\n * `applies` where a visible enabled policy targets the object. `none` only\n * where it is established that no policy is hidden, by the rule\n * `unseenDefinitions` holds: a denied policy, or a policy in a denied schema,\n * is not listed even under the database grant (B10e, B10f). Anything else is\n * `unknown`, with ONE gap on the scope: a hidden policy can filter any table,\n * so the doubt cannot be placed on an object. The gap is there only when some\n * object is unknown; it explains an answer, and an account that sees nothing\n * gave none.\n */\nexport function rowSecurityOf(objectIds: Iterable<number>, policed: ReadonlySet<number>, visibility: Visibility): RowSecurityFound {\n const reasons = unseenDefinitions(visibility, 'security policy')\n const established = reasons.length === 0\n\n const of = (objectId: number): RowSecurity => (policed.has(objectId) ? 'applies' : established ? 'none' : 'unknown')\n const gaps: CoverageGap[] = [...objectIds].some((objectId) => of(objectId) === 'unknown')\n ? [\n {\n subject: { kind: 'scope' },\n aspect: 'row-security',\n detail: `${reasons.join('; ')}, so a security policy it cannot see may filter any table or view in scope`,\n },\n ]\n : []\n return { of, gaps }\n}\n","import type { ConnectionPool } from 'mssql'\n\n/**\n * The build the server runs, as it states it (\"16.0.4205.1\").\n *\n * One query, shared by `ping` and by discovery, so the version a snapshot\n * records and the version a ping reports cannot differ — and so discovery\n * does not import the adapter that imports it. `ProductVersion` rather than\n * `@@VERSION`, which adds the edition, the OS and a paragraph of text. Cast,\n * because `SERVERPROPERTY` returns `sql_variant` and the driver would hand that\n * back as something other than a string.\n */\nexport async function readServerVersion(pool: ConnectionPool): Promise<string> {\n const result = await pool\n .request()\n .query<{ version: string }>(\"select cast(serverproperty('ProductVersion') as nvarchar(128)) as version\")\n const row = result.recordset[0]\n // Never reached against a real server — a SELECT of one expression returns\n // one row — and kept because `recordset[0]` is `T | undefined` under\n // noUncheckedIndexedAccess. The coverage report shows it uncovered, honestly.\n if (row === undefined) throw new Error('SQL Server answered the version query with no row')\n return row.version\n}\n","import type { CoverageGap, DiscoveryScope, MetadataSnapshot, ObjectMeta } from '@formancy/data-core'\nimport { createSnapshot } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport { readAccount } from './account.js'\nimport type { ObjectGap } from './catalog.js'\nimport { readChecks } from './checks.js'\nimport { readColumns } from './columns.js'\nimport { readForeignKeys } from './foreign-keys.js'\nimport { readKeys } from './keys.js'\nimport type { ObjectFound } from './objects.js'\nimport { readObjects } from './objects.js'\nimport { readReferencedBy, referencedByGaps } from './referenced-by.js'\nimport { readPolicies, rowSecurityOf } from './row-security.js'\nimport { readObjectVisibility } from './visibility.js'\nimport { readServerVersion } from '../version.js'\n\n/**\n * What this connection's account can see of the tables and views in `scope`,\n * what it may do with each column, whether a security policy filters each\n * object for it -- and, as gaps, what it cannot establish (0007, 0027) --\n * whether it may delete from each, and every key it can see that refers to\n * each, from any schema (0049).\n *\n * Read from SQL Server's catalog views, never INFORMATION_SCHEMA, which carries\n * neither the trust and disable flags of a key nor rowversion nor extended\n * properties (0004). One catalog concern per query, each bound to the scope by\n * parameters; they run side by side and are not one consistent read. A\n * concurrent ALTER can tear the result, in which case createSnapshot refuses\n * what no catalog could produce, or drift review sees the change next time.\n * A column and its privileges are one read (access.ts), so no column lacks\n * an answer; a concurrent rename can still make that answer a false \"no\".\n *\n * Unlike PostgreSQL's, this catalog is filtered by permission: an object the\n * account holds nothing on is absent, behind a schema gap, a security policy\n * it cannot see leaves row security `unknown`, behind a scope gap, and a key\n * on a table it cannot see is missing from what refers to a table, behind\n * another. A graph edge constraint, which is not a foreign key, is a gap on\n * each node table it connects, for any account (referenced-by.ts).\n *\n * The pool is the caller's. Nothing here opens a connection or reads\n * configuration, and nothing here closes the pool.\n */\nexport async function discoverSqlServer(pool: ConnectionPool, scope: DiscoveryScope): Promise<MetadataSnapshot> {\n const schemas = [...new Set(scope.schemas)]\n // The same query ping runs, so the version a snapshot records and the\n // version a ping reports cannot differ. The account before the early\n // return: an empty snapshot is still somebody's.\n const [version, account] = await Promise.all([readServerVersion(pool), readAccount(pool)])\n if (schemas.length === 0) return createSnapshot({ kind: 'sqlserver', serverVersion: version, account, scope, objects: [], gaps: [] })\n\n const [objects, columns, keys, foreignKeys, referencedBy, checks, visibility, policed] = await Promise.all([\n readObjects(pool, schemas),\n readColumns(pool, schemas),\n readKeys(pool, schemas),\n readForeignKeys(pool, schemas),\n readReferencedBy(pool, schemas),\n readChecks(pool, schemas),\n readObjectVisibility(pool, schemas),\n readPolicies(pool, schemas),\n ])\n const rowSecurity = rowSecurityOf(objects.keys(), policed, visibility)\n\n const assembled: ObjectMeta[] = []\n for (const [objectId, object] of objects) {\n const objectKeys = keys.get(objectId)\n assembled.push({\n ...object,\n columns: columns.byObject.get(objectId) ?? [],\n primaryKey: objectKeys?.primaryKey ?? null,\n uniqueKeys: objectKeys?.uniqueKeys ?? [],\n foreignKeys: foreignKeys.byObject.get(objectId) ?? [],\n checks: checks.byObject.get(objectId) ?? [],\n rowSecurity: rowSecurity.of(objectId),\n referencedBy: referencedBy.byObject.get(objectId) ?? [],\n })\n }\n\n return createSnapshot({\n kind: 'sqlserver',\n serverVersion: version,\n account,\n scope,\n objects: assembled,\n gaps: [...visibility.gaps, ...rowSecurity.gaps, ...referencedByGaps(objects.size, visibility), ...named(objects, [...columns.gaps, ...foreignKeys.gaps, ...referencedBy.gaps, ...checks.gaps])],\n })\n}\n\n/**\n * Gaps with the object's name in place of its id. A gap on an object the\n * objects query did not return belongs to a table created between the two\n * reads, and is left out with the table.\n */\nfunction named(objects: ReadonlyMap<number, ObjectFound>, gaps: readonly ObjectGap[]): CoverageGap[] {\n return gaps.flatMap((gap) => {\n const object = objects.get(gap.objectId)\n return object === undefined ? [] : [{ subject: { kind: 'object', object: object.ref }, aspect: gap.aspect, detail: gap.detail }]\n })\n}\n","import type { DatabaseAdapter } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport { discoverSqlServer } from './discovery/discover.js'\nimport { readServerVersion } from './version.js'\n\n/**\n * SQL Server, through a pool the composition root connected.\n *\n * The pool rather than a connection string: opening the connection is where a\n * secret is handled, and that happens once, in the composition root, where the\n * secret resolver lives. Nothing in this package reads configuration, and the\n * tests hand it a pool pointed at a container.\n *\n * `ConnectionPool` is in this signature, which is why `@types/mssql` is a\n * dependency of this package and not a devDependency: a consumer type-checking\n * against the published declarations needs it, and `skipLibCheck` would not\n * save them, since the import is in OUR declaration file. The install gate\n * runs with `skipLibCheck` off for exactly this.\n */\nexport function createSqlServerAdapter(pool: ConnectionPool): DatabaseAdapter {\n return {\n kind: 'sqlserver',\n\n async ping() {\n return { kind: 'sqlserver', version: await readServerVersion(pool) }\n },\n\n discover: (scope) => discoverSqlServer(pool, scope),\n\n async close(): Promise<void> {\n // A closed pool closes again without complaint, which is what lets a\n // shutdown path and an error path both call this.\n await pool.close()\n },\n }\n}\n","import type { LookupSignal } from '@formancy/data-core'\nimport type { ConnectionPool, ISqlType, Request } from 'mssql'\n\n/** One bound value: a generated name, the driver type it travels as, and the value. */\nexport interface Parameter {\n readonly name: string\n readonly type: ISqlType | (() => ISqlType)\n readonly value: unknown\n}\n\n/** SQL text that holds no value, and the values it names. */\nexport interface Statement {\n readonly sql: string\n readonly parameters: readonly Parameter[]\n}\n\n/**\n * The parameters of one statement as it is built: each value gets the next\n * generated name, `@p0`, `@p1`, and only that name reaches the SQL text. A\n * value is never spliced into a statement, whatever it holds.\n */\nexport class Parameters {\n readonly #list: Parameter[] = []\n\n /** Binds a value and returns its name, for the SQL being built. */\n add(type: ISqlType | (() => ISqlType), value: unknown): string {\n const name = `p${String(this.#list.length)}`\n this.#list.push({ name, type, value })\n return `@${name}`\n }\n\n statement(sql: string): Statement {\n return { sql, parameters: [...this.#list] }\n }\n}\n\n/** A request for one statement, its values bound. A value the driver will not take is thrown here, before anything is sent. */\nexport function prepare(pool: ConnectionPool, statement: Statement): Request {\n const request = pool.request()\n for (const parameter of statement.parameters) request.input(parameter.name, parameter.type, parameter.value)\n return request\n}\n\n/**\n * Sends a prepared statement and returns its last result set: a write batch\n * selects what it wrote after its own bookkeeping, and a read selects once.\n *\n * Every statement travels as `sp_executesql`, with or without parameters —\n * `tedious` sends a query no other way — which is what keeps the values out of\n * the SQL text, and what ends a `SET` with the request. What this rejects\n * with is always the driver's.\n */\nexport async function send<Row>(request: Request, statement: Statement): Promise<Row[]> {\n const result = await request.query<Row>(statement.sql)\n return [...(result.recordsets.at(-1) ?? [])]\n}\n\n/**\n * Runs one statement. Errors are the driver's own and reach the caller as they\n * are: the lookup half lets them propagate, because a lookup that cannot\n * answer refuses (0012). The record half prepares and sends apart, so that it\n * translates only what the driver rejected with.\n */\nexport async function run<Row>(pool: ConnectionPool, statement: Statement): Promise<Row[]> {\n return send<Row>(prepare(pool, statement), statement)\n}\n\n/**\n * Runs one lookup statement until `signal` aborts (0061). Already aborted: it\n * throws `signal.reason` and builds and sends nothing -- the check that also\n * stops a resolve between two key groups, since a listener added to a signal\n * that has already aborted is never called. Aborted while the statement is on\n * its way or running: `request.cancel()` sends a TDS attention on the\n * statement's own connection, and this rejects with exactly `signal.reason`\n * at once, without waiting for the server's acknowledgement. An answer read\n * before the abort is returned as it came.\n *\n * Attention is in-band: tedious waits for the server to acknowledge it\n * before the connection takes another request, so a cancel can only ever\n * stop its own statement. Measured on 2026-10-14 against SQL Server 2022\n * with mssql 12.7.4 and tedious 20.3.3: of 300 trials, the 99 cancels sent\n * as the statement completed reached 0 next requests on the connection. An\n * abort before mssql holds a connection marks the request cancelled, and\n * mssql gives the connection back without sending the statement.\n *\n * The driver's own rejection of a cancelled statement, ECANCEL, comes after\n * this has rejected, and is dropped: by then nobody is waiting for it. The\n * connection goes back to the pool when it arrives.\n *\n * No `requestTimeout` is set here: the deadline is the caller's signal, one\n * timer the same on both engines that also counts the wait for a pooled\n * connection, which tedious's timer, started at send, does not. mssql's\n * default request timeout of 15 s, which it hands tedious for every request\n * (lib/tedious/connection-pool.js), still bounds every statement, a\n * lookup's included.\n */\nexport function runUntil<Row>(pool: ConnectionPool, statement: Statement, signal: LookupSignal): Promise<Row[]> {\n stopIfAborted(signal)\n const request = prepare(pool, statement)\n const answer = send<Row>(request, statement)\n return new Promise<Row[]>((resolve, reject) => {\n const stop = (): void => {\n request.cancel()\n reject(signal.reason)\n }\n signal.addEventListener('abort', stop, { once: true })\n answer.then(\n (rows) => {\n signal.removeEventListener('abort', stop)\n resolve(rows)\n },\n (error: unknown) => {\n signal.removeEventListener('abort', stop)\n reject(error)\n },\n )\n })\n}\n\n/** Throws `signal.reason` when the caller has already gone, so nothing is built or sent for it. */\nexport function stopIfAborted(signal: LookupSignal): void {\n if (signal.aborted) throw signal.reason\n}\n","import type { ApiValue, NormalizedType } from '@formancy/data-core'\nimport { canonicalFloat32 } from '@formancy/data-core'\nimport mssql from 'mssql'\nimport type { Parameters } from './statement.js'\n\n/**\n * How a value crosses between SQL Server and the API, in both directions, for\n * every kind the contract names. One module for the lookup half and the record\n * half, because two spellings of one decimal inside one adapter is the\n * divergence the core exists to prevent.\n *\n * Out of the database, every value is converted to text BY THE SERVER, into\n * exactly what `codecFor(column).parse` returns, and the driver only ever\n * carries a string. `tedious` returns `decimal(18,4)` as a lossy JavaScript\n * number and `date` as midnight UTC (0007); a string it cannot misread.\n *\n * Into the database, every value except a boolean and a float travels as\n * nvarchar text and is converted by the server to the column's type. Not\n * through the driver's typed parameters: `tedious` binds a `Decimal` parameter\n * through a JavaScript number, so `1234567890123.4567` is stored as\n * `1234567890123.4568` (the records suite holds it), and the largest\n * `decimal(18,4)` is refused outright (8023, measured once on 2026-10-09).\n */\n\n/** SQL Server's largest decimal precision: decimal(38, s). */\nconst MAX_PRECISION = 38\n\n/** SQL Server's integer types, narrowest first, by the range the snapshot gives each. */\nconst INTEGER_TYPES: ReadonlyArray<readonly [name: string, min: bigint, max: bigint]> = [\n ['tinyint', 0n, 255n],\n ['smallint', -32768n, 32767n],\n ['int', -2147483648n, 2147483647n],\n ['bigint', -9223372036854775808n, 9223372036854775807n],\n]\n\ntype Kind<K extends NormalizedType['kind']> = Extract<NormalizedType, { kind: K }>\n\n/** The integer type a column of this range is: a key compared with its own type is a seek, not a conversion of every row. */\nfunction integerType(type: Kind<'integer'>): string {\n const min = BigInt(type.min)\n const max = BigInt(type.max)\n const found = INTEGER_TYPES.find(([, low, high]) => low <= min && max <= high)\n if (found === undefined) throw new Error(`No SQL Server integer type holds ${type.min} to ${type.max}`)\n return found[0]\n}\n\n/**\n * The decimal type a value is converted to, spliced into the statement\n * because SQL Server takes no parameter there. So the precision and the scale\n * are checked to be what its syntax allows — whole numbers, 1 to 38 and 0 to\n * the precision — before they become SQL: they come from approved bindings,\n * and a bundle altered where it is stored must not run as a statement.\n */\nfunction decimalType(type: Kind<'decimal'>): string {\n const { precision, scale } = type\n // An unconstrained numeric is PostgreSQL's; every SQL Server decimal has both.\n if (precision === null || scale === null) throw new Error('A SQL Server decimal has a precision and a scale')\n if (!Number.isSafeInteger(precision) || !Number.isSafeInteger(scale) || precision < 1 || precision > MAX_PRECISION || scale < 0 || scale > precision) {\n throw new Error(`A SQL Server decimal's precision is 1 to ${String(MAX_PRECISION)} and its scale 0 to its precision`)\n }\n return `decimal(${String(precision)}, ${String(scale)})`\n}\n\nfunction noValue(type: NormalizedType): Error {\n return new Error(`A ${type.kind} column has no canonical API value, so it can be neither read nor written as one`)\n}\n\n/**\n * SQL that reads `expression` as the text of its canonical API value.\n *\n * - text: itself, as nvarchar(max), so a `varchar` is decoded by the server's\n * code page and not by the driver's. A char(n) or nchar(n) without its\n * padding: SQL Server keeps it through the conversion (`AB ` for a char(3)\n * holding AB, C1) and PostgreSQL's bpchar drops it, so a fixed-length key\n * would otherwise have one token per engine (0028). `rtrim` removes U+0020\n * and nothing else — a no-break space or a tab stays (C1b) — which is\n * exactly the padding. Measured on SQL Server 2022 (16.0.4295) on 2026-10-09.\n * - integer: the decimal string, whatever its width.\n * - decimal: every digit the column holds, padded to its scale, in style 2 —\n * which a decimal ignores, and which gives `money` its four places where\n * its default conversion rounds to two.\n * - boolean: `1` or `0`, which `fromCanonicalText` makes `true` or `false`.\n * - float: style 3, seventeen significant digits, which a double round-trips\n * through; a real's are then made its shortest decimal by\n * `fromCanonicalText` (0026).\n * - date `YYYY-MM-DD`; time `HH:MM`; an instant `YYYY-MM-DDTHH:MM:SSZ` in UTC.\n * Each is formancy's shape, and a time's seconds and an instant's fraction\n * are cut off, not rounded, because the shapes cannot hold them (0017).\n * - a zoneless timestamp: `YYYY-MM-DDTHH:MM:SS`, then its fraction with the\n * trailing zeros dropped, as PostgreSQL spells it (0026). See\n * `zonelessText`.\n * - uuid: lower case, as the codec spells it; SQL Server prints upper case.\n *\n * Text and decimals are read by the column's own type, never by the length,\n * precision or scale the snapshot remembers: CONVERT truncates text and\n * rounds a decimal to the type it is given without a word, so a column\n * widened since discovery would read back as a value it does not hold\n * (measured: 'Muster AG,' for 'Muster AG, Zurich branch', 1.2346 for\n * 1.234567). PostgreSQL reads `::text`, which loses nothing either.\n */\nexport function canonicalText(type: NormalizedType, expression: string): string {\n switch (type.kind) {\n case 'text':\n return type.fixedLength ? `rtrim(convert(nvarchar(max), ${expression}))` : `convert(nvarchar(max), ${expression})`\n case 'integer':\n return `convert(nvarchar(20), ${expression})`\n case 'decimal':\n // decimal(38, 38) at its most negative is 41 characters.\n return `convert(nvarchar(50), ${expression}, 2)`\n case 'boolean':\n return `convert(nchar(1), ${expression})`\n case 'float':\n return `convert(nvarchar(30), ${expression}, 3)`\n case 'date':\n return `convert(nchar(10), ${expression}, 23)`\n case 'time':\n return `convert(nchar(5), ${expression}, 108)`\n case 'timestamp':\n return type.withTimeZone\n ? `convert(nchar(19), switchoffset(${expression}, '+00:00'), 126) + N'Z'`\n : zonelessText(expression)\n case 'uuid':\n return `lower(convert(nchar(36), ${expression}))`\n case 'binary':\n case 'rowversion':\n case 'unsupported':\n throw noValue(type)\n }\n}\n\n/**\n * A zoneless timestamp as text, with its fraction and without its trailing\n * zeros: `2026-10-08T12:34:56.5`. Style 126 prints the column's own scale with\n * trailing zeros -- datetime2(3) holding .5 is `…56.500`, datetime2(7) holding\n * .12 is `…50.1200000`, datetime holding .007 is `…56.007` -- and leaves the\n * fraction out on a whole second. datetime keeps 1/300 s, so what it holds\n * for .007 is .00666…, and style 126 spells it to the millisecond: the one\n * read that is rounded, by SQL Server, and the contract says so. The zeros are trimmed by reversing the text\n * and keeping it up to the first digit that is not 0. Only text past nineteen\n * characters is trimmed -- it has a fraction, and the fraction a digit that\n * is not 0 -- so a whole second ending in 0 keeps it: `…12:34:50`, never\n * `…12:34:5`. Measured on SQL Server 2022 (16.0.4295) on 2026-10-09 for .12,\n * .5, .007, .01, .0000001, .9999999 and a whole second; the records suite\n * holds datetime2(7), datetime and smalldatetime to it. The conversion is\n * spelled five times, which the server evaluates per column read.\n */\nfunction zonelessText(expression: string): string {\n const text = `convert(nvarchar(27), ${expression}, 126)`\n return `case when len(${text}) > 19 then left(${text}, len(${text}) + 1 - patindex(N'%[^0]%', reverse(${text}))) else ${text} end`\n}\n\n/**\n * The API value for text `canonicalText` produced: a boolean and a float become\n * JSON's own; everything else stays a string. A real becomes the shortest\n * decimal naming its float32 -- 0.1, never the 0.10000000149011612 its style 3\n * text is -- which is what the codec returns for it and what PostgreSQL reads\n * (0026), so a value read and sent back unchanged is unchanged.\n */\nexport function fromCanonicalText(type: NormalizedType, text: string | null): ApiValue {\n if (text === null) return null\n if (type.kind === 'boolean') return text === '1'\n if (type.kind === 'float') return type.bits === 32 ? canonicalFloat32(Number(text)) : Number(text)\n return text\n}\n\nfunction requireType(ok: boolean, type: NormalizedType): void {\n if (!ok) throw new Error(`A value for a ${type.kind} column is not the canonical value a codec returns`)\n}\n\n/** As text, for the server to convert: the one way into the database that loses nothing. */\nfunction asText(parameters: Parameters, value: ApiValue): string {\n return parameters.add(mssql.NVarChar(mssql.MAX), value)\n}\n\n/** The kinds a value travels as text for: every kind with a canonical value but a boolean and a float, which travel as themselves. */\ntype TextBound = Kind<'text' | 'integer' | 'decimal' | 'date' | 'time' | 'timestamp' | 'uuid'>\n\n/**\n * SQL that converts `text` — an nvarchar expression holding a canonical value\n * — to its column's type: `convert(decimal(18, 4), @p3)`. A timestamp is an\n * instant; a zoneless one is never written. One spelling for a value bound as\n * text and for a key read back as text, so a record is found again exactly\n * the way it is named.\n */\nexport function fromText(type: TextBound, text: string): string {\n switch (type.kind) {\n case 'text':\n return text\n case 'integer':\n return `convert(${integerType(type)}, ${text})`\n case 'decimal':\n return `convert(${decimalType(type)}, ${text})`\n case 'date':\n return `convert(date, ${text}, 23)`\n case 'time':\n return `convert(time, ${text})`\n case 'timestamp':\n return `convert(datetimeoffset, ${text}, 127)`\n case 'uuid':\n return `convert(uniqueidentifier, ${text})`\n }\n}\n\n/** A kind that travels as text and whose canonical text is its value exactly. */\nexport type ExactKey = Kind<'text' | 'integer' | 'decimal' | 'uuid' | 'date'>\n\n/**\n * Whether a key of this kind read back by `canonicalText` is turned by\n * `fromText` into the very value it was read from. A time and an instant are\n * cut short (0017); a boolean and a float do not travel as text.\n */\nexport function isExactKey(type: NormalizedType): type is ExactKey {\n return type.kind === 'text' || type.kind === 'integer' || type.kind === 'decimal' || type.kind === 'uuid' || type.kind === 'date'\n}\n\n/**\n * Binds one canonical value and returns the SQL expression that is it, typed\n * as its column: `convert(decimal(18, 4), @p3)`. Null is bound with the same\n * type, so it is a typed NULL.\n *\n * Text is bound as nvarchar(max), never with the column's length: a parameter\n * declared shorter than its value is truncated by the server without a word,\n * and the column's own length check is the one that should refuse.\n *\n * A value of the wrong JavaScript type is a programming error, refused before\n * anything is sent: the record port's values arrive as a codec returned them.\n */\nexport function bindValue(parameters: Parameters, type: NormalizedType, value: ApiValue): string {\n const given = value === null ? null : typeof value\n switch (type.kind) {\n case 'integer':\n requireType(given === null || given === 'string' || (given === 'number' && Number.isSafeInteger(value)), type)\n return fromText(type, asText(parameters, value === null ? null : String(value)))\n case 'boolean':\n requireType(given === null || given === 'boolean', type)\n return parameters.add(mssql.Bit, value)\n case 'float':\n requireType(given === null || (given === 'number' && Number.isFinite(value)), type)\n return parameters.add(mssql.Float, value)\n case 'timestamp':\n // A zoneless timestamp is read-only: formancy's datetime is an instant (0009).\n if (!type.withTimeZone) throw noValue(type)\n requireType(given === null || given === 'string', type)\n return fromText(type, asText(parameters, value))\n case 'text':\n case 'decimal':\n case 'date':\n case 'time':\n case 'uuid':\n requireType(given === null || given === 'string', type)\n return fromText(type, asText(parameters, value))\n case 'binary':\n case 'rowversion':\n case 'unsupported':\n throw noValue(type)\n }\n}\n","import type { ObjectRef } from '@formancy/data-core'\n\n/** sysname is nvarchar(128): no SQL Server identifier is longer, and QUOTENAME returns NULL past it. */\nconst MAX_IDENTIFIER_LENGTH = 128\n\n/**\n * One identifier, bracket-quoted with every `]` doubled, which is what\n * QUOTENAME does: inside brackets nothing else is special, so a name with a\n * dot, a space, a quote or a reserved word is one identifier and never SQL.\n *\n * Names come from approved metadata (CLAUDE.md, \"Secrets and identifiers\"),\n * so one that no catalog could hold — empty, longer than sysname, or carrying\n * a NUL — is a programming error, and refused before any SQL is built.\n */\nexport function quoteName(name: string): string {\n if (typeof name !== 'string' || name.length === 0 || name.length > MAX_IDENTIFIER_LENGTH || name.includes('\\u0000')) {\n throw new Error(`An identifier is 1 to ${String(MAX_IDENTIFIER_LENGTH)} characters without NUL, as SQL Server's catalog holds it`)\n }\n return `[${name.replaceAll(']', ']]')}]`\n}\n\n/**\n * A table or view, quoted one part at a time from its two fields. Never from\n * a dotted string: `sales.order` split at the dot is a guess, and a name that\n * contains a dot is legal once quoted (0015).\n */\nexport function quoteTable(ref: ObjectRef): string {\n return `${quoteName(ref.schema)}.${quoteName(ref.name)}`\n}\n","import { quoteName } from './quote.js'\n\n/*\n * An ORDER BY on SQL Server, for a lookup's options and a form's records\n * (0044): one spelling.\n *\n * Where PostgreSQL orders a column otherwise, the difference is the\n * engine's and stays (0056). A uniqueidentifier is ordered by its byte\n * groups, not by its text and not by a collation: the last six bytes first,\n * then the two before them, then the first eight from the right -- in the\n * text 8-4-4-4-12, the fifth group and the fourth read from the left, then\n * the third, the second and the first each read from its last byte. That is\n * the bytes SQL Server stores, compared group by group from the last, with\n * the text's first three groups stored little-endian; the uuid suite reads\n * the stored bytes back and holds both. PostgreSQL orders a uuid by its\n * bytes in turn. Measured on SQL Server 2022\n * (16.0.4295.3) on 2026-10-11 with sixteen keys that each set one byte and\n * with 1000 random keys; the shared cases `uuid: order` and `uuid: lookup`\n * hold it on every run. Ordered by the column, the key's own index serves\n * the order; ordered by its text, to match PostgreSQL, it would sort every\n * row the filter admits, for every page. Every column is named through the\n * row's alias: an ORDER BY that named a select-list alias spelled as the\n * column would order by what the alias holds -- for a uniqueidentifier read\n * as its lower-cased text, PostgreSQL's order, as the measurement first\n * showed by mistake.\n */\n\n/**\n * One column of an order. `nulls` says where a NULL goes whichever the\n * direction, or is `null` where the column holds none -- a NOT NULL column\n * of a list (`listOrder`), which is then spelled as the column alone, so an\n * index on it serves the order. A lookup's order says it on every column\n * (0012).\n */\nexport interface OrderTerm {\n column: string\n direction: 'asc' | 'desc'\n nulls: 'first' | 'last' | null\n}\n\n/**\n * The order of `row`'s columns, made explicit about NULLs where a term says\n * where they go: SQL Server puts them first in an ascending order and has no\n * NULLS LAST, so such a column is preceded by a CASE that places them. Text\n * is ordered by the column's collation -- the server's rule, not code-point\n * order -- a uniqueidentifier by its byte groups (above), and the key that\n * ends every order makes it total, because a key is unique under that same\n * rule.\n *\n * The direction is spliced, because SQL Server takes no parameter for ASC or\n * DESC, so it is checked to be one of the two first: the core only writes\n * those, but this is handed a configuration or a request, and one read from\n * a bundle altered where it is stored must not run as a statement.\n */\nexport function orderBy(row: string, terms: readonly OrderTerm[]): string {\n if (terms.length === 0) throw new Error('An order names at least one column.')\n return terms\n .flatMap((term) => {\n if (term.direction !== 'asc' && term.direction !== 'desc') throw new Error(`${term.column} sorts asc or desc`)\n const name = `${row}.${quoteName(term.column)}`\n if (term.nulls === null) return [`${name} ${term.direction}`]\n if (term.nulls !== 'first' && term.nulls !== 'last') throw new Error(`${term.column} puts NULLs first or last`)\n const [nullRank, valueRank] = term.nulls === 'first' ? ['0', '1'] : ['1', '0']\n return [`case when ${name} is null then ${nullRank} else ${valueRank} end`, `${name} ${term.direction}`]\n })\n .join(', ')\n}\n","import type { LookupSearchColumn } from '@formancy/data-core'\nimport mssql from 'mssql'\nimport { quoteName } from './quote.js'\nimport type { Parameters } from './statement.js'\nimport { canonicalText } from './values.js'\n\n/*\n * How a search matches on SQL Server: one spelling for a lookup's options\n * and a form's records (0044), so the same text finds the same rows in both.\n */\n\n/**\n * The search as a LIKE pattern that matches only itself: `\\` is the escape,\n * and the escape, `%`, `_` and `[` are escaped by it. `[` too, because\n * SQL Server reads `[a-c]` as a character class; `]`, `^` and `-` mean\n * something only inside one.\n */\nexport function containsPattern(search: string): string {\n return `%${search.replace(/[\\\\%_[]/g, (character) => `\\\\${character}`)}%`\n}\n\n/**\n * What a search column of `row` is matched as: text as itself, so the\n * column's collation folds case and accents as it does in an index; an\n * integer as its canonical text, the digits its label or its cell shows,\n * converted explicitly rather than by LIKE's implicit conversion (0028).\n */\nfunction searched(row: string, search: LookupSearchColumn): string {\n const column = `${row}.${quoteName(search.name)}`\n return search.type.kind === 'integer' ? canonicalText(search.type, column) : column\n}\n\n/** The condition that some column of `row` contains `search`, the pattern bound once. `columns` is never empty: a search over nothing is refused before SQL. */\nexport function searchPredicate(parameters: Parameters, row: string, columns: readonly LookupSearchColumn[], search: string): string {\n if (columns.length === 0) throw new Error('A search names at least one column; one over none would match nothing on one engine and fail on the other.')\n const pattern = parameters.add(mssql.NVarChar(mssql.MAX), containsPattern(search))\n return `(${columns.map((entry) => `${searched(row, entry)} like ${pattern} escape N'\\\\'`).join(' or ')})`\n}\n","import type { RowFilterTerm } from '@formancy/data-core'\nimport mssql from 'mssql'\nimport type { Parameters } from './statement.js'\nimport { bindValue } from './values.js'\n\n/**\n * How a row filter and the write check compare text exactly (0028): the\n * column's canonical value is the trusted value, UTF-16 unit for unit, as\n * PostgreSQL compares two `\"C\"`-collated texts.\n *\n * SQL Server has no such operator. Every collation, BIN2 included, ignores\n * trailing spaces in `=`, so `N'acme' = N'acme ' collate BIN2` is true (C2),\n * and a filter of BIN2 alone let tenant `acme` read the rows of `acme `\n * (C2-table). Two equal-length strings that BIN2 calls equal are the same\n * string, so the byte lengths are compared too.\n */\n\n/** A collation that compares code point by code point: case and accents count, trailing spaces still do not. */\nconst EXACT_COLLATION = 'Latin1_General_100_BIN2'\n\n/**\n * SQL that is true when two nvarchar expressions are exactly the same text.\n * Both sides are canonical text — what `canonicalText` reads, or a bound\n * value — so a char(n)'s padding is already gone from both.\n */\nexport function exactText(left: string, right: string): string {\n return `${left} = ${right} collate ${EXACT_COLLATION} and datalength(${left}) = datalength(${right})`\n}\n\n/**\n * One row filter on `column`, binding its value once.\n *\n * A non-text value is bound as its column's type, as a record key is: the\n * canonical spelling `scopeRowFilters` checked converts to exactly one value.\n *\n * Text is compared three ways, all on one parameter:\n *\n * - `column = @p`, in the column's own collation, which admits a superset —\n * an exactly equal pair is equal under every collation — and is the\n * conjunct an index seeks on. Measured on SQL Server 2022 (16.0.4295) on\n * 2026-10-09 over 20,004 rows (C5): an nvarchar or nchar column seeks\n * (`GetRangeWithMismatchedTypes`), and so does a char or varchar under a\n * Windows collation; a char or varchar under a `SQL_` collation still\n * converts every row and scans, as it did before (0017). BIN2 alone never\n * seeked: the fixture's lookup scanned another index and looked each row up.\n * - the same under BIN2, so case and accents count.\n * - for variable-length text, the byte lengths, so trailing spaces count.\n * A fixed-length column needs none: its canonical value has no padding, a\n * value ending in a space is refused before this (`scopeRowFilters`), and\n * `=` ignores the padding the column stores.\n *\n * The parameter is nvarchar(max), never the column's length, which the\n * server would truncate it to without a word.\n */\nexport function filterPredicate(parameters: Parameters, column: string, term: RowFilterTerm): string {\n const { type } = term\n if (type.kind !== 'text') return `${column} = ${bindValue(parameters, type, term.value)}`\n const value = parameters.add(mssql.NVarChar(mssql.MAX), term.value)\n const exact = `${column} = ${value} and ${column} = ${value} collate ${EXACT_COLLATION}`\n return type.fixedLength ? exact : `${exact} and datalength(convert(nvarchar(max), ${column})) = datalength(${value})`\n}\n","import type { LookupConfig, LookupQuery, RowFilterTerm } from '@formancy/data-core'\nimport mssql from 'mssql'\nimport { orderBy } from '../sql/order.js'\nimport { quoteName, quoteTable } from '../sql/quote.js'\nimport { searchPredicate } from '../sql/search.js'\nimport { Parameters } from '../sql/statement.js'\nimport type { Statement } from '../sql/statement.js'\nimport { filterPredicate } from '../sql/filters.js'\nimport { bindValue, canonicalText } from '../sql/values.js'\n\n/**\n * The parameters one statement may bind. SQL Server's message says \"a maximum\n * of 2100 parameters\", and a request with 2099 is refused with 8003: the\n * driver sends every parameterised statement through `sp_executesql`, whose\n * own `@stmt` and `@params` are two of the 2100. Measured against SQL Server\n * 2022 through `tedious` on 2026-10-09; the lookup suite holds the edge.\n */\nexport const PARAMETER_LIMIT = 2098\n\n/** The table, under one alias every column is qualified with, so a column called `v` or `k0` cannot be mistaken for the key list's. */\nconst TARGET = '[target]'\n\nfunction column(name: string): string {\n return `${TARGET}.${quoteName(name)}`\n}\n\n/** The key, each column as the canonical text a token is made of: `[k0]`, `[k1]`, … */\nfunction keySelect(config: LookupConfig): string[] {\n return config.targetColumns.map((key, index) => `${canonicalText(key.type, column(key.name))} as [k${String(index)}]`)\n}\n\n/**\n * The display columns, `[d0]`, `[d1]`, …, read as a record read reads them:\n * the canonical text of each, by the type the configuration carries, which\n * `fromCanonicalText` decodes and `displayText` spells (0028). Not SQL\n * Server's own style 126, which spelled a bit `1`, a uuid in upper case, a\n * float in scientific notation and an instant in its stored offset (C6).\n */\nfunction displaySelect(config: LookupConfig): string[] {\n return config.display.map((display, index) => `${canonicalText(display.type, column(display.name))} as [d${String(index)}]`)\n}\n\n/** A row whose key holds a NULL cannot be referenced by any foreign key value, so it is never offered. */\nfunction keysPresent(config: LookupConfig): string[] {\n return config.targetColumns.map((key) => `${column(key.name)} is not null`)\n}\n\n/**\n * The actor's trusted filters, in the same WHERE as everything else: a row\n * outside them does not exist for this call. Each compares exactly (0028).\n */\nfunction filtered(parameters: Parameters, terms: readonly RowFilterTerm[]): string[] {\n return terms.map((term) => filterPredicate(parameters, column(term.column), term))\n}\n\n/**\n * One page: up to `limit + 1` rows, so `lookupPage` can tell whether there is\n * more without a COUNT. The search is one parameter, matched against each\n * search column with LIKE.\n */\nexport function pageStatement(config: LookupConfig, query: LookupQuery, terms: readonly RowFilterTerm[]): Statement {\n const parameters = new Parameters()\n const where = [...keysPresent(config), ...filtered(parameters, terms)]\n // Matched as a record list matches (sql/search.ts), and ordered as one is ordered (sql/order.ts).\n if (query.search !== '') {\n if (config.search.length === 0) throw new Error(`${config.source} has no searchable column`)\n where.push(searchPredicate(parameters, TARGET, config.search, query.search))\n }\n const offset = parameters.add(mssql.BigInt, query.offset)\n const fetch = parameters.add(mssql.Int, query.limit + 1)\n return parameters.statement(\n `select ${[...keySelect(config), ...displaySelect(config)].join(', ')} from ${quoteTable(config.target)} as ${TARGET}\n where ${where.join(' and ')}\n order by ${orderBy(TARGET, config.sort)}\n offset ${offset} rows fetch next ${fetch} rows only`,\n )\n}\n\n/**\n * The rows, under the filters, whose key is one of `keys`. The keys travel as\n * a table value constructor joined by EXISTS, so a composite key is compared\n * column by column, each value converted to its key column's type, and a row\n * is returned at most once however many keys the database finds equal to it.\n */\nexport function keysStatement(config: LookupConfig, keys: readonly (readonly string[])[], terms: readonly RowFilterTerm[], withDisplay: boolean): Statement {\n const parameters = new Parameters()\n const where = filtered(parameters, terms)\n const rows = keys.map((key) => `(${config.targetColumns.map((target, index) => bindValue(parameters, target.type, key[index] ?? null)).join(', ')})`)\n const names = config.targetColumns.map((_, index) => `[k${String(index)}]`)\n const matches = config.targetColumns.map((target, index) => `${column(target.name)} = [v].[k${String(index)}]`)\n where.push(`exists (select 1 from (values ${rows.join(', ')}) as [v] (${names.join(', ')}) where ${matches.join(' and ')})`)\n const select = withDisplay ? [...keySelect(config), ...displaySelect(config)] : keySelect(config)\n return parameters.statement(`select ${select.join(', ')} from ${quoteTable(config.target)} as ${TARGET} where ${where.join(' and ')}`)\n}\n\n/**\n * The keys in groups that each fit one statement: every key binds one\n * parameter per key column, and the filters bind theirs in every group.\n * Splitting makes resolve and rejects several reads rather than one, so a row\n * changed between two of them is seen as it was when its own group ran.\n */\nexport function keyGroups(config: LookupConfig, keys: readonly (readonly string[])[], filterCount: number): (readonly string[])[][] {\n const size = Math.floor((PARAMETER_LIMIT - filterCount) / config.targetColumns.length)\n if (size < 1) throw new Error(`${config.source}: ${String(filterCount)} filters leave no parameter for a key`)\n const groups: (readonly string[])[][] = []\n for (let start = 0; start < keys.length; start += size) groups.push(keys.slice(start, start + size))\n return groups\n}\n","import type { FoundRow, LookupAdapter, LookupConfig, LookupSignal, RowFilterTerm } from '@formancy/data-core'\nimport { lookupKeys, lookupPage, rejectedTokens, resolvedRows, rowFilterTerms } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport { runUntil, stopIfAborted } from '../sql/statement.js'\nimport { fromCanonicalText } from '../sql/values.js'\nimport { keyGroups, keysStatement, pageStatement } from './statements.js'\n\n/** A row as the lookup statements select it: `k0…` the key's canonical text, `d0…` each display column's. */\ntype Row = Record<string, string | null>\n\nfunction foundRow(config: LookupConfig, row: Row): FoundRow {\n return {\n key: config.targetColumns.map((_, index) => {\n const value = row[`k${String(index)}`]\n // The statements select only rows whose key columns are all present.\n if (typeof value !== 'string') throw new Error(`${config.source}: a key column came back without a value`)\n return value\n }),\n // Decoded as a record read decodes it, so a label is spelled from the value a record holds.\n display: config.display.map((display, index) => fromCanonicalText(display.type, row[`d${String(index)}`] ?? null)),\n }\n}\n\n/**\n * The rows under the filters whose key is one of `keys`, read in as many\n * statements as the parameter limit needs, one after another so a long list\n * holds one connection rather than the pool. Each group runs until `signal`\n * aborts, and `runUntil` checks it before building the next, so an aborted\n * resolve sends no further group (0061).\n */\nasync function findKeys(\n pool: ConnectionPool,\n config: LookupConfig,\n keys: readonly (readonly string[])[],\n terms: readonly RowFilterTerm[],\n withDisplay: boolean,\n signal: LookupSignal,\n): Promise<FoundRow[]> {\n const found: FoundRow[] = []\n for (const group of keyGroups(config, keys, terms.length)) {\n const rows = await runUntil<Row>(pool, keysStatement(config, group, terms, withDisplay), signal)\n for (const row of rows) found.push(foundRow(config, row))\n }\n return found\n}\n\n/**\n * The lookup half of the SQL Server adapter, through a pool the composition\n * root connected.\n *\n * Every answer is decided by `@formancy/data-core`'s helpers — which tokens\n * are asked about, how a page knows there is more, when a token is a member —\n * and this only queries. The filters are read with `rowFilterTerms` before\n * anything is built, so a request without a policy fails instead of seeing\n * every row, and they are part of the same statement as the rest.\n *\n * What SQL Server decides on its own, and the adapter does not hide: how a\n * search matches and how text orders is the column's collation, so on a\n * case-insensitive database a search for `muster` finds `Muster AG` and\n * `apple` sorts before `Banana`; and equality ignores trailing spaces, which\n * is why membership is the re-encoded row's and never the database's match\n * (0012). A filter is the exception: it compares the column's canonical value\n * with its trusted value exactly — case, accents and trailing spaces count —\n * as PostgreSQL's does, and still seeks an nvarchar column's index\n * (../sql/filters.ts, 0028). A label is the record reader's value, spelled by\n * `displayText`, so it reads the same on both engines.\n *\n * A database error propagates: a lookup that cannot answer refuses, and\n * formancy turns that into a refused submission.\n *\n * Every statement runs until the caller's signal aborts, and is then stopped\n * in the database by `request.cancel()`, a TDS attention (0061,\n * ../sql/statement.ts). A signal already aborted is refused before the\n * filters are read or a key is parsed, so a request already gone costs\n * nothing. The pool is the one records use: an attention travels on the\n * statement's own connection, so unlike PostgreSQL's cancel request it\n * cannot stop anyone else's statement. No per-request `requestTimeout` is\n * set; mssql's default of 15 s, which it hands tedious for every request\n * (lib/tedious/connection-pool.js), still bounds every statement.\n */\nexport function createSqlServerLookups(pool: ConnectionPool): LookupAdapter {\n return {\n async search(config, query, filters, signal) {\n stopIfAborted(signal)\n const terms = rowFilterTerms(filters)\n const rows = await runUntil<Row>(pool, pageStatement(config, query, terms), signal)\n return lookupPage(\n config,\n rows.map((row) => foundRow(config, row)),\n query.limit,\n )\n },\n\n async resolve(config, tokens, filters, signal) {\n stopIfAborted(signal)\n const terms = rowFilterTerms(filters)\n const keys = lookupKeys(config, tokens)\n if (keys.length === 0) return []\n return resolvedRows(config, tokens, await findKeys(pool, config, keys, terms, true, signal))\n },\n\n async rejects(config, tokens, filters, signal) {\n stopIfAborted(signal)\n const terms = rowFilterTerms(filters)\n const keys = lookupKeys(config, tokens)\n const found = keys.length === 0 ? [] : await findKeys(pool, config, keys, terms, false, signal)\n return rejectedTokens(\n tokens,\n found.map((row) => row.key),\n )\n },\n }\n}\n","import { createHash } from 'node:crypto'\nimport { inSnapshotOrder } from '@formancy/data-core'\nimport type { DescribedTable } from '@formancy/data-core'\nimport { DESCRIBED_OBJECT } from '../discovery/catalog.js'\nimport { COLUMN_DEFINITION, COLUMN_SOURCE, describedColumn } from '../discovery/columns.js'\nimport type { ColumnDefinitionRow } from '../discovery/columns.js'\nimport { FOREIGN_KEYS_SQL, foreignKeysOf } from '../discovery/foreign-keys.js'\nimport type { ForeignKeyRow } from '../discovery/foreign-keys.js'\nimport { keysOf } from '../discovery/keys.js'\nimport type { KeyRow } from '../discovery/keys.js'\nimport { KEYS_SQL } from '../discovery/keys.js'\nimport { OBJECT_KIND } from '../discovery/objects.js'\n\n/*\n * The root's definition on SQL Server (0041): the facts one statement reads\n * of a table's catalog, as one FOR JSON text, and its SHA-256 by HASHBYTES,\n * which a write's batch checks after its statement, under the statement's\n * locks, and again in CATCH.\n *\n * Every fact is read by discovery's own query for its concern -- the column\n * definition list, the keys, the foreign keys, the object's kind and filter\n * (`discovery/*.ts`) -- scoped to the one object, and becomes metadata\n * through discovery's own row functions, so a fact discovery adds is the\n * definition's too. Measured on mssql/server:2022-latest (the probes before\n * this record, 2026-10-10): with an ORDER BY in every nested FOR JSON the\n * text was byte-stable over 2,250 executions across sessions, accounts and\n * every language, date and ANSI setting tried, and Node's SHA-256 of its\n * UTF-16LE was HASHBYTES' every time. One setting cuts it: under a small\n * TEXTSIZE the text the client receives is cut while HASHBYTES covers it\n * whole, which `describedFrom` refuses as `unavailable`.\n *\n * Nothing here reads a privilege or a comment: a grant to another account,\n * or a description added, is not a new definition.\n */\n\n/**\n * The facts of the object whose quoted name the parameter `table` holds, as\n * one JSON text; NULL when the catalog shows no such object as discovery\n * would describe it.\n */\nexport function factsOf(table: string): string {\n const scoped = '(o.object_id)'\n return `(select ${OBJECT_KIND} as [kind], o.object_id as [object],\n (select ${COLUMN_DEFINITION} from ${COLUMN_SOURCE} where c.object_id = o.object_id order by c.column_id for json path, include_null_values) as [columns],\n (${KEYS_SQL(scoped)} for json path, include_null_values) as [keys],\n (${FOREIGN_KEYS_SQL(scoped)} for json path, include_null_values) as [foreignKeys]\n from sys.objects o\n where o.object_id = object_id(${table}) and ${DESCRIBED_OBJECT}\n for json path, without_array_wrapper, include_null_values)`\n}\n\n/** The SHA-256 of a facts text, as varbinary(32); NULL for NULL. */\nexport function digestOf(facts: string): string {\n return `hashbytes('SHA2_256', ${facts})`\n}\n\n/** A definition this adapter made: a SHA-256 in hex. */\nconst DEFINITION = /^[0-9a-f]{64}$/\n\n/** The definition's bytes, to bind as varbinary(32); a definition this adapter did not make is a programming error. */\nexport function definitionBytes(token: string): Buffer {\n if (typeof token !== 'string' || !DEFINITION.test(token)) throw new Error('A write carries the definition this adapter described the table with: a SHA-256 in hex.')\n return Buffer.from(token, 'hex')\n}\n\ninterface Facts {\n kind: 'table' | 'view'\n columns: ColumnDefinitionRow[] | null\n keys: KeyRow[] | null\n foreignKeys: ForeignKeyRow[] | null\n}\n\n/**\n * The description, from the facts text and the digest the same statement\n * computed: `undefined` when there are no facts, `cut` when the text that\n * arrived is not the text that was hashed -- a TEXTSIZE shorter than it.\n */\nexport function describedFrom(facts: string | null, digest: Buffer | null): DescribedTable | 'cut' | undefined {\n if (facts === null || digest === null) return undefined\n if (!createHash('sha256').update(Buffer.from(facts, 'utf16le')).digest().equals(digest)) return 'cut'\n const parsed = JSON.parse(facts) as Facts\n const keys = keysOf(parsed.keys ?? [])\n return inSnapshotOrder({\n kind: parsed.kind,\n columns: (parsed.columns ?? []).map(describedColumn),\n primaryKey: keys.primaryKey,\n uniqueKeys: keys.uniqueKeys,\n // A target hidden from the account is a gap discovery reports; the description keeps none.\n foreignKeys: foreignKeysOf(parsed.foreignKeys ?? [], []),\n definition: digest.toString('hex'),\n })\n}\n","import type { InsertRequest, ObjectRef, ReadRequest, RecordColumn, RecordConcurrency, RecordTarget, RecordValue, RowFilterTerm, ThroughTerms, UpdateRequest } from '@formancy/data-core'\nimport mssql from 'mssql'\nimport { quoteName, quoteTable } from '../sql/quote.js'\nimport { Parameters } from '../sql/statement.js'\nimport type { Statement } from '../sql/statement.js'\nimport { exactText, filterPredicate } from '../sql/filters.js'\nimport { bindValue, canonicalText, fromText, isExactKey } from '../sql/values.js'\nimport type { ExactKey } from '../sql/values.js'\nimport { digestOf, factsOf } from './definition.js'\n\n/**\n * The SQL of each record operation. Every statement selects the same shape —\n * `[found]`, then `[c0]`, `[c1]`, … the canonical text of each requested\n * column, then `[version]` — so one function in records.ts reads all of them.\n *\n * The write batches raise errors of their own, below. A user error number is\n * anybody's — a customer's trigger may THROW 51701 too — so errors.ts takes\n * one as the adapter's only when its message is exactly the adapter's.\n */\n\n/** Raised when a text column did not store the text it was sent: a varchar whose code page lacks a character, or that drops trailing spaces. */\nexport const TEXT_NOT_STORED = 51701\n/** Its message: the index of the written value, in the request's order. */\nexport const TEXT_NOT_STORED_MESSAGE = /^formancy: text not stored as sent: ([0-9]+)$/\n/** Raised when an update matched more than one row: an identity that is not a key. */\nexport const NOT_ONE_ROW = 51702\nexport const NOT_ONE_ROW_MESSAGE = 'formancy: the identity matched more than one row'\n/** Raised when an enabled INSTEAD OF trigger decides what the write stores. An account that cannot see the table is refused before, by the definition's check (0041). */\nexport const DECIDED_BY_TRIGGER = 51703\nexport const DECIDED_BY_TRIGGER_MESSAGE = 'formancy: an INSTEAD OF trigger decides what this write stores'\n/** Raised when a trigger ended the write's transaction and began another. */\nexport const TRANSACTION_REPLACED = 51704\nexport const TRANSACTION_REPLACED_MESSAGE = 'formancy: a trigger ended the transaction of the write and began another'\n/** Raised from CATCH when the error came after a trigger had ended the write's transaction: it may have committed (0031). */\nexport const TRANSACTION_ENDED = 51705\nexport const TRANSACTION_ENDED_MESSAGE = 'formancy: a trigger ended the transaction of the write and then raised an error'\n/** Raised when the table's definition is not the one the write was decided over (0041), after the statement or in CATCH. */\nexport const DEFINITION_MOVED = 51706\nexport const DEFINITION_MOVED_MESSAGE = 'formancy: table definition moved'\n/** Raised when a delete's account cannot see every key that refers to a table the delete reaches, or one acts on the delete that it was not decided over (0050, 0051). */\nexport const REACH_MOVED = 51707\nexport const REACH_MOVED_MESSAGE = 'formancy: what refers to the table moved'\n/** Raised when a delete's account may not DELETE from a table past the root the delete reaches (0051). */\nexport const REACH_UNDELETABLE = 51708\nexport const REACH_UNDELETABLE_MESSAGE = 'formancy: this account may not delete from a table the delete reaches'\n\n/** A version as it is compared: the 8 bytes of a rowversion, or a version column's decimal string. */\nexport type ExpectedVersion = { kind: 'rowversion'; bytes: Buffer } | { kind: 'version-column'; value: string }\n\n/** One column of what a statement returns: its name in the result, its type in a table variable, and the SQL that computes it. */\nexport interface Selected {\n name: string\n declared: string\n expression: string\n}\n\n/**\n * What every statement returns, from `source` — `[r].` for the table, `inserted.`\n * for an OUTPUT clause. `[found]` is always there, so a request for no\n * columns is still a statement. A rowversion comes back as its 8 bytes, which\n * `encodeRowversion` spells, so the adapter and the core cannot spell a token\n * two ways; a version column as its decimal text.\n */\nexport function selection(columns: readonly RecordColumn[], concurrency: RecordConcurrency | null, source: string): Selected[] {\n const selected: Selected[] = [{ name: '[found]', declared: 'int', expression: '1' }]\n columns.forEach((column, index) => {\n selected.push({ name: `[c${String(index)}]`, declared: 'nvarchar(max)', expression: canonicalText(column.type, `${source}${quoteName(column.name)}`) })\n })\n if (concurrency !== null) selected.push(versionOf(concurrency, source))\n return selected\n}\n\nfunction versionOf(concurrency: RecordConcurrency, source: string): Selected {\n const column = `${source}${quoteName(concurrency.column)}`\n return concurrency.kind === 'rowversion'\n ? { name: '[version]', declared: 'binary(8)', expression: column }\n : { name: '[version]', declared: 'nvarchar(20)', expression: `convert(nvarchar(20), ${column})` }\n}\n\n/**\n * The alias of the target table in every record statement but an insert, so\n * that every column a statement names says which table it is of: a\n * correlated subquery over another table, or over the same one, can then\n * never bind a bare name to the wrong row.\n */\nexport const ROW = '[r]'\n\nfunction column(name: string): string {\n return `${ROW}.${quoteName(name)}`\n}\n\nexport function keyPredicates(parameters: Parameters, key: readonly RecordValue[]): string[] {\n return key.map((value) => `${column(value.name)} = ${bindValue(parameters, value.type, value.value)}`)\n}\n\n/** The trusted filters, each comparing the column's canonical value exactly (../sql/filters.ts, 0028). */\nexport function filterPredicates(parameters: Parameters, terms: readonly RowFilterTerm[]): string[] {\n return terms.map((term) => filterPredicate(parameters, column(term.column), term))\n}\n\n/** The alias of a through's target inside its EXISTS. */\nconst PARENT = '[p]'\n\n/**\n * One through (0043) as a condition on the record: its parent row, the one\n * the record's foreign-key columns reference, is one the target's filter\n * admits. An EXISTS in the statement itself, under the statement's own\n * locks. The pair compares with `=`, as the foreign key does; the filter\n * terms compare exactly (0028). Every column is qualified, so a key onto the\n * same table compares the parent's key with the record's column and never a\n * row with itself. A record whose foreign key is NULL matches no parent.\n */\nexport function throughPredicate(parameters: Parameters, through: ThroughTerms): string {\n const pairs = through.pairs.map((pair) => `${PARENT}.${quoteName(pair.references)} = ${column(pair.column)}`)\n const terms = through.terms.map((term) => filterPredicate(parameters, `${PARENT}.${quoteName(term.column)}`, term))\n return `exists (select 1 from ${quoteTable(through.target)} as ${PARENT} where ${[...pairs, ...terms].join(' and ')})`\n}\n\n/** What locates a record in every statement but an insert: its key, the trusted filters and every through. */\nexport function located(parameters: Parameters, key: readonly RecordValue[], terms: readonly RowFilterTerm[], through: readonly ThroughTerms[]): string[] {\n return [...keyPredicates(parameters, key), ...filterPredicates(parameters, terms), ...through.map((entry) => throughPredicate(parameters, entry))]\n}\n\n/** The table's quoted name, bound as `object_id` reads it. */\nexport function tableName(parameters: Parameters, table: ObjectRef): string {\n return parameters.add(mssql.NVarChar(mssql.MAX), quoteTable(table))\n}\n\n/** One column of a table's description: its name in the result, and the SQL that computes it. */\nexport interface DescribedColumnSql {\n name: string\n expression: string\n}\n\n/** The table's facts and their digest, as `[facts]` and `[digest]` of a derived table `[f]`. */\nexport function described(parameters: Parameters, table: ObjectRef): { columns: DescribedColumnSql[]; from: string } {\n return {\n columns: [\n { name: '[facts]', expression: '[f].[facts]' },\n { name: '[digest]', expression: digestOf('[f].[facts]') },\n ],\n from: `(select ${factsOf(tableName(parameters, table))} as [facts]) as [f]`,\n }\n}\n\n/** A description's columns as a select list. */\nfunction describedSelect(columns: readonly DescribedColumnSql[]): string {\n return columns.map((column) => `${column.expression} as ${column.name}`).join(', ')\n}\n\n/** The table's description, in one statement: its facts and their digest. */\nexport function describeStatement(table: ObjectRef): Statement {\n const parameters = new Parameters()\n const { columns, from } = described(parameters, table)\n return parameters.statement(`select ${describedSelect(columns)} from ${from}`)\n}\n\n/**\n * One record under the filters, with the table as this same statement found\n * it (0041): one statement, which holds a schema-stability lock on the table\n * while it runs, so no ALTER lands between the facts and the record.\n * `top (2)`, so an identity that matched more than one row is noticed\n * without reading every row it matched; one row with a NULL `[found]` when\n * none is inside the filters.\n */\nexport function readStatement(request: ReadRequest, terms: readonly RowFilterTerm[], through: readonly ThroughTerms[]): Statement {\n const parameters = new Parameters()\n const { columns, from } = described(parameters, request.target.table)\n const where = located(parameters, request.key, terms, through)\n const record = selection(request.columns, request.target.concurrency, `${ROW}.`).map((selected) => `${selected.expression} as ${selected.name}`)\n return parameters.statement(\n `select ${describedSelect(columns)}, [record].* from ${from} outer apply (select top (2) ${record.join(', ')} from ${quoteTable(request.target.table)} as ${ROW} where ${where.join(' and ')}) as [record]`,\n )\n}\n\n/**\n * Whether a record is there for this actor -- what tells a stale update from\n * one aimed at nothing -- and whether the table's definition is still the\n * one the update was decided over (0041), which comes first. Located as the\n * update is, inside the filters and every through (0043), so a record outside\n * them is not found whatever version was sent.\n */\nexport function existsStatement(request: Pick<UpdateRequest, 'target' | 'key'>, terms: readonly RowFilterTerm[], through: readonly ThroughTerms[], definition: Buffer): Statement {\n const parameters = new Parameters()\n const table = request.target.table\n const same = `case when ${digestOf(factsOf(tableName(parameters, table)))} = ${parameters.add(mssql.VarBinary(32), definition)} then 1 else 0 end`\n const where = located(parameters, request.key, terms, through)\n return parameters.statement(`select (select count(*) from ${quoteTable(table)} as ${ROW} where ${where.join(' and ')}) as [found], ${same} as [same]`)\n}\n\n/** A value a write assigns — an insert's VALUES or an update's SET — and the SQL it was bound as. */\nexport interface Assigned {\n value: RecordValue\n sql: string\n}\n\n/** What reads a written row's version back: the key it captures, the variables it holds it in, and the statements. */\ninterface Refind {\n captured: Selected[]\n declared: string[]\n statements: string[]\n}\n\n/**\n * Reads the version back from the row itself, after the statement and its\n * AFTER triggers and before the commit. OUTPUT saw the row before a trigger\n * that touches it — an audit column, a version the application's own trigger\n * moves — changed its version again; a token taken from OUTPUT would be stale\n * before anyone held it, and refuse the next save.\n *\n * The row is found by its identity as the statement wrote it, a generated one\n * included, captured as canonical text and converted back as a bound key is,\n * so it is found exactly as a later save names it. The text goes through\n * variables rather than a join on the table variable, whose column would\n * bring the database's collation into the comparison and conflict with a key\n * column's own (468). A target with no identity, or with a key column of\n * another kind — a time or an instant, whose text is cut short, a boolean or\n * a float, which do not travel as text — keeps the version the statement saw.\n */\nfunction versionAfterTriggers(target: RecordTarget): Refind {\n const keys = target.identity.map((column, index) => ({ column: quoteName(column.name), type: column.type, variable: `@i${String(index)}`, name: `[i${String(index)}]` }))\n const exact = (key: (typeof keys)[number]): key is (typeof keys)[number] & { type: ExactKey } => isExactKey(key.type)\n if (target.concurrency === null || keys.length === 0 || !keys.every(exact)) return { captured: [], declared: [], statements: [] }\n const where = keys.map((key) => `[stored].${key.column} = ${fromText(key.type, key.variable)}`)\n const version = versionOf(target.concurrency, '[stored].')\n return {\n captured: keys.map((key) => ({ name: key.name, declared: 'nvarchar(max)', expression: canonicalText(key.type, `inserted.${key.column}`) })),\n declared: [`declare ${keys.map((key) => `${key.variable} nvarchar(max)`).join(', ')};`],\n statements: [\n `select ${keys.map((key) => `${key.variable} = ${key.name}`).join(', ')} from @written;`,\n `update [written] set [version] = ${version.expression} from @written as [written] cross join ${quoteTable(target.table)} as [stored] where ${where.join(' and ')};`,\n ],\n }\n}\n\n/**\n * Whether an INSTEAD OF trigger decides what this write stores. Such a\n * trigger runs in place of the statement, and OUTPUT returns the row as if\n * the statement had run — the identity 0, the values before the trigger\n * changed them, a row for an update that changed nothing — so nothing the\n * batch reads says what the trigger stored, and the write is refused.\n *\n * Asked of the catalog after the statement, so a table that is not there has\n * already failed it as schema-changed (208), and after the definition's\n * check, so a table the account writes but cannot see in the catalog --\n * denied VIEW DEFINITION, `object_id` NULL to it -- has already failed that\n * as a moved definition (51706): its facts are NULL. Whether a trigger\n * decides such a write cannot be told, and it is refused either way: fail\n * closed. Before 0041 this check refused it itself, by `object_id` being\n * NULL; that branch could no longer be reached and is gone. The table's\n * name is bound, as `object_id` reads it.\n */\nfunction insteadOfGuard(name: string, operation: Write['operation']): string {\n const deciding =\n 'select 1 from sys.triggers as [t] join sys.trigger_events as [e] on [e].[object_id] = [t].[object_id] ' +\n `where [t].[parent_id] = object_id(${name}) and [t].[is_instead_of_trigger] = 1 and [t].[is_disabled] = 0 and [e].[type_desc] = N'${operation}'`\n return `if exists (${deciding}) throw ${String(DECIDED_BY_TRIGGER)}, N'${DECIDED_BY_TRIGGER_MESSAGE}', 1;`\n}\n\n/**\n * Whether the table still has the definition the write was decided over\n * (0041), as a statement: NULL-safe, because `NULL <> x` is not true and a\n * table the catalog no longer shows hashes to NULL.\n */\nfunction definitionGuard(table: string, definition: string): string[] {\n return [`set @d = ${digestOf(factsOf(table))};`, `if @d is null or @d <> ${definition} throw ${String(DEFINITION_MOVED)}, N'${DEFINITION_MOVED_MESSAGE}', 1;`]\n}\n\n/** One write: the statement given its OUTPUT clause, what it assigns, what it returns, and what is checked straight after it. */\nexport interface Write {\n target: RecordTarget\n /** The definition it was decided over (0041). */\n definition: Buffer\n /** `DELETE` since 0050: it assigns nothing, and its row is not there to read a version back from. */\n operation: 'INSERT' | 'UPDATE' | 'DELETE'\n statement: (output: string) => string\n assigned: readonly Assigned[]\n returned: Selected[]\n /** Checks that may read `@rows`, the rows the statement changed. */\n afterWrite: readonly string[]\n}\n\n/**\n * The batch every write runs in, so that what it stored is checked before it\n * commits, and nothing it did outlives an error:\n *\n * - `OUTPUT … INTO` a table variable, never a bare `OUTPUT`, which SQL Server\n * refuses (334) on a table with an enabled trigger. The output is the row as\n * the statement wrote it, before any AFTER trigger changed it; the version\n * is read back from the row afterwards (`versionAfterTriggers`).\n * - The transaction is the one the batch began. A trigger that rolls it back\n * and begins another leaves `@@trancount` as it was, so nothing is raised,\n * and the commit would commit an empty transaction over a write that is\n * gone; one that commits it and begins another has stored the write. The\n * batch cannot tell the two apart, and says so (errors.ts). CATCH asks the\n * same question: a trigger that committed and then raised an error of its\n * own has stored the write, and its error is not the refusal it looks\n * like. Measured (0031): in CATCH the transaction is no longer the one the\n * batch began after a trigger's COMMIT, its COMMIT and BEGIN, and its\n * ROLLBACK, and still is after a constraint's error or a trigger that only\n * raises. So the error is replaced by one that says the transaction ended\n * -- unknown-outcome, over-reported for the ROLLBACK -- unless it is 3609\n * or the batch's own replaced-transaction error, which already say so.\n * - No INSTEAD OF trigger decided what was stored (`insteadOfGuard`).\n * - Every text value is compared with what its column stored, exactly, and a\n * difference rolls the write back: SQL Server converts nvarchar to a\n * single-byte varchar without an error, a character its code page lacks\n * becoming its \"best fit\" or `?` (0017), and a varchar created under\n * ANSI_PADDING OFF drops trailing spaces without one (C12, 0028). The stored\n * side is canonical text, a char(n)'s padding trimmed, so one comparison\n * (`exactText`) serves both lengths. OUTPUT shows the row before an AFTER\n * trigger changed it, so this sees what the statement stored, not a trigger.\n * - TRY…CATCH rolls back on every error it catches, then rethrows it as it\n * was. xact_abort alone does not: a trigger's RAISERROR, unlike THROW, ends\n * nothing, so the statement and the commit would run and the driver would\n * still report the error — a refusal over a write that committed.\n * - `xact_abort`, for what CATCH cannot catch in its own scope: a table\n * missing when the batch compiles is resolved only when its statement\n * runs, after `begin transaction`, and without xact_abort its 208 leaves\n * the transaction open on the pooled connection. Both settings end with the\n * request, which runs inside `sp_executesql` (../sql/statement.ts).\n * - The table's definition is the one the write was decided over (0041),\n * read after the statement, while its locks keep any ALTER out: ALTER\n * needs a schema-modification lock, which waits for this transaction. And\n * again in CATCH, after the rollback: a statement that failed against a\n * moved table -- 'many' into a column retyped to int, 245 -- is answered\n * as the move. Only while the transaction is still the batch's own: one a\n * trigger ended is answered as ended, 3609, 51704 or 51705, before the\n * catalog is read, because the trigger may have committed the write\n * (0031). Measured: asked first, the definition answered \"nothing was\n * written\" over a row a trigger's COMMIT had stored. The catalog reads in\n * CATCH even when the transaction was doomed, once it is rolled back\n * (measured, the probes before 0041).\n */\nexport function writeBatch(parameters: Parameters, { target, definition, operation, statement, assigned, returned, afterWrite }: Write): string {\n const guarded = assigned.flatMap(({ value, sql }, index) => (value.type.kind === 'text' && value.value !== null ? [{ value, sql, index }] : []))\n const stored = guarded.map(({ value }, position) => ({\n name: `[w${String(position)}]`,\n declared: 'nvarchar(max)',\n expression: canonicalText(value.type, `inserted.${quoteName(value.name)}`),\n }))\n // A deleted row's version is the one OUTPUT saw it deleted at: the row is\n // gone, and one a trigger inserted again is another row's to read (0050).\n const refind: Refind = operation === 'DELETE' ? { captured: [], declared: [], statements: [] } : versionAfterTriggers(target)\n const table = tableName(parameters, target.table)\n const moved = definitionGuard(table, parameters.add(mssql.VarBinary(32), definition))\n const captured = [...returned, ...stored, ...refind.captured]\n const output = `output ${captured.map((column) => column.expression).join(', ')} into @written (${captured.map((column) => column.name).join(', ')})`\n const checks = guarded.map(\n ({ sql, index }, position) =>\n `if exists (select 1 from @written where not (${exactText(`[w${String(position)}]`, sql)})) ` +\n `throw ${String(TEXT_NOT_STORED)}, N'formancy: text not stored as sent: ${String(index)}', 1;`,\n )\n return [\n 'set nocount on;',\n 'set xact_abort on;',\n `declare @written table (${captured.map((column) => `${column.name} ${column.declared}`).join(', ')});`,\n 'declare @transaction bigint, @rows int, @ended bit, @d varbinary(32);',\n ...refind.declared,\n 'begin try',\n 'begin transaction;',\n 'set @transaction = current_transaction_id();',\n `${statement(output)};`,\n 'set @rows = @@rowcount;',\n `if coalesce(current_transaction_id(), 0) <> @transaction throw ${String(TRANSACTION_REPLACED)}, N'${TRANSACTION_REPLACED_MESSAGE}', 1;`,\n ...moved,\n insteadOfGuard(table, operation),\n ...afterWrite,\n ...checks,\n ...refind.statements,\n 'commit transaction;',\n 'end try',\n 'begin catch',\n 'set @ended = case when coalesce(current_transaction_id(), 0) <> @transaction then 1 else 0 end;',\n 'if @@trancount > 0 rollback transaction;',\n `if @ended = 1 and error_number() <> 3609 and not (error_number() = ${String(TRANSACTION_REPLACED)} and error_message() = N'${TRANSACTION_REPLACED_MESSAGE}') ` +\n `throw ${String(TRANSACTION_ENDED)}, N'${TRANSACTION_ENDED_MESSAGE}', 1;`,\n 'if @ended = 1 throw;',\n ...moved,\n 'throw;',\n 'end catch;',\n `select ${returned.map((column) => column.name).join(', ')} from @written;`,\n ].join('\\n')\n}\n\n/** Exactly the given columns, so a column with a default gets it and a generated one is never named. */\nexport function insertStatement(request: InsertRequest, definition: Buffer): Statement {\n const parameters = new Parameters()\n const assigned = request.values.map((value) => ({ value, sql: bindValue(parameters, value.type, value.value) }))\n const table = quoteTable(request.target.table)\n const columns = assigned.map(({ value }) => quoteName(value.name)).join(', ')\n const values = assigned.map(({ sql }) => sql).join(', ')\n const sql = writeBatch(parameters, {\n target: request.target,\n definition,\n operation: 'INSERT',\n statement: (output) => (assigned.length === 0 ? `insert into ${table} ${output} default values` : `insert into ${table} (${columns}) ${output} values (${values})`),\n assigned,\n returned: selection(request.returning, request.target.concurrency, 'inserted.'),\n afterWrite: [],\n })\n return parameters.statement(sql)\n}\n\n/** Whether the row's version is still the one expected: a rowversion's 8 bytes, or a version column compared as a bigint. An update's and a delete's (0050). */\nexport function versionIs(parameters: Parameters, concurrency: RecordConcurrency, expected: ExpectedVersion): string {\n const version = column(concurrency.column)\n return expected.kind === 'rowversion'\n ? `${version} = ${parameters.add(mssql.VarBinary(8), expected.bytes)}`\n : `${version} = convert(bigint, ${parameters.add(mssql.NVarChar(mssql.MAX), expected.value)})`\n}\n\n/**\n * ONE guarded statement (0015): the key, the trusted filters, every through\n * (0043) and the expected version in a single WHERE, and for a version column\n * the increment in the same SET, so nothing can change between the check and\n * the write. A row the filters or a through exclude is not matched, so another\n * tenant's record cannot be changed even with its current version in hand.\n * More than one row matched means the identity is not a key, and the batch\n * rolls back rather than change several. The table is aliased, `update [r]\n * … from <table> as [r]`, so that the through's EXISTS can name the row.\n */\nexport function updateStatement(request: UpdateRequest, terms: readonly RowFilterTerm[], through: readonly ThroughTerms[], expected: ExpectedVersion, definition: Buffer): Statement {\n const parameters = new Parameters()\n const { target } = request\n const assigned = request.set.map((value) => ({ value, sql: bindValue(parameters, value.type, value.value) }))\n // A SET names a column of the table updated, so it is not qualified; what it is set from is.\n const set = assigned.map(({ value, sql }) => `${quoteName(value.name)} = ${sql}`)\n const version = column(target.concurrency.column)\n if (target.concurrency.kind === 'version-column') set.push(`${quoteName(target.concurrency.column)} = ${version} + 1`)\n const where = [...located(parameters, request.key, terms, through), versionIs(parameters, target.concurrency, expected)]\n const sql = writeBatch(parameters, {\n target,\n definition,\n operation: 'UPDATE',\n statement: (output) => `update ${ROW} set ${set.join(', ')} ${output} from ${quoteTable(target.table)} as ${ROW} where ${where.join(' and ')}`,\n assigned,\n returned: selection(request.returning, target.concurrency, 'inserted.'),\n afterWrite: [`if @rows > 1 throw ${String(NOT_ONE_ROW)}, N'${NOT_ONE_ROW_MESSAGE}', 1;`],\n })\n return parameters.statement(sql)\n}\n","import type { DeleteRequest, DeleteTerms, ObjectRef, ReachTerms } from '@formancy/data-core'\nimport mssql from 'mssql'\nimport { DENIED_OBJECTS, DENIED_SCHEMAS, VIEWS_DATABASE } from '../discovery/visibility.js'\nimport { quoteTable } from '../sql/quote.js'\nimport { Parameters } from '../sql/statement.js'\nimport type { Statement } from '../sql/statement.js'\nimport {\n located,\n NOT_ONE_ROW,\n NOT_ONE_ROW_MESSAGE,\n REACH_MOVED,\n REACH_MOVED_MESSAGE,\n REACH_UNDELETABLE,\n REACH_UNDELETABLE_MESSAGE,\n ROW,\n selection,\n tableName,\n versionIs,\n writeBatch,\n} from './statements.js'\nimport type { ExpectedVersion } from './statements.js'\n\n/*\n * The delete of one record on SQL Server (0050): one statement in the write\n * batch every write runs in, checked after it and before the commit.\n */\n\n/** sys.foreign_keys' `delete_referential_action` for each action a delete acts through. */\nconst ACTION_CODES: Readonly<Record<ReachTerms['accepted'][number]['onDelete'], number>> = { cascade: 1, 'set-null': 2, 'set-default': 3 }\n\n/** A table's name as `object_id` and HAS_PERMS_BY_NAME read it: quoted, and bound. */\nconst named = (parameters: Parameters, table: ObjectRef): string => tableName(parameters, table)\n\n/**\n * Whether the account still sees every key that refers to a table the delete\n * reaches, and every key that acts on it is one the reach accepts, as a\n * statement that raises 51707 when either fails (0050, 0051). The planner\n * refuses a grant over any other key by the snapshot (`deleteProblems`);\n * this is the same rule asked of the catalog inside the delete's\n * transaction, so a key added after the form was published is refused\n * there, and whatever its cascade did is rolled back with it.\n *\n * A key that acts on delete -- cascades, sets NULL or sets a default --\n * onto a table the delete removes rows of is accepted only as the reach\n * names it: the table it is on, its name, the table it refers to and its\n * action, the name compared under Latin1_General_100_BIN2, never under the\n * database's collation. A key that refers to a column the delete clears and\n * acts ON UPDATE would carry the change on, and is refused whatever it is.\n *\n * Run after the statement, under its locks: ADD FOREIGN KEY ... REFERENCES\n * a table needs a schema-modification lock, which waits for this\n * transaction. An edge constraint that cascades acts on a delete of a node\n * as such a key does, from either end of each of its clauses (0049, P2b),\n * and sys.foreign_keys does not list it, so sys.edge_constraints is read\n * too; none is ever accepted, since the snapshot names one only as a gap.\n *\n * SQL Server lists a key only to an account that may see the table the key\n * is on (0049, P2), so the catalog alone could miss one. The account sees\n * every key exactly under discovery's own conditions for a snapshot without\n * a `referenced-by` gap -- VIEW DEFINITION on the database, and no VIEW\n * DEFINITION or CONTROL deny on an object or a schema that binds it --\n * shared from `visibility.ts`, so the guard and the gap cannot disagree; an\n * account that lost either since its snapshot is refused, whether or not a\n * key is hidden from it. A disabled key is counted: enabled again, it acts\n * without anything here noticing. sys.foreign_keys is read by the\n * referenced object's id through an index seek (measured on 16.0.4295.3,\n * 2026-10-11, P8); the edge constraints' plan and cost are not measured.\n */\nexport function reachGuard(parameters: Parameters, reach: ReachTerms): string {\n const removed = reach.removed.map((table) => `object_id(${named(parameters, table)})`).join(', ')\n const accepted =\n reach.accepted.length === 0\n ? ''\n : ` and not exists (select 1 from (values ${reach.accepted\n .map(\n (key) =>\n `(${named(parameters, key.from)}, ${parameters.add(mssql.NVarChar(mssql.MAX), key.name)}, ${named(parameters, key.onto)}, ${parameters.add(mssql.TinyInt, ACTION_CODES[key.onDelete])})`,\n )\n .join(', ')}) as [a]([from], [key], [onto], [action])\n where [k].[parent_object_id] = object_id([a].[from]) and [k].[name] = [a].[key] collate Latin1_General_100_BIN2\n and [k].[referenced_object_id] = object_id([a].[onto]) and [k].[delete_referential_action] = [a].[action])`\n const cleared = reach.cleared.flatMap(({ table, columns }) => columns.map((column) => `(${named(parameters, table)}, ${parameters.add(mssql.NVarChar(mssql.MAX), column)})`))\n const followed =\n cleared.length === 0\n ? []\n : [\n ` or exists (select 1 from sys.foreign_keys as [k] join sys.foreign_key_columns as [c] on [c].[constraint_object_id] = [k].[object_id]`,\n ` join (values ${cleared.join(', ')}) as [x]([table], [column]) on [k].[referenced_object_id] = object_id([x].[table])`,\n ` and col_name([c].[referenced_object_id], [c].[referenced_column_id]) = [x].[column] collate Latin1_General_100_BIN2`,\n ` where [k].[update_referential_action] <> 0)`,\n ]\n return [\n `if coalesce(${VIEWS_DATABASE}, 0) <> 1`,\n ` or exists (select 1 from sys.database_permissions p where ${DENIED_OBJECTS})`,\n ` or exists (select 1 from sys.database_permissions p where ${DENIED_SCHEMAS})`,\n ` or exists (select 1 from sys.foreign_keys as [k] where [k].[referenced_object_id] in (${removed}) and [k].[delete_referential_action] <> 0${accepted})`,\n ` or exists (select 1 from sys.edge_constraints as [ec] join sys.edge_constraint_clauses as [cl] on [cl].[object_id] = [ec].[object_id]`,\n ` where ([cl].[from_object_id] in (${removed}) or [cl].[to_object_id] in (${removed})) and [ec].[delete_referential_action] <> 0)`,\n ...followed,\n ` throw ${String(REACH_MOVED)}, N'${REACH_MOVED_MESSAGE}', 1;`,\n ].join('\\n')\n}\n\n/**\n * Whether the account may DELETE from every table past the root the delete\n * reaches, as a statement that raises 51708 when it may not (0051). SQL\n * Server asks the deleting account nothing of the tables a cascade or a SET\n * NULL reaches -- no grant, and a DENY there does not stop it: measured on\n * 16.0.4295.3, 2026-10-12 (0051 P5) -- so the batch asks, and a delete is held\n * to what its account could have deleted directly, as PostgreSQL's lock holds\n * it. HAS_PERMS_BY_NAME applies grants, denies and their precedence; NULL,\n * for a name it cannot resolve, is a refusal. The root's own DELETE is the\n * statement's to refuse, 229, before anything here runs.\n */\nexport function reachDeletable(parameters: Parameters, reach: ReachTerms): string[] {\n const past = [...reach.removed.slice(1), ...reach.cleared.map((entry) => entry.table)]\n if (past.length === 0) return []\n const tables = past.map((table) => `(${named(parameters, table)})`).join(', ')\n return [\n `if exists (select 1 from (values ${tables}) as [t]([table]) where coalesce(has_perms_by_name([t].[table], N'OBJECT', N'DELETE'), 0) <> 1)`,\n ` throw ${String(REACH_UNDELETABLE)}, N'${REACH_UNDELETABLE_MESSAGE}', 1;`,\n ]\n}\n\n/**\n * ONE guarded delete (0050): the key, the trusted filters, every through and\n * the expected version in a single WHERE, in the write batch, so nothing can\n * change between the check and the delete and nothing it did outlives a\n * check that fails. OUTPUT ... INTO the batch's table variable returns the\n * key and the version the row was deleted at, the root's row alone -- not a\n * row a cascade deleted, measured (0051 P5); an AFTER DELETE trigger runs\n * before the checks, and what it does is the database's (0050). After the\n * statement, in order: the transaction is still the batch's, the definition\n * is the one the delete was decided over (0041), no INSTEAD OF DELETE\n * trigger decided it, the reach is what the delete was decided over and\n * visible (`reachGuard`), the account may delete from every table of it\n * (`reachDeletable`, 0051), and one row or none was deleted -- more is an\n * identity that is not a key, and the batch rolls back rather than delete\n * several.\n */\nexport function deleteStatement(request: DeleteRequest, terms: DeleteTerms, expected: ExpectedVersion, definition: Buffer): Statement {\n const parameters = new Parameters()\n const { target } = request\n const where = [...located(parameters, terms.key, terms.terms, terms.through), versionIs(parameters, target.concurrency, expected)]\n const sql = writeBatch(parameters, {\n target,\n definition,\n operation: 'DELETE',\n statement: (output) => `delete ${ROW} ${output} from ${quoteTable(terms.root)} as ${ROW} where ${where.join(' and ')}`,\n assigned: [],\n returned: selection(target.identity, target.concurrency, 'deleted.'),\n afterWrite: [reachGuard(parameters, terms.reach), ...reachDeletable(parameters, terms.reach), `if @rows > 1 throw ${String(NOT_ONE_ROW)}, N'${NOT_ONE_ROW_MESSAGE}', 1;`],\n })\n return parameters.statement(sql)\n}\n","import type { RecordFailure, RecordFailureCode, RecordValue } from '@formancy/data-core'\nimport {\n DECIDED_BY_TRIGGER,\n DECIDED_BY_TRIGGER_MESSAGE,\n DEFINITION_MOVED,\n DEFINITION_MOVED_MESSAGE,\n NOT_ONE_ROW,\n NOT_ONE_ROW_MESSAGE,\n REACH_MOVED,\n REACH_MOVED_MESSAGE,\n REACH_UNDELETABLE,\n REACH_UNDELETABLE_MESSAGE,\n TEXT_NOT_STORED,\n TEXT_NOT_STORED_MESSAGE,\n TRANSACTION_ENDED,\n TRANSACTION_ENDED_MESSAGE,\n TRANSACTION_REPLACED,\n TRANSACTION_REPLACED_MESSAGE,\n} from './statements.js'\n\n/**\n * What SQL Server's refusals mean, as the stable codes of the record port.\n *\n * The code always comes from the error NUMBER, which does not change with the\n * session's language. The constraint or column a failure names is taken from\n * the message only where it is English — which it is unless the composition\n * root set `options.language`, because `tedious` asks for us_english at login —\n * and is left out otherwise rather than guessed.\n *\n * The server's message is never passed on: it repeats the values a person\n * typed (\"The duplicate key value is (CH)\", \"Truncated value: 'AB'\"), and a\n * failure's message goes to a log. Every sentence here is the adapter's own,\n * and names nothing but the error number, a constraint and a column.\n *\n * Two codes for a refusal nothing else names, as PostgreSQL's adapter has\n * them (0028):\n *\n * - `refused`, the default: the database refused the statement for a reason\n * the port has no code for — a trigger's THROW or RAISERROR, an INSTEAD OF\n * trigger the adapter cannot verify, a number nobody mapped. Nothing was\n * written, and the same request would be refused again.\n * - `unavailable`, only for what SQL Server documents as passing: a deadlock\n * it chose this statement to lose, a lock or resource it could not get in\n * time, a log or filegroup that is full, a database that is read-only or\n * an availability replica that is not accessible now. Nothing was written,\n * and a retry may succeed. Anything not on that list is `refused`, because promising a\n * retry for a business rule invites a person to send it again.\n */\n\n/** Whether the operation could have changed anything: a write was sent, a read never changes a row. */\nexport type Phase = 'read' | 'write'\n\ninterface ServerError {\n number: number\n message: string\n}\n\nconst UNIQUE_KEY = /^Violation of (?:PRIMARY KEY|UNIQUE KEY) constraint '(.+?)'\\. Cannot insert duplicate key in object '/\nconst UNIQUE_INDEX = /^Cannot insert duplicate key row in object '.+?' with unique index '(.+?)'\\. The duplicate key value is /\n/** A foreign key to its own table is FOREIGN KEY SAME TABLE for a reference to no row, SAME TABLE REFERENCE for a row still referenced. */\nconst CONFLICT = /^The [A-Z]+ statement conflicted with the (FOREIGN KEY(?: SAME TABLE)?|(?:SAME TABLE )?REFERENCE|CHECK) constraint \"(.+?)\"\\. The conflict occurred in /\n/** Every translation of 547 keeps these SQL keywords: checked by hand in the 34 languages of SQL Server 2022 on 2026-10-09, and in German by the failures suite. */\nconst FOREIGN_KEY_WORDS = /\\b(?:FOREIGN KEY|REFERENCE)\\b/\nconst NULL_COLUMN = /^Cannot insert the value NULL into column '(.+?)', table '/\nconst TRUNCATED_COLUMN = /^String or binary data would be truncated in table '.+?', column '(.+?)'\\. Truncated value: /\nconst DENIED_COLUMN = /^The [A-Z ]+ permission was denied on the column '(.+?)' of the object '/\nconst INVALID_COLUMN = /^Invalid column name '(.+)'\\.$/\n\n/** Conversions and overflows: a value the codec accepted and the column, or the column's type, could not hold. */\nconst OUT_OF_RANGE: ReadonlySet<number> = new Set([\n 220, // arithmetic overflow for a tinyint or smallint\n 232, // arithmetic overflow for a type\n 244, // a text value overflowed a tinyint or smallint column\n 245, // text that is not a number of the column's type\n 248, // a text value overflowed an int column\n 8114, // text that cannot be converted to the column's type\n 8115, // arithmetic overflow converting to the column's type: money past its range, a version column past its largest value\n])\n\n/**\n * A column the database writes itself, which a binding named for a write: an\n * identity (544 on insert, 8102 on update), a computed column (271), a\n * rowversion (273 on insert, 272 on update — measured, not 273 for both), a\n * GENERATED ALWAYS column such as a system-versioning period's start or end\n * (13536 on insert, 13537 on update). A\n * binding comes to name one when the column became one after discovery, so\n * it is `schema-changed`, as PostgreSQL's 428C9 is (C8, 0028). The parity\n * suite provokes every number here.\n */\nconst GENERATED_COLUMN: ReadonlySet<number> = new Set([544, 8102, 271, 273, 272, 13536, 13537])\n\n/**\n * The refusals SQL Server documents as passing, and the only `unavailable`\n * ones. 1205, a deadlock victim, and 3906, a database switched to read-only,\n * are provoked by the parity suite; the others are by documentation, not\n * provoked.\n */\nconst PASSING: ReadonlySet<number> = new Set([\n 1205, // chosen as a deadlock victim\n 1222, // lock request timed out\n 1204, // no more locks available\n 701, // not enough memory to run the query\n 8645, // timed out waiting for memory to run the query\n 8651, // the memory grant could not be met\n 9002, // the transaction log is full\n 1105, // the filegroup is full\n 3960, // a snapshot isolation update conflict: another transaction changed the row\n 3906, // the database is read-only: PostgreSQL's 25006, a read-only transaction or a standby\n 976, // an availability group database that is not accessible for queries now\n 983, // an availability group database whose replica is in neither role yet\n])\n\n/** The first number SQL Server leaves to users: THROW's and RAISERROR's own. */\nconst FIRST_USER_ERROR = 50000\n\nfunction named(pattern: RegExp, message: string): string | undefined {\n return pattern.exec(message)?.[1]\n}\n\nfunction failure(code: RecordFailureCode, message: string, names: { constraint?: string | undefined; column?: string | undefined } = {}): RecordFailure {\n return {\n ok: false,\n code,\n ...(names.column === undefined ? {} : { column: names.column }),\n ...(names.constraint === undefined ? {} : { constraint: names.constraint }),\n message,\n }\n}\n\n/**\n * Error 547 is a foreign key and a check alike; which one is the constraint\n * the message names. In English the message says so in a fixed sentence; in\n * any other language the kind is the SQL keyword the translation keeps, and\n * the name is left out because its quoting differs per language.\n */\nfunction constraintConflict(message: string): RecordFailure {\n const match = CONFLICT.exec(message)\n const kind = match?.[1]\n const foreignKey = kind === undefined ? FOREIGN_KEY_WORDS.test(message) : kind !== 'CHECK'\n return foreignKey\n ? failure('foreign-key-violation', 'SQL Server refused the write: a foreign key has no row to reference, or a referenced row is still referenced (547).', {\n constraint: match?.[2],\n })\n : failure('check-violation', 'SQL Server refused the write: a check constraint does not accept a value (547).', { constraint: match?.[2] })\n}\n\n/** A trigger ended the transaction the write ran in. Whether by COMMIT or by ROLLBACK, nothing the batch can read says. */\nconst ENDED_BY_TRIGGER = 'it may have committed, and it is not retried.'\n\n/**\n * The write batch's own errors (statements.ts), recognised by number AND\n * message: a customer's trigger may THROW the same number, and its error is\n * then an unrecognised refusal like any other.\n *\n * - An INSTEAD OF trigger that decides the write is `refused`: the batch\n * rolled it back, and the same write would be refused again (0028). Not\n * `schema-changed`, which would claim a binding names something gone, and\n * send someone to a drift review that cannot show a trigger (0017).\n * - A transaction a trigger replaced is `unknown-outcome`: it may have\n * committed the write before beginning another. So is one a trigger ended\n * and then raised an error in: the error is not a refusal of a write the\n * COMMIT stored (0031).\n * - A table whose definition moved is `schema-changed` (0041): the batch\n * found, after its statement or in CATCH, that the table is not the one\n * the write was decided over, and rolled it back. So is a delete whose\n * reach moved, or whose account no longer sees every key (0050).\n */\nfunction ownError(error: ServerError, written: readonly RecordValue[]): RecordFailure | undefined {\n if (error.number === NOT_ONE_ROW && error.message === NOT_ONE_ROW_MESSAGE) {\n // The bindings named an identity that is not a key; the batch rolled back.\n throw new Error('The record identity matched more than one row, so the update was rolled back: the bindings do not name a key.')\n }\n if (error.number === DECIDED_BY_TRIGGER && error.message === DECIDED_BY_TRIGGER_MESSAGE) {\n return failure(\n 'refused',\n 'An INSTEAD OF trigger would decide what this write stores, so the adapter refused it; nothing was written.',\n )\n }\n if (error.number === TRANSACTION_REPLACED && error.message === TRANSACTION_REPLACED_MESSAGE) {\n return failure('unknown-outcome', `A trigger ended the transaction of the write and began another; ${ENDED_BY_TRIGGER}`)\n }\n if (error.number === TRANSACTION_ENDED && error.message === TRANSACTION_ENDED_MESSAGE) {\n return failure('unknown-outcome', `A trigger ended the transaction of the write and then raised an error; ${ENDED_BY_TRIGGER}`)\n }\n if (error.number === DEFINITION_MOVED && error.message === DEFINITION_MOVED_MESSAGE) {\n // The batch rolled the write back, its triggers' work with it (0041).\n return failure('schema-changed', \"The table's definition is not the one this write was decided over; nothing was written.\")\n }\n if (error.number === REACH_MOVED && error.message === REACH_MOVED_MESSAGE) {\n // The batch rolled the delete back, and whatever a key it was not decided over did with it (0050).\n return failure(\n 'schema-changed',\n 'A foreign key now acts on this delete that it was not decided over, or this account can no longer see every key that refers to a table it reaches; nothing was deleted.',\n )\n }\n if (error.number === REACH_UNDELETABLE && error.message === REACH_UNDELETABLE_MESSAGE) {\n // The batch rolled the delete back, and what its cascade did with it (0051).\n return failure('permission-denied', 'This account may not DELETE from a table this delete reaches, so the delete was refused and rolled back; nothing was deleted.')\n }\n const index = error.number === TEXT_NOT_STORED ? TEXT_NOT_STORED_MESSAGE.exec(error.message)?.[1] : undefined\n if (index === undefined) return undefined\n return failure('out-of-range', 'SQL Server did not store this text as sent: its code page lacks a character, or the column drops trailing spaces, and the write was rolled back.', {\n column: written[Number(index)]?.name,\n })\n}\n\n/**\n * A refusal the server reported for this statement, which therefore did not\n * commit: the write batch rolls back on every error it is told of, a\n * trigger's RAISERROR included, and on the errors it cannot catch xact_abort\n * does (statements.ts). Except 3609: a trigger ended the write's transaction\n * itself, and SQL Server raises it alike after a COMMIT, which stored the\n * write, and after a ROLLBACK, which did not. A trigger that commits and then\n * raises an error of its own never reaches here as that error: the batch's\n * CATCH sees its transaction gone and raises its own instead (statements.ts,\n * 0031).\n */\nfunction refusal(error: ServerError, written: readonly RecordValue[]): RecordFailure {\n const own = ownError(error, written)\n if (own !== undefined) return own\n const { number, message } = error\n switch (number) {\n case 3609:\n return failure('unknown-outcome', `A trigger ended the transaction of the write (3609); ${ENDED_BY_TRIGGER}`)\n case 2627:\n case 2601:\n return failure('unique-violation', `SQL Server refused the write: a unique key already holds this value (${String(number)}).`, {\n constraint: named(number === 2627 ? UNIQUE_KEY : UNIQUE_INDEX, message),\n })\n case 547:\n return constraintConflict(message)\n case 515:\n return failure('not-null-violation', 'SQL Server refused the write: a column that does not allow NULL was given none (515).', {\n column: named(NULL_COLUMN, message),\n })\n case 2628:\n return failure('too-long', 'SQL Server refused the write: a value is longer than its column (2628).', { column: named(TRUNCATED_COLUMN, message) })\n case 8152:\n // 2628's predecessor, at compatibility levels below 150: it does not say which column.\n return failure('too-long', 'SQL Server refused the write: a value is longer than its column (8152).')\n case 229:\n case 230:\n return failure('permission-denied', `SQL Server refused this account the operation (${String(number)}).`, { column: named(DENIED_COLUMN, message) })\n case 33504:\n // A security policy's block predicate refused the row, for every\n // principal: the counterpart of PostgreSQL's row-level security WITH\n // CHECK, which is 42501 there (0027). The message names the table, and\n // no column.\n return failure('permission-denied', 'A security policy on this table refused the row this write would store (33504).')\n case 207:\n case 208:\n return failure('schema-changed', `A table or column the binding names is not there any more (${String(number)}).`, {\n column: named(INVALID_COLUMN, message),\n })\n default:\n if (OUT_OF_RANGE.has(number)) return failure('out-of-range', `SQL Server could not hold a value in its column's type (${String(number)}).`)\n if (GENERATED_COLUMN.has(number)) {\n return failure('schema-changed', `A column the binding writes is one SQL Server now generates itself (${String(number)}); nothing was written.`)\n }\n if (PASSING.has(number)) return failure('unavailable', `SQL Server could not complete this now (${String(number)}), and nothing was written.`)\n if (number >= FIRST_USER_ERROR) {\n return failure('refused', `The database refused the statement with an error of its own (${String(number)}), a trigger's or a procedure's, and nothing was written.`)\n }\n // A refusal this adapter does not recognise. It was reported for the\n // statement, and the batch rolled back on it; nothing says it will pass,\n // so it is not `unavailable`. The number is the lead for the log.\n return failure('refused', `SQL Server refused the statement with error ${String(number)}, and nothing was written.`)\n }\n}\n\n/**\n * A refusal SQL Server reported for the statement, with the connection still\n * alive — severity 20 and above end the session.\n *\n * `typeof number === 'number'` is the test, not `number !== undefined`: when\n * the driver's error has no `info` — a socket that closed, a request that\n * timed out — mssql's lib/error/request-error.js copies its `code` into\n * `number`, so a lost answer is a `RequestError` whose number is the string\n * `'ECONNRESET'` or `'ETIMEOUT'`. Read as a number, it would be a refusal,\n * `refused`, a claim that nothing was written over a write that may have\n * committed. records-lost-answer.integration.test.ts pins both (0031).\n */\nfunction serverError(error: Error): ServerError | undefined {\n const { number, class: severity } = error as Error & { number?: unknown; class?: unknown }\n if (error.name !== 'RequestError' || typeof number !== 'number') return undefined\n if (typeof severity === 'number' && severity >= 20) return undefined\n return { number, message: error.message }\n}\n\n/**\n * The failure for what the driver rejected one statement with.\n *\n * - Anything but a `RequestError` is the pool's, from before it handed out a\n * connection: `mssql` turns every failure after that into a `RequestError`\n * (lib/tedious/request.js), and before it passes on what the pool rejected\n * with — its own `ConnectionError` for a pool that is closed or cannot\n * connect, and tarn's `TimeoutError`, unwrapped, when no connection came\n * free within `acquireTimeoutMillis`. Nothing was sent, so even a write is\n * `unavailable`.\n * - The server refused the statement: the code for its error number.\n * - Any other `RequestError` — a timeout, a socket that closed, a session\n * killed (596, severity 21) — after a write was sent is `unknown-outcome`: it\n * may have committed, and it is never retried (plan section 12). After a\n * read it is `unavailable`, because a read changed nothing.\n *\n * A request the driver would not take is thrown before it is sent, and never\n * reaches this. `written` is the values the statement assigned, in its order,\n * so a text value that was not stored can be named.\n */\nexport function failureFor(error: unknown, phase: Phase, written: readonly RecordValue[] = []): RecordFailure {\n if (!(error instanceof Error)) throw error\n if (error.name !== 'RequestError') return failure('unavailable', 'SQL Server could not be reached, or no connection came free in time, and nothing was sent.')\n const server = serverError(error)\n if (server !== undefined) return refusal(server, written)\n return phase === 'write'\n ? failure('unknown-outcome', 'The connection failed after the write was sent; it may have committed. It is not retried.')\n : failure('unavailable', 'The connection failed during the read, which changed nothing.')\n}\n","import type { ListRequest, ListTerms } from '@formancy/data-core'\nimport mssql from 'mssql'\nimport { orderBy } from '../sql/order.js'\nimport { quoteTable } from '../sql/quote.js'\nimport { searchPredicate } from '../sql/search.js'\nimport { Parameters } from '../sql/statement.js'\nimport type { Statement } from '../sql/statement.js'\nimport { described, filterPredicates, keyPredicates, ROW, selection, throughPredicate } from './statements.js'\n\n/**\n * One page of a form's records on SQL Server (0044), with the table as this\n * same statement found it (0041), in one statement -- which holds a\n * schema-stability lock on the table while it runs, as a read does, so no\n * ALTER lands between the facts and the page:\n *\n * select <description, on the page's first row>, [page].*\n * from (select <the table's facts> as [facts]) as [f]\n * outer apply (\n * select 1 as [found], [c0], …, [version], row_number() over (order by <order>) as [n]\n * from <table> as [r] where <parent> and <filters> and <throughs> and <search>\n * order by <order> offset @o rows fetch next @l rows only\n * ) as [page]\n * order by [page].[n]\n *\n * One row with a NULL `[found]` when the page is empty, so the description is\n * answered either way, as a read's is. The rows of an APPLY have no order of\n * their own, so each carries its position in the page's order -- which is\n * total, the key ending it, so the position is the order -- and the\n * statement is ordered by it. The description is selected once, on the\n * page's first row, whose position is `offset + 1`: repeated, it would send\n * the table's catalog facts once per record.\n *\n * The parent's columns compare with `=`, as the foreign key does, each value\n * bound as its column's type, as a key is; the filters, the throughs and the\n * search are a read's and a lookup's own spellings (`statements.ts`,\n * `sql/search.ts`). A nullable column's NULLs are placed by a CASE before it\n * in the order, and a NOT NULL column is ordered bare, so an index on it can\n * serve the order (`sql/order.ts`). `limit + 1` rows, so `recordPage` can\n * tell whether more follow without a COUNT.\n */\nexport function listStatement(request: ListRequest, terms: ListTerms): Statement {\n const parameters = new Parameters()\n const { columns, from } = described(parameters, request.target.table)\n const where = [\n ...keyPredicates(parameters, terms.equal),\n ...filterPredicates(parameters, terms.terms),\n ...terms.through.map((entry) => throughPredicate(parameters, entry)),\n ]\n if (terms.search !== null) where.push(searchPredicate(parameters, ROW, terms.search.columns, terms.search.text))\n const order = orderBy(ROW, terms.sort)\n const offset = parameters.add(mssql.BigInt, terms.offset)\n const fetch = parameters.add(mssql.Int, terms.limit + 1)\n const first = parameters.add(mssql.BigInt, terms.offset + 1)\n const select = [\n ...selection(request.columns, request.target.concurrency, `${ROW}.`).map((selected) => `${selected.expression} as ${selected.name}`),\n `row_number() over (order by ${order}) as [n]`,\n ]\n const page = [\n `select ${select.join(', ')} from ${quoteTable(request.target.table)} as ${ROW}`,\n where.length > 0 ? `where ${where.join(' and ')}` : '',\n `order by ${order} offset ${offset} rows fetch next ${fetch} rows only`,\n ]\n .filter((part) => part !== '')\n .join(' ')\n const once = columns.map((column) => `case when [page].[n] is null or [page].[n] = ${first} then ${column.expression} end as ${column.name}`)\n return parameters.statement(`select ${once.join(', ')}, [page].* from ${from} outer apply (${page}) as [page] order by [page].[n]`)\n}\n","import type { DeleteOutcome, RecordAdapter, RecordColumn, RecordConcurrency, RecordFailure, RecordRead, RecordTarget, RecordValue } from '@formancy/data-core'\nimport { decodeRowversion, deleteTerms, encodeRowversion, listTerms, rowFilterTerms, throughTerms } from '@formancy/data-core'\nimport type { ConnectionPool } from 'mssql'\nimport { prepare, send } from '../sql/statement.js'\nimport type { Statement } from '../sql/statement.js'\nimport { fromCanonicalText } from '../sql/values.js'\nimport { deleteStatement } from './delete.js'\nimport { definitionBytes, describedFrom } from './definition.js'\nimport { failureFor } from './errors.js'\nimport type { Phase } from './errors.js'\nimport { listStatement } from './list.js'\nimport { describeStatement, existsStatement, insertStatement, readStatement, updateStatement } from './statements.js'\nimport type { ExpectedVersion } from './statements.js'\n\n/** A row as every record statement selects it: `[found]`, `[c0]…` canonical text, and `[version]`. */\ntype Row = Record<string, unknown>\n\nconst NOT_FOUND: RecordFailure = { ok: false, code: 'not-found', message: 'No such record is visible to this request.' }\nconst STALE: RecordFailure = { ok: false, code: 'stale', message: 'The record has changed since it was read.' }\n/** The table moved under an update that matched nothing, or that was never sent (0041). */\nconst DEFINITION_MOVED: RecordFailure = { ok: false, code: 'schema-changed', message: \"The table's definition is not the one this write was decided over; nothing was written.\" }\n/** An object the catalog does not show this account as discovery describes one: gone, out of sight, or not a table or a view. Which, drift review says (0010). */\nconst NOT_DESCRIBED: RecordFailure = { ok: false, code: 'schema-changed', message: 'The catalog does not show this table as discovery describes one.' }\n/** The facts arrived shorter than they were hashed: a TEXTSIZE the connection set. Nothing can be decided over them. */\nconst CUT: RecordFailure = { ok: false, code: 'unavailable', message: \"The table's description arrived cut short, so nothing can be decided over it: the connection's TEXTSIZE is smaller than the description.\" }\n\n/** The largest bigint: a version column's token is compared as one. */\nconst BIGINT_MAX = 9223372036854775807n\nconst CANONICAL_INTEGER = /^-?(?:0|[1-9][0-9]*)$/\n\nfunction names(values: readonly RecordColumn[]): string[] {\n return values.map((value) => value.name)\n}\n\n/**\n * The key names exactly the target's identity, each column once. Anything\n * else could match several records — or, with no identity at all, every\n * record — so it is a programming error, refused before anything is sent.\n */\nfunction checkKey(target: RecordTarget, key: readonly RecordValue[]): void {\n const identity = names(target.identity)\n const given = names(key)\n if (identity.length === 0 || given.length !== identity.length || new Set(given).size !== given.length || !identity.every((name) => given.includes(name))) {\n throw new Error(`A record key names exactly its identity (${identity.join(', ')}), and this one names (${given.join(', ')})`)\n }\n}\n\n/** The values a write assigns: each column once, which SQL Server would otherwise refuse with an error that is not a refusal. */\nfunction checkAssigned(values: readonly RecordValue[], reserved: string | null): void {\n const given = names(values)\n if (new Set(given).size !== given.length) throw new Error('A write names each column once')\n if (reserved !== null && given.includes(reserved)) throw new Error(`${reserved} is the concurrency column; the database or the adapter writes it`)\n}\n\n/**\n * The version as it is compared, or `undefined` for a token no record can\n * hold — not 16 lower-case hex digits for a rowversion, not a canonical\n * integer within bigint for a version column. Such a token is never bound; it\n * gets the answer a token that does not match gets.\n */\nfunction expectedVersion(concurrency: RecordConcurrency, token: string): ExpectedVersion | undefined {\n if (concurrency.kind === 'rowversion') {\n const bytes = decodeRowversion(token)\n return bytes === undefined ? undefined : { kind: 'rowversion', bytes: Buffer.from(bytes) }\n }\n if (typeof token !== 'string' || !CANONICAL_INTEGER.test(token) || token === '-0') return undefined\n const value = BigInt(token)\n return value > BIGINT_MAX || value < -BIGINT_MAX - 1n ? undefined : { kind: 'version-column', value: token }\n}\n\n/** The token for the version a row came back with: `encodeRowversion`'s hex, or a version column's decimal string. */\nfunction versionToken(concurrency: RecordConcurrency | null, row: Row): string | null {\n if (concurrency === null) return null\n const version = row.version\n if (concurrency.kind === 'rowversion') {\n if (!(version instanceof Uint8Array)) throw new Error(`${concurrency.column} did not come back as a rowversion`)\n return encodeRowversion(version)\n }\n if (typeof version !== 'string') throw new Error(`${concurrency.column} did not come back as a version`)\n return version\n}\n\nfunction recordFrom(row: Row, columns: readonly RecordColumn[], concurrency: RecordConcurrency | null): Omit<RecordRead, 'ok'> {\n return {\n // fromEntries, so a column called __proto__ is a value like any other.\n values: Object.fromEntries(\n columns.map((column, index) => {\n const text = row[`c${String(index)}`]\n return [column.name, fromCanonicalText(column.type, typeof text === 'string' ? text : null)]\n }),\n ),\n version: versionToken(concurrency, row),\n }\n}\n\n/** Runs one statement, and turns what the driver rejected it with into a failure. A request it would not even take is thrown. */\nasync function attempt(pool: ConnectionPool, statement: Statement, phase: Phase, written: readonly RecordValue[] = []): Promise<Row[] | RecordFailure> {\n const request = prepare(pool, statement)\n try {\n return await send<Row>(request, statement)\n } catch (error) {\n return failureFor(error, phase, written)\n }\n}\n\nfunction onlyRow(rows: readonly Row[]): Row | undefined {\n if (rows.length > 1) throw new Error('The record identity matched more than one row: the bindings do not name a key.')\n return rows[0]\n}\n\n/**\n * The record half of the SQL Server adapter, through a pool the composition\n * root connected (0015).\n *\n * Values arrive canonical and are bound as text the server converts; they\n * leave as text the server produced (`../sql/values.ts`). Each write is one\n * batch: the statement, a check that its transaction is still the one it\n * began and that no INSTEAD OF trigger decided what it stored, a check that\n * every text value was stored as sent, the version read back from the row\n * once its triggers ran, and a commit, all rolled back on any error — so a\n * single-byte varchar cannot quietly keep `LA` for `ŁA`, neither an INSTEAD\n * OF trigger nor one that swaps the transaction can make a write that was not\n * stored look done, and a refusal is not reported over a write the batch\n * committed. A trigger that ends the transaction itself is `unknown-outcome`,\n * whether or not it then raises an error, because whether it committed cannot\n * be told. A database error is a\n * `RecordFailure`, never thrown; a malformed request — a key that is not the\n * identity, a column named twice, a value no codec returns — is a programming\n * error and is.\n */\n/** The description a row of `describeStatement` or `readStatement` carries, or why there is none. */\nfunction describedBy(row: Row): ReturnType<typeof describedFrom> {\n const facts = row.facts\n const digest = row.digest\n return describedFrom(typeof facts === 'string' ? facts : null, digest instanceof Uint8Array ? Buffer.from(digest) : null)\n}\n\nexport function createSqlServerRecords(pool: ConnectionPool): RecordAdapter {\n return {\n async describe(table) {\n const rows = await attempt(pool, describeStatement(table), 'read')\n if (!Array.isArray(rows)) return rows\n // One row: a SELECT of expressions over one derived row.\n const described = describedBy(rows[0] as Row)\n if (described === 'cut') return CUT\n return described === undefined ? NOT_DESCRIBED : { ok: true, described }\n },\n\n async read(request) {\n const terms = rowFilterTerms(request.filters)\n const through = throughTerms(request.through)\n checkKey(request.target, request.key)\n const rows = await attempt(pool, readStatement(request, terms, through), 'read')\n if (!Array.isArray(rows)) return rows\n // Always a row, the description's, with the record beside it or not.\n const row = onlyRow(rows) as Row\n const described = describedBy(row)\n if (described === 'cut') return CUT\n if (described === undefined) return NOT_DESCRIBED\n return { ok: true, described, record: row.found === null ? null : recordFrom(row, request.columns, request.target.concurrency) }\n },\n\n async list(request) {\n const terms = listTerms(request)\n const rows = await attempt(pool, listStatement(request, terms), 'read')\n if (!Array.isArray(rows)) return rows\n // Always a row: the description's, on the page's first record or beside none.\n const described = describedBy(rows[0] as Row)\n if (described === 'cut') return CUT\n if (described === undefined) return NOT_DESCRIBED\n return { ok: true, described, rows: rows.filter((row) => row.found !== null).map((row) => recordFrom(row, request.columns, request.target.concurrency)) }\n },\n\n async insert(request) {\n checkAssigned(request.values, null)\n const definition = definitionBytes(request.definition)\n const rows = await attempt(pool, insertStatement(request, definition), 'write', request.values)\n if (!Array.isArray(rows)) return rows\n const row = rows[0]\n // An INSERT … VALUES writes one row, and the batch selects it back.\n if (row === undefined) throw new Error('SQL Server reported no inserted row')\n return { ok: true, ...recordFrom(row, request.returning, request.target.concurrency) }\n },\n\n async update(request) {\n const { target } = request\n const terms = rowFilterTerms(request.filters)\n const through = throughTerms(request.through)\n checkKey(target, request.key)\n if (request.set.length === 0) throw new Error('An update sets at least one column')\n checkAssigned(request.set, target.concurrency.column)\n const definition = definitionBytes(request.definition)\n\n const expected = expectedVersion(target.concurrency, request.expectedVersion)\n if (expected !== undefined) {\n const rows = await attempt(pool, updateStatement(request, terms, through, expected, definition), 'write', request.set)\n if (!Array.isArray(rows)) return rows\n const row = onlyRow(rows)\n if (row !== undefined) return { ok: true, ...recordFrom(row, request.returning, target.concurrency) }\n }\n\n // Nothing matched: the table moved, the version moved, or there is no\n // such record for this actor. A second query tells them apart, in that\n // order, inside the same filters and throughs; the write changed\n // nothing, so its failure is a read's.\n const found = await attempt(pool, existsStatement(request, terms, through, definition), 'read')\n if (!Array.isArray(found)) return found\n if (Number(found[0]?.same ?? 0) !== 1) return DEFINITION_MOVED\n return Number(found[0]?.found ?? 0) > 0 ? STALE : NOT_FOUND\n },\n\n async delete(request): Promise<DeleteOutcome> {\n const { target } = request\n const terms = deleteTerms(request)\n checkKey(target, terms.key)\n const definition = definitionBytes(request.definition)\n const expected = expectedVersion(target.concurrency, terms.expectedVersion)\n if (expected !== undefined) {\n const rows = await attempt(pool, deleteStatement(request, terms, expected, definition), 'write')\n if (!Array.isArray(rows)) return rows\n const row = onlyRow(rows)\n if (row !== undefined) {\n const removed = recordFrom(row, target.identity, target.concurrency)\n return { ok: true, deleted: { values: removed.values, version: removed.version as string } }\n }\n }\n // Nothing was deleted: as for an update, a second query tells a moved\n // definition, a stale version and no such record apart, inside the\n // same filters and throughs. A reach that moved was refused by the\n // batch itself, which raised it (delete.ts).\n const found = await attempt(pool, existsStatement({ target, key: terms.key }, terms.terms, terms.through, definition), 'read')\n if (!Array.isArray(found)) return found\n if (Number(found[0]?.same ?? 0) !== 1) return DEFINITION_MOVED\n return Number(found[0]?.found ?? 0) > 0 ? STALE : NOT_FOUND\n },\n }\n}\n","import mssql from 'mssql'\nimport type { ConnectionPool } from 'mssql'\n\nexport interface SqlServerConnectOptions {\n host: string\n port: number\n database: string\n user: string\n password: string\n /** TLS. The composition root decides; there is no default here to forget. */\n encrypt: boolean\n trustServerCertificate: boolean\n}\n\n/**\n * A connected pool, from this package's own copy of mssql.\n *\n * Why the adapter package opens its own connections: mssql's parameter types\n * are objects tedious checks by identity, and this package binds every value\n * with `mssql.NVarChar` and friends from ITS copy. A pool built from another\n * copy — two installs of mssql@12.7.4 that differ only in which supports-color\n * satisfied an optional peer, which is exactly what pnpm produced for the\n * server — refuses every parameter with \"type.validate is not a function\".\n * Found by the end-to-end suite; no unit test could see it. Opening the pool\n * here means the pool and the types always come from one copy.\n */\nexport function connectSqlServer(options: SqlServerConnectOptions): Promise<ConnectionPool> {\n return new mssql.ConnectionPool({\n server: options.host,\n port: options.port,\n database: options.database,\n user: options.user,\n password: options.password,\n options: { encrypt: options.encrypt, trustServerCertificate: options.trustServerCertificate },\n }).connect()\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formancy/data-sqlserver",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The Microsoft SQL Server adapter for Formancy Data: catalog inspection, quoting, binding, transactions and error translation, behind the port @formancy/data-core defines.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.mts",
|
|
11
|
+
"default": "./dist/index.mjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"LICENSE.md",
|
|
17
|
+
"NOTICE"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@formancy/data-core": "0.1.0",
|
|
21
|
+
"@types/mssql": "^12.3.0",
|
|
22
|
+
"mssql": "^12.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
26
|
+
"@formancy/data-fixtures": "0.1.0",
|
|
27
|
+
"@types/node": "^22.10.0",
|
|
28
|
+
"@vitest/coverage-v8": "^5.0.1",
|
|
29
|
+
"publint": "^0.3.24",
|
|
30
|
+
"tsdown": "^0.23.0",
|
|
31
|
+
"typescript": "~6.0.3",
|
|
32
|
+
"unrun": "^0.3.1",
|
|
33
|
+
"vitest": "^5.0.1"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/sharkysan/formancy.ai-data.git",
|
|
41
|
+
"directory": "packages/data-sqlserver"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/sharkysan/formancy.ai-data",
|
|
44
|
+
"bugs": "https://github.com/sharkysan/formancy.ai-data/issues",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsdown",
|
|
47
|
+
"test:coverage": "vitest run --coverage",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"check:pkg": "publint && attw --pack . --profile esm-only"
|
|
51
|
+
}
|
|
6
52
|
}
|