unit OpenAPI.Classes.Parameter;

interface

uses
  SysUtils, Classes,
  Bcl.Json.Attributes, Bcl.Json.Converters,
  XData.JSchema.Classes,
  OpenAPI.Classes,
  OpenAPI.Json.Attributes, OpenAPI.Types, OpenAPI.Consts;

type
  // Describes a single operation parameter.
  [OAJsonInclusion, OAJsonNaming]
  TParameter = class
  strict private
    [JsonInclude(TInclusionMode.Always)]
    FIn: TLocation;
    FName: string;
    FDescription: string;
    FRequired: boolean;
    [JsonIgnore]
    FAllowEmptyValue: boolean;
    [JsonIgnore]
    FCollectionFormat: TCollectionFormat;
    [JsonIgnore]
    FSchema: TJsonSchema;
    function GetDefaultNum: double;
    function GetDefaultStr: string;
    function GetDefinition: string;
    function GetEnum: TStrings;
    function GetExclusiveMaximum: boolean;
    function GetExclusiveMinimum: boolean;
    function GetFormat: string;
    function GetItems: TJsonSchema;
    function GetJsonSchema: TJsonSchema;
    function GetMaximum: double;
    function GetMaxItems: integer;
    function GetMaxLength: integer;
    function GetMinimum: double;
    function GetMinItems: integer;
    function GetMinLength: integer;
    function GetMultipleOf: double;
    function GetPattern: string;
    function GetType: string;
    function GetUniqueItems: boolean;
    procedure SetDefinition(const Value: string);
    procedure SetSchema(const Value: TJsonSchema);
  public
    constructor Create;
    destructor Destroy; override;
    function InBody: boolean;
    function SchemaAs<T: TJsonSchema>(out ASchema: T): boolean;
    // Required. The location of the parameter. Possible values are "query", "header", "path", "formData" or "body".
    property &In: TLocation read FIn write FIn default TLocation.Query;
    // Required. The name of the parameter. Parameter names are case sensitive.
    // If in is "path", the name field MUST correspond to the associated path segment from the path field in the Paths Object.
    // For all other cases, the name corresponds to the parameter name used based on the in property.
    property Name: string read FName write FName;
    // A brief description of the parameter.
    property Description: string read FDescription write FDescription;
    // Determines whether this parameter is mandatory.
    // If the parameter is in "path", this property is required and its value MUST be true.
    // Otherwise, the property MAY be included and its default value is false.
    property Required: boolean read FRequired write FRequired default false;
    // If in is "body":
    // Property Schema (required). The schema defining the type used for the body parameter.
    property Schema: TJsonSchema read FSchema write SetSchema;
    property Definition: string read GetDefinition write SetDefinition;
    [JsonProperty(TOpenAPIConsts.Schema)]
    property JsonSchema: TJsonSchema read GetJsonSchema;
    // If in is any value other than "body": the properties below.
    // Required. The type of the parameter.
    // Since the parameter is not located at the request body, it is limited to simple types (that is, not an object).
    // The value MUST be one of "string", "number", "integer", "boolean", "array" or "file".
    // If type is "file", the consumes MUST be either "multipart/form-data", " application/x-www-form-urlencoded" or both and the parameter MUST be in "formData".
    [JsonProperty]
    property &Type: string read GetType;
    // The extending format for the previously mentioned type.
    [JsonProperty]
    property Format: string read GetFormat;
    // Sets the ability to pass empty-valued parameters.
    // This is valid only for either query or formData parameters and allows you to send a parameter with a name only or an empty value.
    // Default value is false.
    [JsonProperty]
    property AllowEmptyValue: boolean read FAllowEmptyValue;
    // Required if type is "array". Describes the type of items in the array.
    [JsonProperty]
    property Items: TJsonSchema read GetItems;
    // Determines the format of the array if type array is used.
    // Possible values are: csv (default), ssv, tsv, pipes, multi.
    [JsonProperty]
    property CollectionFormat: TCollectionFormat read FCollectionFormat write FCollectionFormat default TCollectionFormat.CSV;
    // Declares the value of the parameter that the server will use if none is provided.
    [JsonProperty(TJsonSchemaProps.Default)]
    property DefaultNum: double read GetDefaultNum;
    [JsonProperty(TJsonSchemaProps.Default)]
    property DefaultStr: string read GetDefaultStr;
    // Maximum value.
    [JsonProperty]
    property Maximum: double read GetMaximum;
    // If "exclusiveMaximum" is present, "maximum" MUST also be present.
    [JsonProperty]
    property ExclusiveMaximum: boolean read GetExclusiveMaximum;
    // Minimum value.
    [JsonProperty]
    property Minimum: double read GetMinimum;
    // If "exclusiveMinimum" is present, "minimum" MUST also be present.
    [JsonProperty]
    property ExclusiveMinimum: boolean read GetExclusiveMinimum;
    // Maximum length.
    [JsonProperty]
    property MaxLength: integer read GetMaxLength;
    // Minimum length.
    [JsonProperty]
    property MinLength: integer read GetMinLength;
    // This string SHOULD be a valid regular expression
    [JsonProperty]
    property Pattern: string read GetPattern;
    // Maximum size of an array.
    [JsonProperty]
    property MaxItems: integer read GetMaxItems;
    // Minimum size of an array.
    [JsonProperty]
    property MinItems: integer read GetMinItems;
    // Array with unique elements.
    [JsonProperty]
    property UniqueItems: boolean read GetUniqueItems;
    // Value equal to one of these elements.
    [JsonProperty]
    property Enum: TStrings read GetEnum;
    // Result of the division of the instance by this value is an integer.
    [JsonProperty]
    property MultipleOf: double read GetMultipleOf;
  end;

