Class FabricWarehouseUtils

java.lang.Object
io.openlineage.client.utils.FabricWarehouseUtils

public final class FabricWarehouseUtils extends Object
How OpenLineage names tables in Microsoft Fabric warehouses.

Each Fabric workspace has one SQL address that all its warehouses share, for example ck32i2hmt2qeziwtnklnft2ptq-hnd7nul2t5jehfalvdluiyot7q.datawarehouse.fabric.microsoft.com. A table is named fabric-warehouse://<address> plus <warehouse>.<schema>.<table>.

Some of what this class relies on isn't documented by Microsoft: how the address is built from the tenant and workspace IDs, and the option names that Microsoft's Spark connector for Fabric uses. All of it is kept in this class, and was checked against real workspaces, so a change on Microsoft's side only needs fixing here.

  • Field Details

  • Method Details

    • canonicalEndpoint

      public static String canonicalEndpoint(String endpoint)
      Normalizes a Fabric address, so the same table always gets the same name.

      The address is lowercased, the .z<two characters> label that Fabric sometimes adds before .datawarehouse.fabric.microsoft.com is removed, and port 1433, the default, is removed. Any other port is kept as :port.

      Parameters:
      endpoint - host, host:port or host,port
      Returns:
      the normalized address, or just lowercased if it can't be read
    • isFabricEndpoint

      public static boolean isFabricEndpoint(String endpoint)
      Whether this is the SQL address of a Fabric workspace, optionally followed by a numeric port. Addresses used to reach a workspace in another organization have an extra part and aren't matched.
    • endpointFor

      public static String endpointFor(UUID tenantId, UUID workspaceId)
      Builds a workspace's SQL address from its tenant ID and workspace ID. This is needed when only the IDs are known, as with writes from Microsoft's Spark connector for Fabric.

      The address is <tenant part>-<workspace part>.datawarehouse.fabric.microsoft.com. Each part is the ID turned into 26 characters:

      1. take the ID's 16 bytes in the order Microsoft's .NET stores them, which reverses the bytes within each of the first three groups of the ID;
      2. write those bytes in base32 (letters a-z and digits 2-7), lowercase, without trailing = padding.

      For example, tenant 68a4b712-9eec-4ca0-a2d3-6a96d2cf4f9c and workspace d1f6473b-9f7a-4352-940b-a8d74461d3fc give ck32i2hmt2qeziwtnklnft2ptq-hnd7nul2t5jehfalvdluiyot7q.datawarehouse.fabric.microsoft.com.

      Microsoft doesn't document this. In November 2026 it matched the real addresses of 2 test workspaces and 44 public tenants, and Microsoft's own fabric-warehouse-labs samples build the address the same way. If Microsoft changes it, update this method and the known examples in FabricWarehouseUtilsTest. Users can also set the address themselves; see the Spark integration's Microsoft Fabric docs.

    • workspaceIdOf

      public static Optional<UUID> workspaceIdOf(String endpoint)
      Reads the workspace ID back out of a Fabric SQL address.
    • oneLakeLocation

      public static DatasetIdentifier oneLakeLocation(UUID workspaceId, UUID warehouseId, String schema, String table)
      Builds the location of a table's files in OneLake, Fabric's storage. The path always uses IDs, never names, because OneLake refuses paths that mix the two (error 400 FriendlyNameSupportDisabled).
      Returns:
      namespace abfss://<workspace ID>@onelake.dfs.fabric.microsoft.com and name <warehouse ID>/Tables/<schema>/<table>
    • withOneLakeLocation

      public static DatasetIdentifier withOneLakeLocation(DatasetIdentifier identifier, Optional<String> idWarehouse, Optional<String> workspaceIdOption, Optional<String> warehouseIdOption)
      Adds the table's OneLake file location to a Fabric warehouse dataset, as a LOCATION symlink.

      This needs the warehouse's ID, which is only available when the user passes it with the connector's DatawarehouseId option. That ID belongs to one warehouse, but a query can read tables from several warehouses in the same workspace. So the location is only added to tables in the warehouse the ID was given for; other tables would get a wrong path.

      The workspace is the one in the SQL address, because that is what was queried, and the dataset's name says so; toOneLakeLocation(io.openlineage.client.utils.DatasetIdentifier) uses the same rule. If the address has no workspace, no location is added. If the WorkspaceId option names another workspace, or isn't a valid ID, the IDs can't be trusted to belong together and no location is added either. When the address is built from the tenant and the WorkspaceId option, as for synapsesql writes, the two always agree.

      If anything is missing, the table is in another warehouse, or an ID isn't valid, the dataset is returned as it was.

      Parameters:
      identifier - a fabric-warehouse dataset named <warehouse>.<schema>.<table>
      idWarehouse - name of the warehouse that warehouseIdOption belongs to
      workspaceIdOption - the WorkspaceId option; must match the address's workspace
      warehouseIdOption - the DatawarehouseId option
      Returns:
      the same dataset, with the location added when possible
    • toOneLakeLocation

      public static Optional<OneLakeLocation> toOneLakeLocation(DatasetIdentifier identifier)
      Describes a Fabric warehouse table in OneLake terms, for the fabric_onelake facet.

      Everything comes from the dataset itself, never from the Spark session, because a table can be in another workspace than the one the job runs in:

      Parameters:
      identifier - a dataset, possibly with symlinks
      Returns:
      the description, or empty if this isn't a fabric-warehouse dataset named <warehouse>.<schema>.<table>
    • parseGuid

      public static Optional<UUID> parseGuid(String value)
      Reads an ID, returning empty instead of failing when the text isn't a valid ID. Same as OneLakeLocation.guid(java.lang.String): only the full 36-character form is accepted.