Tokens for several companies
One token for several companies, and how to pick the company with useCompany.
The frm claim in a token says which companies the caller may work in:
frm |
Meaning |
|---|---|
F0001 |
One firm database, as before. The token decides; useCompany(no:) is ignored. |
F0001,F0002 |
Those firms only. The caller picks one with useCompany(no:). |
ANY |
Every firm of the installation. The caller picks with useCompany(no:). |
Every name is checked as a plain identifier (VismaFirm), since it becomes a database name in
executed SQL. A list with one bad entry is refused as a whole.
query {
a: useCompany(no: 1) { order(first: 3) { nodes { orderNo } } }
b: useCompany(no: 9999) { order(first: 3) { nodes { orderNo } } }
}
mutation {
one: useCompany(no: 1) { order_update(orderNo: 7, order: { information1: "x" }) { orderNo } }
two: useCompany(no: 9999) { order_update(orderNo: 3, order: { information1: "y" }) { orderNo } }
}
Rules
- With a list or
ANY, everything that reads or writes a company’s data has to be inside auseCompany(no:)on the query or mutation root. A root field outside one is refused. So are auseCompanywithoutnoand a nesteduseCompany.apiand introspection need no company. nomust be a company Visma Business has, read from its own register. The catalogue’sSitetable gives the system database for sitestandard, and that database’sFrmtable lists the companies.Business:CatalogDatabasenames the catalogue: a database name on the same server (defaultCatalog) or a full connection string. The list is kept for five minutes. If the register cannot be read, the server logs it and only checks that the database exists.nomaps to the firm database the way Visma names them: an optional prefix (Business:DatabasePrefix),F, and the number with at least four digits. 1 isF0001and 12345 isF12345. This is Visma’s own{0}F{1:#0000}; the register records no database names. With a list in the token, the database must be one of the list.- Under
useCompanyon the mutation root the mutations run one after another, in document order, exactly as root mutations do.@exportkeeps working.
Isolation
Each useCompany is its own tree, and everything under it works in that tree’s company. That
covers the EF context, SQL connections, the Visma Business request (CompanyNo), the data loaders
and the caches.
useCompanyputs the firm in the tree’s scoped state.FirmScope.Middlewareruns around every field and makes it current (anAsyncLocal) while the field resolves. That is where contexts, connections and Visma requests are made.GetVismaBusinessDatabase()reads it first.- A data loader’s batch runs outside the field that asked. Every loader that touches a company’s
data therefore takes
Firmed<TKey>keys, which carry the firm.FirmBatches.PerFirmruns each firm’s keys in that firm. One company’s identical key, such as a product number, is never answered from another company’s batch or cache. VBFirstOrDefaultFetcherandContributedFinderhold a context for the firm they were made in, so they are transient rather than scoped.- Outside a
useCompany, a multi-firm token names no database. Building a connection string then throws instead of falling back to the connection string’s catalogue, which would quietly serve a company the caller never chose.
FirmTests covers this without a database: an interceptor records which database every
statement would have gone to.