implementation

uses
  OpenAPI.Utils;

{ TParameter }

constructor TParameter.Create;
begin
  inherited;
  FIn := TLocation.Query;
  FCollectionFormat := TCollectionFormat.CSV;
end;

destructor TParameter.Destroy;
begin
  FSchema.Free;
  inherited;
end;

function TParameter.GetDefaultNum: double;
var
  num: TNumericSchema;
begin
  if not InBody and SchemaAs<TNumericSchema>(num) and num.DefaultValue.HasValue then
    result := num.DefaultValue
  else
    result := 0;
end;

function TParameter.GetDefaultStr: string;
var
  str: TStringSchema;
begin
  if not InBody and SchemaAs<TStringSchema>(str) and str.DefaultValue.HasValue then
    result := str.DefaultValue
  else
    result := '';
end;

function TParameter.GetDefinition: string;
var
  nameRef: TNameReferenceSchema;
begin
  if not InBody and SchemaAs<TNameReferenceSchema>(nameRef) then
    result := nameRef.Name
  else
    result := '';
end;

function TParameter.GetEnum: TStrings;
var
  str: TStringSchema;
begin
  if not InBody and SchemaAs<TStringSchema>(str) and (str.Enum.Count > 0) then
    result := str.Enum
  else
    result := nil;
end;

function TParameter.GetExclusiveMaximum: boolean;
var
  num: TNumericSchema;
begin
  result := not InBody and SchemaAs<TNumericSchema>(num) and num.ExclusiveMaximum;
end;

function TParameter.GetExclusiveMinimum: boolean;
var
  num: TNumericSchema;
begin
  result := not InBody and SchemaAs<TNumericSchema>(num) and num.ExclusiveMinimum;
end;

function TParameter.GetFormat: string;
begin
  if not InBody and Assigned(FSchema) then
    result := FSchema.Format
  else
    result := '';
end;

function TParameter.GetItems: TJsonSchema;
var
  arr: TArraySchema;
begin
  if not InBody and SchemaAs<TArraySchema>(arr) and (arr.ItemSchemas.Count > 0) then
    result := arr.ItemSchemas.First
  else
    result := nil;
end;

function TParameter.GetJsonSchema: TJsonSchema;
begin
  if InBody then
    result := Schema // property serialized when in is "body"
  else
    result := nil;
end;

function TParameter.GetMaximum: double;
var
  num: TNumericSchema;
begin
  if not InBody and SchemaAs<TNumericSchema>(num) then
    result := num.Maximum
  else
    result := 0;
end;

function TParameter.GetMaxItems: integer;
var
  arr: TArraySchema;
begin
  if not InBody and SchemaAs<TArraySchema>(arr) then
    result := arr.MaxItems
  else
    result := 0;
end;

function TParameter.GetMaxLength: integer;
var
  str: TStringSchema;
begin
  if not InBody and SchemaAs<TStringSchema>(str) then
    result := str.MaxLength
  else
    result := 0;
end;

function TParameter.GetMinimum: double;
var
  num: TNumericSchema;
begin
  if not InBody and SchemaAs<TNumericSchema>(num) then
    result := num.Minimum
  else
    result := 0;
end;

function TParameter.GetMinItems: integer;
var
  arr: TArraySchema;
begin
  if not InBody and SchemaAs<TArraySchema>(arr) then
    result := arr.MinItems
  else
    result := 0;
end;

function TParameter.GetMinLength: integer;
var
  str: TStringSchema;
begin
  if not InBody and SchemaAs<TStringSchema>(str) then
    result := str.MinLength
  else
    result := 0;
end;

function TParameter.GetMultipleOf: double;
var
  num: TNumericSchema;
begin
  if not InBody and SchemaAs<TNumericSchema>(num) then
    result := num.MultipleOf
  else
    result := 0;
end;

function TParameter.GetPattern: string;
var
  str: TStringSchema;
begin
  if not InBody and SchemaAs<TStringSchema>(str) then
    result := str.Pattern
  else
    result := '';
end;

function TParameter.GetType: string;
begin
  if not InBody and Assigned(FSchema) then
    result := FSchema._Type
  else
    result := '';
end;

function TParameter.GetUniqueItems: boolean;
var
  arr: TArraySchema;
begin
  result := not InBody and SchemaAs<TArraySchema>(arr) and arr.UniqueItems;
end;

function TParameter.InBody: boolean;
begin
  result := &In = TLocation.Body;
end;

function TParameter.SchemaAs<T>(out ASchema: T): boolean;
begin
  result := Assigned(FSchema) and (FSchema is T);
  if result then
    ASchema := T(FSchema);
end;

procedure TParameter.SetDefinition(const Value: string);
begin
  if InBody and (Value > '') then
    TOpenAPIUtils.SetNameReference(FSchema, Value);
end;

procedure TParameter.SetSchema(const Value: TJsonSchema);
begin
  FreeAndNil(FSchema);
  FSchema := Value;
end;

end.

