Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions common/api/core-quantity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ export class BaseFormat {
// (undocumented)
protected _precision: number;
// (undocumented)
get ratioFormatType(): RatioFormatType | undefined;
set ratioFormatType(ratioFormatType: RatioFormatType | undefined);
// (undocumented)
protected _ratioFormatType?: RatioFormatType;
// (undocumented)
get ratioSeparator(): string | undefined;
set ratioSeparator(ratioSeparator: string | undefined);
// (undocumented)
protected _ratioSeparator?: string;
// (undocumented)
get ratioType(): RatioType | undefined;
set ratioType(ratioType: RatioType | undefined);
// (undocumented)
Expand Down Expand Up @@ -288,6 +298,8 @@ export interface FormatProps {
readonly minWidth?: number;
// (undocumented)
readonly precision?: number;
readonly ratioFormatType?: string;
readonly ratioSeparator?: string;
readonly ratioType?: string;
readonly revolutionUnit?: string;
// (undocumented)
Expand Down Expand Up @@ -492,6 +504,9 @@ export class Parser {
static parseToQuantityValue(inString: string, format: Format, unitsConversions: UnitConversionSpec[]): QuantityParseResult;
}

// @beta (undocumented)
export function parseRatioFormatType(ratioFormatType: string, formatName: string): RatioFormatType;

// @beta (undocumented)
export function parseRatioType(ratioType: string, formatName: string): RatioType;

Expand Down Expand Up @@ -633,6 +648,12 @@ export enum QuantityStatus {
UnsupportedUnit = 35047
}

// @beta
export enum RatioFormatType {
Decimal = "Decimal",
Fractional = "Fractional"
}

// @beta
export enum RatioType {
NToOne = "NToOne",
Expand Down
12 changes: 12 additions & 0 deletions common/api/ecschema-metadata.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,12 @@ export class Format extends SchemaItem {
// (undocumented)
get precision(): DecimalPrecision | FractionalPrecision;
// (undocumented)
get ratioFormatType(): string | undefined;
// (undocumented)
get ratioSeparator(): string | undefined;
// (undocumented)
get ratioType(): string | undefined;
// (undocumented)
get roundFactor(): number;
// (undocumented)
readonly schemaItemType: SchemaItemType;
Expand Down Expand Up @@ -1130,6 +1136,12 @@ export class OverrideFormat {
// (undocumented)
get precision(): DecimalPrecision | FractionalPrecision;
// (undocumented)
get ratioFormatType(): string | undefined;
// (undocumented)
get ratioSeparator(): string | undefined;
// (undocumented)
get ratioType(): string | undefined;
// (undocumented)
get roundFactor(): number;
// (undocumented)
get scientificType(): ScientificType | undefined;
Expand Down
2 changes: 2 additions & 0 deletions common/api/summary/core-quantity.exports.csv
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ beta;function;parseFractionalPrecision
beta;function;parsePrecision
beta;interface;ParseQuantityError
beta;class;Parser
beta;function;parseRatioFormatType
beta;function;parseRatioType
beta;class;ParserSpec
beta;function;parseScientificType
Expand All @@ -50,6 +51,7 @@ beta;class;QuantityError
beta;type;QuantityParseResult
beta;interface;QuantityProps
beta;enum;QuantityStatus
beta;enum;RatioFormatType
beta;enum;RatioType
beta;type;ResolvedFormatCompositeProps
beta;type;ResolvedFormatProps
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-quantity",
"comment": "Add scale factors support for ratio formatting",
"type": "none"
}
],
"packageName": "@itwin/core-quantity"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/ecschema-metadata",
"comment": "Add scale factors support for ratio formatting",
"type": "none"
}
],
"packageName": "@itwin/ecschema-metadata"
}
9 changes: 9 additions & 0 deletions core/ecschema-metadata/src/Deserialization/JsonParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,15 @@ export class JsonParser extends AbstractParser<UnknownObject> {
if (undefined !== jsonObj.scientificType && typeof (jsonObj.scientificType) !== "string")
throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'scientificType' attribute. It should be of type 'string'.`);

if (undefined !== jsonObj.ratioType && typeof (jsonObj.ratioType) !== "string")
throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'ratioType' attribute. It should be of type 'string'.`);

if (undefined !== jsonObj.ratioSeparator && typeof (jsonObj.ratioSeparator) !== "string")
throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'ratioSeparator' attribute. It should be of type 'string'.`);

if (undefined !== jsonObj.ratioFormatType && typeof (jsonObj.ratioFormatType) !== "string")
throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'ratioFormatType' attribute. It should be of type 'string'.`);

