namespace ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts; /// /// The keys SqlBrowseSession states in a browsed column's AttributeInfo.AddressFields, and /// that RawBrowseCommitMapper reads back when it builds the committed tag's TagConfig. /// Why a shared constant rather than a literal at each end. A Sql tag's binding is a tuple /// (table + column + which row), so — exactly as for MQTT's Sparkplug tuple and /// MqttTagConfigKeys — the producing session states the parts and the mapper must never /// re-infer them. Two independently spelled string literals agree by coincidence, and a disagreement is /// silent: the mapper simply sees no field, and emits a config missing whatever the session was trying /// to say. That is precisely how Gitea #552 shipped — a wide-row blob with no rowSelector, which /// both and the authoring gate refuse. /// These are the browse channel's names, not the tag blob's schema. Three of them happen /// to match a TagConfig key because the mapper writes them straight through; /// matches the key nested inside rowSelector — deliberately /// not spelled timestampColumn, which is the blob's unrelated top-level source-timestamp /// field. /// public static class SqlBrowseAddressFields { /// The catalog schema owning the browsed column's table (e.g. dbo, sales). public const string Schema = "schema"; /// The unqualified table (or view) name the browsed column belongs to. public const string Table = "table"; /// The browsed column's own name — the wide-row tag's value column. public const string ColumnName = "columnName"; /// /// The table's preferred date/time-typed column, when it has one: the commit writes it as the /// wide-row rowSelector.topByTimestamp, i.e. "read the newest row". Absent when the table /// carries no date/time column at all, which is not a shape a browse can bind — see /// RawBrowseCommitMapper.DescribeUncommittableLeaf. /// public const string TopByTimestamp = "topByTimestamp"; }