if (undefined !== jsonObj.stationOffsetSize && typeof (jsonObj.stationOffsetSize) !== "number")
throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'stationOffsetSize' attribute. It should be of type 'number'.`);

Expand Down
6 changes: 6 additions & 0 deletions core/ecschema-metadata/src/Deserialization/XmlParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,9 @@ export class XmlParser extends AbstractParser<Element> {
const thousandSeparator = this.getOptionalAttribute(xmlElement, "thousandSeparator");
const uomSeparator = this.getOptionalAttribute(xmlElement, "uomSeparator");
const scientificType = this.getOptionalAttribute(xmlElement, "scientificType");
const ratioType = this.getOptionalAttribute(xmlElement, "ratioType");
const ratioSeparator = this.getOptionalAttribute(xmlElement, "ratioSeparator");
const ratioFormatType = this.getOptionalAttribute(xmlElement, "ratioFormatType");

const stationOffsetSize = this.getOptionalIntAttribute(xmlElement, "stationOffsetSize",
`The Format ${this._currentItemFullName} has an invalid 'stationOffsetSize' attribute. It should be a numeric value.`);
Expand Down Expand Up @@ -563,6 +566,9 @@ export class XmlParser extends AbstractParser<Element> {
thousandSeparator,
uomSeparator,
scientificType,
ratioType,
ratioSeparator,
ratioFormatType,
stationOffsetSize,
stationSeparator,
composite,
Expand Down
18 changes: 18 additions & 0 deletions core/ecschema-metadata/src/Metadata/Format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export class Format extends SchemaItem {
public get stationSeparator(): string { return this._base.stationSeparator; }
public get stationOffsetSize(): number | undefined { return this._base.stationOffsetSize; }
public get stationBaseFactor(): number | undefined { return this._base.stationBaseFactor; }
public get ratioType(): string | undefined { return this._base.ratioType; }
public get ratioSeparator(): string | undefined { return this._base.ratioSeparator; }
public get ratioFormatType(): string | undefined { return this._base.ratioFormatType; }
public get formatTraits(): FormatTraits { return this._base.formatTraits; }
public get spacer(): string | undefined { return this._base.spacer; }
public get includeZero(): boolean | undefined { return this._base.includeZero; }
Expand Down Expand Up @@ -187,6 +190,15 @@ export class Format extends SchemaItem {
schemaJson.stationSeparator = this.stationSeparator;
}

if (FormatType.Ratio === this.type) {
if (undefined !== this.ratioType)
schemaJson.ratioType = this.ratioType;
if (undefined !== this.ratioSeparator)
schemaJson.ratioSeparator = this.ratioSeparator;
if (undefined !== this.ratioFormatType)
schemaJson.ratioFormatType = this.ratioFormatType;
}

if (undefined === this.units)
return schemaJson;

Expand Down Expand Up @@ -225,6 +237,12 @@ export class Format extends SchemaItem {
itemElement.setAttribute("minWidth", this.minWidth.toString());
if (undefined !== this.scientificType)
itemElement.setAttribute("scientificType", this.scientificType);
if (undefined !== this.ratioType)
itemElement.setAttribute("ratioType", this.ratioType);
if (undefined !== this.ratioSeparator)
itemElement.setAttribute("ratioSeparator", this.ratioSeparator);
if (undefined !== this.ratioFormatType)
itemElement.setAttribute("ratioFormatType", this.ratioFormatType);
if (undefined !== this.stationOffsetSize)
itemElement.setAttribute("stationOffsetSize", this.stationOffsetSize.toString());

Expand Down
5 changes: 4 additions & 1 deletion core/ecschema-metadata/src/Metadata/OverrideFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ export class OverrideFormat {
public get type(): FormatType { return this.parent.type; }
public get minWidth(): number | undefined { return this.parent.minWidth; }
public get scientificType(): ScientificType | undefined { return this.parent.scientificType; }
public get ratioType(): string | undefined { return this.parent.ratioType; }
public get ratioSeparator(): string | undefined { return this.parent.ratioSeparator; }
public get ratioFormatType(): string | undefined { return this.parent.ratioFormatType; }
public get showSignOption(): ShowSignOption { return this.parent.showSignOption; }
public get decimalSeparator(): string { return this.parent.decimalSeparator; }
public get thousandSeparator(): string { return this.parent.thousandSeparator; }
Expand Down Expand Up @@ -93,7 +96,7 @@ export class OverrideFormat {
for (const [unit, unitLabel] of this._units) {
const unitSchema = koqSchema.context.getSchemaSync(unit.schemaKey);
if(unitSchema === undefined)
throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The unit schema ${unit.schemaKey} is not found in the context.`);
throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The unit schema ${unit.schemaKey.name} is not found in the context.`);

fullName += "[";
fullName += XmlSerializationUtils.createXmlTypedName(koqSchema, unitSchema, unit.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,65 @@ describe("JsonParser", () => {
};
assert.throws(() => parser.parseFormat(json), ECSchemaError, `The Format TestSchema.AmerMYFI4 has a Composite with an invalid 'spacer' attribute.`);
});

it("should parse ratio format props correctly", () => {
const json = {
schemaItemType: "Format",
type: "Ratio",
ratioType: "OneToN",
ratioSeparator: ":",
ratioFormatType: "Decimal",
precision: 4,
formatTraits: "trailZeroes|showUnitLabel",
};
parser = new JsonParser(createSchemaJsonWithItems({ TestRatioFormat: json }));
parser.findItem("TestRatioFormat");
const result = parser.parseFormat(json);
assert.strictEqual(result.ratioType, "OneToN");
assert.strictEqual(result.ratioSeparator, ":");
assert.strictEqual(result.ratioFormatType, "Decimal");
});

it("should throw for invalid ratioType", () => {
const json = {
schemaItemType: "Format",
type: "Ratio",
ratioType: 123,
precision: 4,
formatTraits: "trailZeroes",
};
parser = new JsonParser(createSchemaJsonWithItems({ TestRatioFormat: json }));
parser.findItem("TestRatioFormat");
assert.throws(() => parser.parseFormat(json), ECSchemaError, `The Format TestSchema.TestRatioFormat has an invalid 'ratioType' attribute. It should be of type 'string'.`);
});

it("should throw for invalid ratioSeparator", () => {
const json = {
schemaItemType: "Format",
type: "Ratio",
ratioType: "OneToN",
ratioSeparator: 456,
precision: 4,
formatTraits: "trailZeroes",
};
parser = new JsonParser(createSchemaJsonWithItems({ TestRatioFormat: json }));
parser.findItem("TestRatioFormat");
assert.throws(() => parser.parseFormat(json), ECSchemaError, `The Format TestSchema.TestRatioFormat has an invalid 'ratioSeparator' attribute. It should be of type 'string'.`);
});

it("should throw for invalid ratioFormatType", () => {
const json = {
schemaItemType: "Format",
type: "Ratio",
ratioType: "OneToN",
ratioFormatType: 789,
precision: 4,
formatTraits: "trailZeroes",
};
parser = new JsonParser(createSchemaJsonWithItems({ TestRatioFormat: json }));
parser.findItem("TestRatioFormat");
assert.throws(() => parser.parseFormat(json), ECSchemaError, `The Format TestSchema.TestRatioFormat has an invalid 'ratioFormatType' attribute. It should be of type 'string'.`);
});
});

describe("parseInvertedUnit", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,9 @@ describe("XmlParser", () => {
scientificType: undefined,
stationOffsetSize: undefined,
stationSeparator: undefined,
ratioFormatType: undefined,
ratioSeparator: undefined,
ratioType: undefined,
} as SchemaItemFormatProps;

const actualReferenceSchema: SchemaReferenceProps[] = Array.from(parser.getReferences());
Expand Down Expand Up @@ -546,6 +549,60 @@ describe("XmlParser", () => {
});

it("should throw for invalid composite includeZero attribute", () => { });

it("should parse ratio format props correctly", () => {
const itemXml = `
<ECSchemaReference name="Units" alias="u" version="1.0.0"></ECSchemaReference>
<Format typeName="TestRatioFormat" type="Ratio" ratioType="OneToN" ratioSeparator=":" ratioFormatType="Decimal" precision="4" formatTraits="trailZeroes|showUnitLabel" />`;

parser = new XmlParser(createSchemaXmlWithItems(itemXml));
const findResult = parser.findItem("TestRatioFormat");
if (findResult === undefined)
throw new Error("Expected finding Format to be successful");

const [, , itemElement] = findResult;

const expectedProps = {
type: "Ratio",
precision: 4,
formatTraits: ["trailZeroes", "showUnitLabel"],
ratioType: "OneToN",
ratioSeparator: ":",
ratioFormatType: "Decimal",
description: undefined,
label: undefined,
roundFactor: undefined,
minWidth: undefined,
showSignOption: undefined,
decimalSeparator: undefined,
thousandSeparator: undefined,
uomSeparator: undefined,
scientificType: undefined,
stationOffsetSize: undefined,
stationSeparator: undefined,
composite: undefined,
} as SchemaItemFormatProps;

const actualProps = parser.parseFormat(itemElement);
assert.deepEqual(actualProps, expectedProps);
});

it("should parse ratio format with fractional type", () => {
const itemXml = `
<Format typeName="TestRatioFormat" type="Ratio" ratioType="NToOne" ratioSeparator="=" ratioFormatType="Fractional" precision="8" formatTraits="keepSingleZero" />`;

parser = new XmlParser(createSchemaXmlWithItems(itemXml));
const findResult = parser.findItem("TestRatioFormat");
if (findResult === undefined)
throw new Error("Expected finding Format to be successful");

const [, , itemElement] = findResult;

const actualProps = parser.parseFormat(itemElement);
assert.strictEqual(actualProps.ratioType, "NToOne");
assert.strictEqual(actualProps.ratioSeparator, "=");
assert.strictEqual(actualProps.ratioFormatType, "Fractional");
});
});

describe("parseInvertedUnit", () => {
Expand Down
Loading
Loading