logo.png
mORMot2 API Reference

mormot.core.variants.pas unit

Purpose: Framework Core Low-Level Variants / TDocVariant process
- this unit is a part of the Open Source Synopse mORMot framework 2, licensed under a MPL/GPL/LGPL three license - see LICENSE.md

1.1. Units used in the mormot.core.variants unit

Unit NameDescription
mormot.core.baseFramework Core Shared Types and RTL-like Functions
mormot.core.buffersFramework Core Low-Level Memory Buffer Process
mormot.core.dataFramework Core Low-Level Data Processing Functions
mormot.core.jsonFramework Core Low-Level JSON Processing
mormot.core.osFramework Core Low-Level Wrappers to the Operating-System API
mormot.core.rttiFramework Core Low-Level Cross-Compiler RTTI Definitions
mormot.core.textFramework Core Low-Level Text Processing
mormot.core.unicodeFramework Core Low-Level Unicode UTF-8 UTF-16 Ansi Conversion

1.2. mormot.core.variants class hierarchy

TObjectTDocVariantDataTSynInvokeableVariantTypeTDocVariantTInvokeableVariantTypeIDocAnyIDocListIDocDictISerializableESynExceptionESynVariantEDocVariantEDocListEDocDict
mormot.core.variants class hierarchy

1.3. Objects implemented in the mormot.core.variants unit

ObjectsDescription
EDocDictException raised by IDocDict
EDocListException raised by IDocList
EDocVariantException class associated to TDocVariant JSON/BSON document
ESynVariantException class raised by this unit during raw Variant process
IDocAnyAbstract parent with common methods to IDocList/IDocDict wrappers
IDocDictA Dictionary, used to store key:value pairs
IDocListA List, used to store multiple values
TDocVariantA custom variant type used to store any JSON/BSON document-based content
TDocVariantDataMemory structure used for TDocVariant storage of any JSON/BSON document-based content as variant
TSynInvokeableVariantTypeCustom variant handler with easier/faster access of variant properties, and JSON serialization support

1.3.1. ESynVariant

ESynVariant = class(ESynException)

Exception class raised by this unit during raw Variant process


1.3.2. TSynInvokeableVariantType

TSynInvokeableVariantType = class(TInvokeableVariantType)

Custom variant handler with easier/faster access of variant properties, and JSON serialization support
- default GetProperty/SetProperty methods are called via some protected virtual IntGet/IntSet methods, with less overhead (to be overriden)
- these kind of custom variants will be faster than the default TInvokeableVariantType for properties getter/setter, but you should manually register each type by calling SynRegisterCustomVariantType()
- also feature custom JSON parsing, via TryJsonToVariant() protected method


constructor Create; virtual;

Virtual constructor which should set the custom type Options


function CompareOp(const Left, Right: TVarData; const Operation: TVarOp): boolean; override;

Compare two items - this overriden method will redirect to Compare()
- Delphi RTL does this redirection, where FPC does not (but should)


function FindSynVariantType(aVarType: cardinal): TSynInvokeableVariantType; overload;

Search of a registered custom variant type from its low-level VarType
- will first compare with its own VarType for efficiency


function FindSynVariantType(aVarType: cardinal; out CustomType: TSynInvokeableVariantType): boolean; overload;

Search of a registered custom variant type from its low-level VarType
- will first compare with its own VarType for efficiency
- returns true and set the matching CustomType if found, false otherwise


function IntCompare(const Instance, Another: TVarData; CaseInsensitive: boolean): integer; virtual;

Override this method if default VariantCompAsText() call is not optimal


function IntGet(var Dest: TVarData; const Instance: TVarData; Name: PAnsiChar; NameLen: PtrInt; NoException: boolean): boolean; virtual;

Override this abstract method for actual getter by name implementation


function IntSet(const Instance, Value: TVarData; Name: PAnsiChar; NameLen: PtrInt): boolean; virtual;

Override this abstract method for actual setter by name implementation


function IsOfType(const V: variant): boolean;

Returns TRUE if the supplied variant is of the exact custom type


function IsVoid(const V: TVarData): boolean; virtual;

Returns TRUE if the supplied custom variant is void
- e.g. returns true for a TDocVariant or TBsonVariant with Count = 0
- caller should have ensured that it is of the exact custom type


function IterateCount(const V: TVarData; GetObjectAsValues: boolean): integer; virtual;

Will check if the value is an array, and return the number of items
- if the document is an array, will return the items count (0 meaning void array) - used e.g. by TSynMustacheContextVariant
- this default implementation will return -1 (meaning this is not an array)
- overridden method could implement it, e.g. for TDocVariant of kind dvArray - or dvObject (ignoring names) if GetObjectAsValues is true


function TryJsonToVariant(var Json: PUtf8Char; var Value: variant; EndOfObject: PUtf8Char): boolean; virtual;

Customization of JSON parsing into variants
- is enabled only if the sioHasTryJsonToVariant option is set
- will be called by e.g. by VariantLoadJson() or GetVariantFromJsonField() with Options: PDocVariantOptions parameter not nil
- this default implementation will always returns FALSE, meaning that the supplied JSON is not to be handled by this custom (abstract) variant type
- this method could be overridden to identify any custom JSON content and convert it into a dedicated variant instance, then return TRUE
- warning: should NOT modify JSON buffer in-place, unless it returns true


procedure Clear(var V: TVarData); override;

Clear the content
- this default implementation will set VType := varEmpty
- override it if your custom type needs to manage its internal memory


procedure Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); override;

Compare two items - overriden method calling case-sensitive IntCompare()


procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: boolean); override;

Copy two variant content
- this default implementation will copy the TVarData memory
- override it if your custom type needs to manage its internal structure


procedure CopyByValue(var Dest: TVarData; const Source: TVarData); virtual;

Copy two variant content by value
- this default implementation will call the Copy() method
- override it if your custom types may use a by reference copy pattern


procedure Iterate(var Dest: TVarData; const V: TVarData; Index: integer); virtual;

Allow to loop over an array document
- Index should be in 0..IterateCount-1 range
- this default implementation will do nothing


procedure Lookup(var Dest: TVarData; const Instance: TVarData; FullName: PUtf8Char; PathDelim: AnsiChar = '.');

This method will allow to look for dotted name spaces, e.g. 'parent.child'
- return Unassigned (varEmpty) if the FullName does not match any value
- will identify TDocVariant storage, or resolve and call the generic TSynInvokeableVariantType.IntGet() method until nested value match
- you can set e.g. PathDelim = '/' to search e.g. for 'parent/child'


procedure ToJson(W: TJsonWriter; Value: PVarData); overload; virtual;

Customization of variant into JSON serialization


procedure ToJson(Value: PVarData; var Json: RawUtf8; const Prefix: RawUtf8 = ''; const Suffix: RawUtf8 = ''; Format: TTextWriterJsonFormat = jsonCompact); overload; virtual;

Save a variant as UTF-8 encoded JSON
- implemented as a wrapper around ToJson()


property Options: TSynInvokeableVariantTypeOptions read fOptions;

Identify how this custom type behave
- as set by the class constructor, to avoid calling any virtual method


1.3.3. EDocVariant

EDocVariant = class(ESynException)

Exception class associated to TDocVariant JSON/BSON document


1.3.4. TDocVariant

TDocVariant = class(TSynInvokeableVariantType)

A custom variant type used to store any JSON/BSON document-based content
- i.e. name/value pairs for objects, or an array of values (including nested documents), stored in a TDocVariantData memory structure
- you can use _Obj()/_ObjFast() _Arr()/_ArrFast() _Json()/_JsonFast() or _JsonFmt()/_JsonFastFmt() functions to create instances of such variants
- property access may be done via late-binding - with some restrictions for older versions of FPC, e.g. allowing to write:

 TDocVariant.NewFast(aVariant);
 aVariant.Name := 'John';
 aVariant.Age := 35;
 writeln(aVariant.Name,' is ',aVariant.Age,' years old');

- it also supports a small set of pseudo-properties or pseudo-methods:

 aVariant._Count = DocVariantData(aVariant).Count
 aVariant._Kind = ord(DocVariantData(aVariant).Kind)
 aVariant._JSON = DocVariantData(aVariant).JSON
 aVariant._(i) = DocVariantData(aVariant).Value[i]
 aVariant.Value(i) = DocVariantData(aVariant).Value[i]
 aVariant.Value(aName) = DocVariantData(aVariant).Value[aName]
 aVariant.Name(i) = DocVariantData(aVariant).Name[i]
 aVariant.Add(aItem) = DocVariantData(aVariant).AddItem(aItem)
 aVariant._ := aItem = DocVariantData(aVariant).AddItem(aItem)
 aVariant.Add(aName,aValue) = DocVariantData(aVariant).AddValue(aName,aValue)
 aVariant.Exists(aName) = DocVariantData(aVariant).GetValueIndex(aName)>=0
 aVariant.Delete(i) = DocVariantData(aVariant).Delete(i)
 aVariant.Delete(aName) = DocVariantData(aVariant).Delete(aName)
 aVariant.NameIndex(aName) = DocVariantData(aVariant).GetValueIndex(aName)

- it features direct JSON serialization/unserialization, e.g.:

 assert(_Json('["one",2,3]')._JSON='["one",2,3]');

- it features direct trans-typing into a string encoded as JSON, e.g.:

 assert(_Json('["one",2,3]')='["one",2,3]');

destructor Destroy; override;

Finalize the stored information


function DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): boolean; override;

Low-level callback to access internal pseudo-methods
- mainly the _(Index: integer): variant method to retrieve an item if the document is an array


function DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): boolean; override;

Low-level callback to access internal pseudo-methods


function IntCompare(const Instance, Another: TVarData; CaseInsensitive: boolean): integer; override;

Overriden method redirecting to TDocVariantData.Compare()


function InternNames: TRawUtf8Interning;

Used by dvoInternNames for string interning of all Names[] values


function InternValues: TRawUtf8Interning;

Used by dvoInternValues for string interning of all RawUtf8 Values[]


function IntGet(var Dest: TVarData; const Instance: TVarData; Name: PAnsiChar; NameLen: PtrInt; NoException: boolean): boolean; override;

Overriden method for actual getter by name implementation


function IntSet(const Instance, Value: TVarData; Name: PAnsiChar; NameLen: PtrInt): boolean; override;

Overriden method for actual setter by name implementation


function IsVoid(const V: TVarData): boolean; override;

Returns true if this document has Count = 0


function IterateCount(const V: TVarData; GetObjectAsValues: boolean): integer; override;

Will check if the value is an array, and return the number of items
- if the document is an array, will return the items count (0 meaning void array) - used e.g. by TSynMustacheContextVariant
- this overridden method will implement it for dvArray instance kind


class function New(Options: TDocVariantOptions = []): variant; overload;

Initialize a variant instance to store some document-based content
- you can use this function to create a variant, which can be nested into another document, e.g.:

 aVariant := TDocVariant.New;
 aVariant.id := 10;

- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set Options=[dvoValueCopiedByReference] will increase the process speed a lot
- in practice, you should better use _Obj()/_ObjFast() _Arr()/_ArrFast() functions or TDocVariant.NewFast()


class function NewArray(const Items: array of const; Options: TDocVariantOptions = []): variant; overload;

Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied as parameters, e.g.

 aVariant := TDocVariant.NewArray(['one',2,3.0]);

which is the same as:

 TDocVariant.New(aVariant);
 TDocVariantData(aVariant).AddItem('one');
 TDocVariantData(aVariant).AddItem(2);
 TDocVariantData(aVariant).AddItem(3.0);

- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set aOptions=[dvoValueCopiedByReference] will increase the process speed a lot
- in practice, you should better use the function _Arr() which is a wrapper around this class method


class function NewArray(const Items: TVariantDynArray; Options: TDocVariantOptions = []): variant; overload;

Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied dynamic array of variants


class function NewJson(const Json: RawUtf8; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): variant;

Initialize a variant instance to store some document-based object content from a supplied (extended) JSON content
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names
- a private copy of the incoming JSON buffer will be used, then it will call the TDocVariantData.InitJsonInPlace() method
- to be used e.g. as:

 var V: variant;
 begin
   V := TDocVariant.NewJson('{"id":10,"doc":{"name":"John","birthyear":1972}}');
   assert(V.id=10);
   assert(V.doc.name='John');
   assert(V.doc.birthYear=1972);
   // and also some pseudo-properties:
   assert(V._count=2);
   assert(V.doc._kind=ord(dvObject));

- or with a JSON array:

   V := TDocVariant.NewJson('["one",2,3]');
   assert(V._kind=ord(dvArray));
   for i := 0 to V._count-1 do
     writeln(V._(i));

- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, add dvoValueCopiedByReference in Options will increase the process speed a lot
- in practice, you should better use the function _Json()/_JsonFast() which are handy wrappers around this class method


class function NewObject(const NameValuePairs: array of const; Options: TDocVariantOptions = []): variant;

Initialize a variant instance to store some document-based object content
- object will be initialized with data supplied two by two, as Name,Value pairs, e.g.

 aVariant := TDocVariant.NewObject(['name','John','year',1972]);

which is the same as:

 TDocVariant.New(aVariant);
 TDocVariantData(aVariant).AddValue('name','John');
 TDocVariantData(aVariant).AddValue('year',1972);

- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set Options=[dvoValueCopiedByReference] will increase the process speed a lot
- in practice, you should better use the function _Obj() which is a wrapper around this class method


class function NewUnique(const SourceDocVariant: variant; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): variant;

Initialize a variant instance to store some document-based object content from a supplied existing TDocVariant instance
- use it on a value returned as varByRef (e.g. by _() pseudo-method), to ensure the returned variant will behave as a stand-alone value
- for instance, the following:

  oSeasons := TDocVariant.NewUnique(o.Seasons);

is the same as:

  _Unique(oSeasons);

or even:

  oSeasons := _Copy(o.Seasons);

procedure Cast(var Dest: TVarData; const Source: TVarData); override;

Handle type conversion
- only types processed by now are string/OleStr/UnicodeString/date


procedure CastTo(var Dest: TVarData; const Source: TVarData; const AVarType: TVarType); override;

Handle type conversion
- only types processed by now are string/OleStr/UnicodeString/date


procedure Clear(var V: TVarData); override;

Low-level callback to clear the content


procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: boolean); override;

Low-level callback to copy two variant content
- such copy will by default be done by-value, for safety
- if you are sure you will use the variants as read-only, you can set the dvoValueCopiedByReference Option to use faster by-reference copy


procedure CopyByValue(var Dest: TVarData; const Source: TVarData); override;

Copy two variant content by value
- overridden method since instance may use a by-reference copy pattern


class procedure GetSingleOrDefault(const docVariantArray, default: variant; var result: variant);

Will return the unique element of a TDocVariant array or a default
- if the value is a dvArray with one single item, returns this value
- if the value is not a TDocVariant nor a dvArray with one single item, it wil return the default value


class procedure IsOfTypeOrNewFast(var aValue: variant);

Ensure a variant is a TDocVariant instance
- if aValue is not a TDocVariant, will create a new JSON_FAST


procedure Iterate(var Dest: TVarData; const V: TVarData; Index: integer); override;

Allow to loop over an array document
- Index should be in 0..IterateCount-1 range
- this default implementation will do handle dvArray instance kind


class procedure New(out aValue: variant; aOptions: TDocVariantOptions = []); overload;

Initialize a variant instance to store some document-based content
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set aOptions=[dvoValueCopiedByReference] will increase the process speed a lot


class procedure NewFast(const aValues: array of PDocVariantData; aKind: TDocVariantKind = dvUndefined); overload;

Initialize several variant instances to store document-based content
- replace several calls to TDocVariantData.InitFast
- to be used e.g. as

var
  v1, v2, v3: TDocVariantData;
begin
  TDocVariant.NewFast([@v1,@v2,@v3]);
  ...

class procedure NewFast(out aValue: variant; aKind: TDocVariantKind = dvUndefined); overload;

Initialize a variant instance to store per-reference document-based content
- same as New(aValue, JSON_FAST);
- to be used e.g. as

var
  v: variant;
begin
  TDocVariant.NewFast(v);
  ...

procedure ToJson(W: TJsonWriter; Value: PVarData); override;

This implementation will write the content as JSON object or array


1.3.5. TDocVariantData

TDocVariantData = object(TObject)

Memory structure used for TDocVariant storage of any JSON/BSON document-based content as variant
- i.e. name/value pairs for objects, or an array of values (including nested documents)
- you can use _Obj()/_ObjFast() _Arr()/_ArrFast() _Json()/_JsonFast() or _JsonFmt()/_JsonFastFmt() functions to create instances of such variants
- you can transtype such an allocated variant into TDocVariantData to access directly its internals (like Count or Values[]/Names[]):

 aVariantObject := TDocVariant.NewObject(['name','John','year',1972]);
 aVariantObject := _ObjFast(['name','John','year',1972]);
 with _Safe(aVariantObject)^ do
   for i := 0 to Count-1 do
     writeln(Names[i],'=',Values[i]); // for an object
 aVariantArray := TDocVariant.NewArray(['one',2,3.0]);
 aVariantArray := _JsonFast('["one",2,3.0]');
 with _Safe(aVariantArray)^ do
   for i := 0 to Count-1 do
     writeln(Values[i]); // for an array

- use "with _Safe(...)^ do" and not "with TDocVariantData(...) do" as the former will handle internal variant redirection (varByRef), e.g. from late binding or assigned another TDocVariant
- Delphi "object" is buggy on stack -> also defined as record with methods


function AddItem(const aValue: variant; aIndex: integer = -1): integer; overload;

Add a value to this document, handled as array
- if instance's Kind is dvObject, it will raise an EDocVariant exception
- you can therefore write e.g.:

 TDocVariant.New(aVariant);
 Assert(TDocVariantData(aVariant).Kind=dvUndefined);
 TDocVariantData(aVariant).AddItem('one');
 Assert(TDocVariantData(aVariant).Kind=dvArray);

- you can specify an optional index in the array where to insert
- returns the index of the corresponding newly added item


function AddItem(const aValue: TDocVariantData; aIndex: integer = -1): integer; overload;

Add a TDocVariant value to this document, handled as array


function AddItemFromText(const aValue: RawUtf8; aIndex: integer = -1): integer;

Add a value to this document, handled as array, from its text representation
- this function expects a UTF-8 text for the value, which would be converted to a variant number, if possible (as varInt/varInt64/varCurrency and/or as varDouble is dvoAllowDoubleValue option is set)
- if instance's Kind is dvObject, it will raise an EDocVariant exception
- you can specify an optional index in the array where to insert
- returns the index of the corresponding newly added item


function AddItemText(const aValue: RawUtf8; aIndex: integer = -1): integer;

Add a RawUtf8 value to this document, handled as array
- if instance's Kind is dvObject, it will raise an EDocVariant exception
- you can specify an optional index in the array where to insert
- returns the index of the corresponding newly added item


function AddOrUpdateValue(const aName: RawUtf8; const aValue: variant; wasAdded: PBoolean = nil; OnlyAddMissing: boolean = false): integer;

Add a value in this document, or update an existing entry
- if instance's Kind is dvArray, it will raise an EDocVariant exception
- any existing Name would be updated with the new Value, unless OnlyAddMissing is set to TRUE, in which case existing values would remain
- returns the index of the corresponding value, which may be just added


function AddValue(aName: PUtf8Char; aNameLen: integer; const aValue: variant; aValueOwned: boolean = false; aIndex: integer = -1): integer; overload;

Add a value in this document
- overloaded function accepting a UTF-8 encoded buffer for the name


function AddValue(const aName: RawUtf8; const aValue: variant; aValueOwned: boolean = false; aIndex: integer = -1): integer; overload;

Add a value in this document
- if aName is set, if dvoCheckForDuplicatedNames option is set, any existing duplicated aName will raise an EDocVariant; if instance's kind is dvArray and aName is defined, it will raise an EDocVariant
- aName may be '' e.g. if you want to store an array: in this case, dvoCheckForDuplicatedNames option should not be set; if instance's Kind is dvObject, it will raise an EDocVariant exception
- if aValueOwned is true, then the supplied aValue will be assigned to the internal values - by default, it will use SetVariantByValue()
- you can therefore write e.g.:

 TDocVariant.New(aVariant);
 Assert(TDocVariantData(aVariant).Kind=dvUndefined);
 TDocVariantData(aVariant).AddValue('name','John');
 Assert(TDocVariantData(aVariant).Kind=dvObject);

- you can specify an optional index in the array where to insert
- returns the index of the corresponding newly added value


function AddValueFromText(const aName, aValue: RawUtf8; DoUpdate: boolean = false): integer;

Add a value in this document, from its text representation
- this function expects a UTF-8 text for the value, which would be converted to a variant number, if possible (as varInt/varInt64/varCurrency and/or as varDouble is dvoAllowDoubleValue option is set)
- if Update=TRUE, will set the property, even if it is existing


function Compare(const Another: TDocVariantData; CaseInsensitive: boolean = false): integer; overload;

Efficient comparison of two TDocVariantData content
- will return the same result than JSON comparison, but more efficiently


function Compare(const aName: RawUtf8; const aValue: variant; aCaseInsensitive: boolean = false): integer; overload;

Compare a TTDocVariantData object property with a given value
- returns -1 if this instance is not a dvObject or has no aName property


function CompareObject(const ObjFields: array of RawUtf8; const Another: TDocVariantData; CaseInsensitive: boolean = false): integer;

Efficient comparison of two TDocVariantData objects
- will always ensure that both this instance and Another are Objects
- will compare all supplied Fields values in their specified order
- if ObjFields is void, will fallback to regular Compare()


function CountItemByValue(const aValue: Variant; CaseInsensitive: boolean = false; StartIndex: integer = 0): integer;

Search and count occurences of one value in this document, handled as array


function Delete(Index: PtrInt): boolean; overload;

Delete a value/item in this document, from its index
- return TRUE on success, FALSE if the supplied index is not correct


function Delete(const aNames: array of RawUtf8): integer; overload;

Delete/filter some values/items in this document, from their name
- return the number of deleted items


function Delete(const aName: RawUtf8; aValue: PVariant = nil): boolean; overload;

Delete a value/item in this document, from its name
- return TRUE on success, FALSE if the supplied name does not exist


function DeleteByPath(const aPath: RawUtf8; aPathDelim: AnsiChar = '.'; aDeletedValue: PVariant = nil): boolean;

Delete a value/item in this document, from its name
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- return TRUE on success, FALSE if the supplied name does not exist
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'


function DeleteByProp(const aPropName, aPropValue: RawUtf8; aPropValueCaseSensitive: boolean): boolean;

Delete a value in this document, by property name match
- {aPropName:aPropValue} will be searched within the stored array or object, and the corresponding item will be deleted, on match
- returns FALSE if no match is found, TRUE if found and deleted
- will call VariantEquals() for value comparison


function DeleteByStartName(aStartName: PUtf8Char; aStartNameLen: integer): integer;

Delete all values matching the first characters of a property name
- returns the number of deleted items
- returns 0 if the document is not a dvObject, or if no match was found
- will use IdemPChar(), so search would be case-insensitive


function DeleteByValue(const aValue: Variant; CaseInsensitive: boolean = false): integer;

Delete one or several value/item in this document, from its value
- returns the number of deleted items
- returns 0 if the document is not a dvObject, or if no match was found
- if the value exists several times, all occurrences would be removed
- is optimized for DeleteByValue(null) call


function Equals(const aName: RawUtf8; const aValue: variant; aCaseInsensitive: boolean = false): boolean; overload;

Efficient equality comparison a TTDocVariantData object property


function Equals(const Another: TDocVariantData; CaseInsensitive: boolean = false): boolean; overload;

Efficient equality comparison of two TDocVariantData content
- just a wrapper around Compare(Another)=0


function Exists(const aName: RawUtf8): boolean;

Search if a given Name do exists in this document
- just a wrapper around GetValueIndex(aName) >= 0


function Extract(aIndex: integer; var aValue: variant; aName: PRawUtf8 = nil): boolean;

Retrieve a value at a given index, and delete it from the array
- negative aIndex are from VCount, i.e. Extract(-1) pop the last item


function FlattenAsNestedObject(const aObjectPropName: RawUtf8): boolean;

Map {"obj.prop1"..,"obj.prop2":..} into {"obj":{"prop1":..,"prop2":...}}
- the supplied aObjectPropName should match the incoming dotted value of all properties (e.g. 'obj' for "obj.prop1")
- if any of the incoming property is not of "obj.prop#" form, the whole process would be ignored
- return FALSE if the TDocVariant did not change
- return TRUE if the TDocVariant has been flattened


function GetAsArray(const aName: RawUtf8; out aArray: PDocVariantData; aSortedCompare: TUtf8Compare = nil): boolean;

Find a non-void array item in this document, and returns its value
- return false if aName is not found, or if not a TDocVariant array
- return true if the name was found as non-void array and set to aArray
- after a SortByName(aSortedCompare), could use faster binary search


function GetAsBoolean(const aName: RawUtf8; out aValue: boolean; aSortedCompare: TUtf8Compare = nil): boolean;

Find an item in this document, and returns its value as boolean
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using B[] property if you want simple read/write typed access


function GetAsDocVariant(const aName: RawUtf8; out aValue: PDocVariantData; aSortedCompare: TUtf8Compare = nil): boolean;

Find an item in this document, and returns its value as a TDocVariantData
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found and points to a TDocVariant: then aValue stores a pointer to the value
- after a SortByName(aSortedCompare), could use faster binary search


function GetAsDocVariantSafe(const aName: RawUtf8; aSortedCompare: TUtf8Compare = nil): PDocVariantData;

Find an item in this document, and returns its value as a TDocVariantData
- returns a void TDocVariant if aName is not a document
- after a SortByName(aSortedCompare), could use faster binary search
- consider using O[] or A[] properties if you want simple read-only access, or O_[] or A_[] properties if you want the ability to add a missing object or array in the document


function GetAsDouble(const aName: RawUtf8; out aValue: double; aSortedCompare: TUtf8Compare = nil): boolean;

Find an item in this document, and returns its value as floating point
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using D[] property if you want simple read/write typed access


function GetAsInt64(const aName: RawUtf8; out aValue: Int64; aSortedCompare: TUtf8Compare = nil): boolean;

Find an item in this document, and returns its value as integer
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using I[] property if you want simple read/write typed access


function GetAsInteger(const aName: RawUtf8; out aValue: integer; aSortedCompare: TUtf8Compare = nil): boolean;

Find an item in this document, and returns its value as integer
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using I[] property if you want simple read/write typed access


function GetAsObject(const aName: RawUtf8; out aObject: PDocVariantData; aSortedCompare: TUtf8Compare = nil): boolean;

Find a non-void object item in this document, and returns its value
- return false if aName is not found, or if not a TDocVariant object
- return true if the name was found as non-void object and set to aObject
- after a SortByName(aSortedCompare), could use faster binary search


function GetAsPVariant(aName: PUtf8Char; aNameLen: PtrInt): PVariant; overload;

Find an item in this document, and returns pointer to its value
- lookup the value by aName/aNameLen for an object document, or accept an integer text as index for an array document
- return nil if aName is not found, or if the instance is not a TDocVariant
- return a pointer to the stored variant, if the name has been found


function GetAsPVariant(const aName: RawUtf8; out aValue: PVariant; aSortedCompare: TUtf8Compare = nil): boolean; overload;

Find an item in this document, and returns pointer to its value
- return false if aName is not found
- return true if the name has been found: then aValue stores a pointer to the value
- after a SortByName(aSortedCompare), could use faster binary search


function GetAsRawUtf8(const aName: RawUtf8; out aValue: RawUtf8; aSortedCompare: TUtf8Compare = nil): boolean;

Find an item in this document, and returns its value as RawUtf8
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using U[] property if you want simple read/write typed access


function GetDocVariantByPath(const aPath: RawUtf8; out aValue: PDocVariantData; aPathDelim: AnsiChar = '.'): boolean;

Retrieve a reference to a TDocVariant, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- if the supplied aPath does not match any object, it will return false
- if aPath stores a valid TDocVariant, returns true and a pointer to it
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'


function GetDocVariantByProp(const aPropName, aPropValue: RawUtf8; aPropValueCaseSensitive: boolean; out Dest: PDocVariantData): boolean;

Retrieve a reference to a dvObject in the dvArray, from a property value
- {aPropName:aPropValue} will be searched within the stored array, and the corresponding item will be copied into Dest, on match
- returns FALSE if no match is found, TRUE if found and copied by reference


function GetItemByProp(const aPropName, aPropValue: RawUtf8; aPropValueCaseSensitive: boolean; var Dest: variant; DestByRef: boolean = false): boolean;

Retrieve a dvObject in the dvArray, from a property value
- {aPropName:aPropValue} will be searched within the stored array, and the corresponding item will be copied into Dest, on match
- returns FALSE if no match is found, TRUE if found and copied
- create a copy of the variant by default, unless DestByRef is TRUE
- will call VariantEquals() for value comparison


function GetJsonByStartName(const aStartName: RawUtf8): RawUtf8;

Returns a JSON object containing all properties matching the first characters of the supplied property name
- returns null if the document is not a dvObject
- will use IdemPChar(), so search would be case-insensitive


function GetModel(out model: TDocVariantModel): boolean;

Guess the TDocVariantModel corresponding to the current document Options
- returns true if model has been found and set
- returns false if no JSON_[] matches the current options


function GetNames: TRawUtf8DynArray;

Return a dynamic array with all dvObject Names, and length() = Count
- since length(Names) = Capacity, you can use this method to retrieve all the object keys
- consider using FieldNames iterator or Names[0..Count-1] if you need to iterate on the key names
- will internally force length(Names)=length(Values)=Capacity=Count and return the Names[] instance with no memory (re)allocation
- if the document is not a dvObject, will return nil


function GetPVariantByPath(const aPath: RawUtf8; aPathDelim: AnsiChar = '.'): PVariant;

Retrieve a reference to a value, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- if the supplied aPath does not match any object, it will return nil
- if aPath is found, returns a pointer to the corresponding value
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'


function GetPVariantExistingByPath(const aPath: RawUtf8; aPathDelim: AnsiChar = '.'): PVariant;

Retrieve a reference to a value, given its path
- if the supplied aPath does not match any object, it will follow dvoReturnNullForUnknownProperty option


function GetValueByPath( const aPath: RawUtf8; aPathDelim: AnsiChar = '.'): variant; overload;

Retrieve a value, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- return Unassigned (varEmpty) if there is no item at the supplied aPath
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
- see also the P[] property if the default aPathDelim = '.' is enough


function GetValueByPath(const aPath: RawUtf8; out aValue: variant; aPathDelim: AnsiChar = '.'): boolean; overload;

Retrieve a value, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- returns FALSE if there is no item at the supplied aPath
- returns TRUE and set the found value in aValue
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
- see also the P[] property if the default aPathDelim = '.' is enough


function GetValueByPath(const aDocVariantPath: array of RawUtf8): variant; overload;

Retrieve a value, given its path
- path is defined as a list of names, e.g. ['doc','glossary','title']
- return Unassigned (varEmpty) if there is no item at the supplied aPath
- this method will only handle nested TDocVariant values: use the slightly slower GetValueByPath() overloaded method, if any nested object may be of another type (e.g. a TBsonVariant)


function GetValueEnumerate(const aName: RawUtf8; aTypeInfo: PRttiInfo; out aValue; aDeleteFoundEntry: boolean = false): boolean;

Find an item in this document, and returns its value as enumerate
- return false if aName is not found, if the instance is not a TDocVariant, or if the value is not a string corresponding to the supplied enumerate
- return true if the name has been found, and aValue stores the value
- will call Delete() on the found entry, if aDeleteFoundEntry is true


function GetValueIndex(aName: PUtf8Char; aNameLen: PtrInt; aCaseSensitive: boolean): integer; overload;

Find an item index in this document from its name
- lookup the value by name for an object document, or accept an integer text as index for an array document
- returns -1 if not found


function GetValueIndex(const aName: RawUtf8): integer; overload;

Find an item index in this document from its name
- search will follow dvoNameCaseSensitive option of this document
- lookup the value by name for an object document, or accept an integer text as index for an array document
- returns -1 if not found


function GetValueOrDefault(const aName: RawUtf8; const aDefault: variant): variant;

Find an item in this document, and returns its value
- return the supplied default if aName is not found, or if the instance is not a TDocVariant


function GetValueOrEmpty(const aName: RawUtf8): variant;

Find an item in this document, and returns its value
- return a cleared variant if aName is not found, or if the instance is not a TDocVariant


function GetValueOrNull(const aName: RawUtf8): variant;

Find an item in this document, and returns its value
- return null if aName is not found, or if the instance is not a TDocVariant


function GetValueOrRaiseException(const aName: RawUtf8): variant;

Find an item in this document, and returns its value
- raise an EDocVariant if not found and dvoReturnNullForUnknownProperty is not set in Options (in this case, it will return Null)


function GetValuesByStartName(const aStartName: RawUtf8; TrimLeftStartName: boolean = false): variant;

Returns a TDocVariant object containing all properties matching the first characters of the supplied property name
- returns null if the document is not a dvObject
- will use IdemPChar(), so search would be case-insensitive


function GetVarData(const aName: RawUtf8; aSortedCompare: TUtf8Compare = nil; aFoundIndex: PInteger = nil): PVarData; overload;

Find an item in this document, and returns its value as TVarData pointer
- return nil if aName is not found, or if the instance is not a TDocVariant
- return a pointer to the value if the name has been found, and optionally fill aFoundIndex^ with its index in Values[]
- after a SortByName(aSortedCompare), could use faster binary search


function GetVarData(const aName: RawUtf8; var aValue: TVarData; aSortedCompare: TUtf8Compare = nil): boolean; overload;

Find an item in this document, and returns its value as TVarData
- return false if aName is not found, or if the instance is not a TDocVariant
- return true and set aValue if the name has been found
- will use simple loop lookup to identify the name, unless aSortedCompare is set, and would let use a faster O(log(n)) binary search after a SortByName()


function InitArrayFromResults(const Json: RawUtf8; aModel: TDocVariantModel): boolean; overload;

Fill a TDocVariant array from standard or non-expanded JSON ORM/DB result
- accept the ORM/DB results dual formats as recognized by TOrmTableJson
- about 2x (expanded) or 3x (non-expanded) faster than Doc.InitJson()
- will also use less memory, because all object field names will be shared
- in expanded mode, the fields order won't be checked, as with TOrmTableJson
- a private copy of the incoming JSON buffer will be used before parsing


function InitArrayFromResults(const Json: RawUtf8; aOptions: TDocVariantOptions = JSON_FAST_FLOAT): boolean; overload;

Fill a TDocVariant array from standard or non-expanded JSON ORM/DB result
- accept the ORM/DB results dual formats as recognized by TOrmTableJson
- about 2x (expanded) or 3x (non-expanded) faster than Doc.InitJson()
- will also use less memory, because all object field names will be shared
- in expanded mode, the fields order won't be checked, as with TOrmTableJson
- a private copy of the incoming JSON buffer will be used before parsing


function InitArrayFromResults(Json: PUtf8Char; JsonLen: PtrInt; aOptions: TDocVariantOptions = JSON_FAST_FLOAT): boolean; overload;

Fill a TDocVariant array from standard or non-expanded JSON ORM/DB result
- accept the ORM/DB results dual formats as recognized by TOrmTableJson, i.e. both [{"f1":"1v1","f2":1v2},{"f2":"2v1","f2":2v2}...] and {"fieldCount":2,"values":["f1","f2","1v1",1v2,"2v1",2v2...],"rowCount":20}
- about 2x (expanded) or 3x (non-expanded) faster than Doc.InitJsonInPlace()
- will also use less memory, because all object field names will be shared
- in expanded mode, the fields order won't be checked, as with TOrmTableJson
- warning: the incoming JSON buffer will be modified in-place: so you should make a private copy before running this method, as overloaded procedures do
- some numbers on a Core i5-13500, extracted from our regression tests:

 TDocVariant InitJsonInPlace in 72.91ms i.e. 2.1M rows/s, 268.8 MB/s
 TDocVariant InitJsonInPlace no guess in 69.49ms i.e. 2.2M rows/s, 282 MB/s
 TDocVariant InitJsonInPlace dvoIntern in 68.41ms i.e. 2.2M rows/s, 286.5 MB/s
 TDocVariant FromResults exp in 31.69ms i.e. 4.9M rows/s, 618.6 MB/s
 TDocVariant FromResults not exp in 24.48ms i.e. 6.4M rows/s, 352.1 MB/s

function InitFrom(const CloneFrom: TDocVariantData; CloneValues: boolean; MakeUnique: boolean = false): PVariant;

Low-level copy a document-based variant with the very same options and count
- if you call Init*() methods in a row, ensure you call Clear in-between
- will copy Count and Names[] by reference, but Values[] only if CloneValues
- returns the first item in Values[]


function InitJson(const Json: RawUtf8; aModel: TDocVariantModel): boolean; overload;

Initialize a variant instance to store some document-based object content from a supplied JSON array or JSON object content
- use the options corresponding to the supplied TDocVariantModel
- a private copy of the incoming JSON buffer will be made
- if you call Init*() methods in a row, ensure you call Clear in-between
- handle only currency for floating point values unless you set mFastFloat
- consider the faster InitArrayFromResults() from ORM/SQL JSON results


function InitJson(const Json: RawUtf8; aOptions: TDocVariantOptions = []): boolean; overload;

Initialize a variant instance to store some document-based object content from a supplied JSON array or JSON object content
- a private copy of the incoming JSON buffer will be used, then it will call the other overloaded InitJsonInPlace() method
- this method is called e.g. by _Json() and _JsonFast() global functions
- if you call Init*() methods in a row, ensure you call Clear in-between
- handle only currency for floating point values: set JSON_FAST_FLOAT or dvoAllowDoubleValue option to support double, with potential precision loss
- consider the faster InitArrayFromResults() from ORM/SQL JSON results


function InitJsonFromFile(const FileName: TFileName; aOptions: TDocVariantOptions = []): boolean;

Initialize a variant instance to store some document-based object content from a file containing some JSON array or JSON object
- file may have been serialized using the SaveToJsonFile() method
- if you call Init*() methods in a row, ensure you call Clear in-between
- handle only currency for floating point values: set JSON_FAST_FLOAT or dvoAllowDoubleValue option to support double, with potential precision loss
- will assume text file with no BOM is already UTF-8 encoded


function InitJsonInPlace(Json: PUtf8Char; aOptions: TDocVariantOptions = []; aEndOfObject: PUtf8Char = nil): PUtf8Char;

Initialize a variant instance to store some document-based object content from a supplied JSON array or JSON object content
- warning: the incoming JSON buffer will be modified in-place: so you should make a private copy before running this method, as InitJson() does
- this method is called e.g. by _JsonFmt() _JsonFastFmt() global functions with a temporary JSON buffer content created from a set of parameters
- if you call Init*() methods in a row, ensure you call Clear in-between
- consider the faster InitArrayFromResults() from ORM/SQL JSON results


function InternalAdd(const aName: RawUtf8; aIndex: integer = -1): integer;

Low-level method called internally to reserve place for new values
- returns the index of the newly created item in Values[]/Names[] arrays
- you should not have to use it, unless you want to add some items directly within the Values[]/Names[] arrays, using e.g. InitFast(InitialCapacity) to initialize the document
- if aName='', append a dvArray item, otherwise append a dvObject field
- you can specify an optional aIndex value to Insert instead of Add
- warning: FPC optimizer is confused by Values[InternalAdd(name)] so you should call InternalAdd() in an explicit previous step


function IsArray: boolean;

Check if the Document is an array - i.e. Kind = dvArray


function IsCaseSensitive: boolean;

Check if names lookups are case sensitive in this object Document


function IsObject: boolean;

Check if the Document is an object - i.e. Kind = dvObject


function IsVoid: boolean;

Returns true if this is not a true TDocVariant, or Count equals 0


function Reduce(const aPropNames: array of RawUtf8; aCaseSensitive: boolean; aDoNotAddVoidProp: boolean = false): variant; overload;

Create a TDocVariant object, from a selection of properties of the objects of this document array, by property name
- always returns a TDocVariantData, even if no property name did match (in this case, it is dvUndefined)


function ReduceAsArray(const aPropName: RawUtf8; const OnReduce: TOnReducePerItem = nil): variant; overload;

Create a TDocVariant array, from the values of a single property of the objects of this document array, specified by name
- always returns a TDocVariantData, even if no property name did match (in this case, it is dvUndefined)
- you can optionally apply an additional filter to each reduced item


function ReduceAsArray(const aPropName: RawUtf8; const OnReduce: TOnReducePerValue): variant; overload;

Create a TDocVariant array, from the values of a single property of the objects of this document array, specified by name
- always returns a TDocVariantData, even if no property name did match (in this case, it is dvUndefined)
- this overloaded method accepts an additional filter to each reduced item


function ReduceAsVariantArray(const aPropName: RawUtf8; aDuplicates: TSearchDuplicate = sdNone): TVariantDynArray;

Return the variant values of a single property of the objects of this document array, specified by name
- returns nil if the document is not a dvArray


function ReduceFilter(const aExpression: RawUtf8; aLimit: integer = 0; aPathDelim: AnsiChar = #0): variant; overload;

Create a TDocVariant array, matching a filtering expression
- expressions are e.g. 'name=Synopse' or 'price<100'


function ReduceFilter(const aExpression: RawUtf8; const aValue: variant; aLimit: integer = 0; aPathDelim: AnsiChar = #0): variant; overload;

Create a TDocVariant array, matching a filtering expression
- e.g. ReduceFilter('name=','Synopse') or ReduceFilter('price<',MaxPrice)


function Rename(const aFromPropName, aToPropName: TRawUtf8DynArray): integer;

Rename some properties of a TDocVariant object
- returns the number of property names modified


function RetrieveValueOrRaiseException(aName: PUtf8Char; aNameLen: integer; aCaseSensitive: boolean; var Dest: variant; DestByRef: boolean): boolean; overload;

Find an item in this document, and returns its value
- raise an EDocVariant if not found and dvoReturnNullForUnknownProperty is not set in Options (in this case, it will return Null)
- create a copy of the variant by default, unless DestByRef is TRUE


function SearchItemByProp(const aPropName, aPropValue: RawUtf8; aPropValueCaseSensitive: boolean): integer; overload;

Search a property match in this document, handled as array or object
- {aPropName:aPropValue} will be searched within the stored array or object, and the corresponding item index will be returned, on match
- returns -1 if no match is found
- will call VariantEquals() for value comparison


function SearchItemByProp(const aPropNameFmt: RawUtf8; const aPropNameArgs: array of const; const aPropValue: RawUtf8; aPropValueCaseSensitive: boolean): integer; overload;

Search a property match in this document, handled as array or object
- {aPropName:aPropValue} will be searched within the stored array or object, and the corresponding item index will be returned, on match
- returns -1 if no match is found
- will call VariantEquals() for value comparison


function SearchItemByValue(const aValue: Variant; CaseInsensitive: boolean = false; StartIndex: PtrInt = 0): PtrInt;

Search a value in this document, handled as array
- aValue will be searched within the stored array and the corresponding item index will be returned, on match
- returns -1 if no match is found
- you could make several searches, using the StartIndex optional parameter


function SetValueByPath(const aPath: RawUtf8; const aValue: variant; aCreateIfNotExisting: boolean = false; aPathDelim: AnsiChar = '.'; aMergeExisting: boolean = false): PVariant;

Set a value, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- aCreateIfNotExisting=true will force missing nested objects creation
- aMergeExisting=true will merge aValue object with any existing object
- returns nil if there is no item to be set at the supplied aPath
- returns the address of the found or created value in aValue
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'


function ToArrayOfConst: TTVarRecDynArray; overload;

Save an array document as an array of TVarRec, i.e. an array of const
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- values will be passed by referenced as vtVariant to @VValue[ndx]
- would allow to write code as such:

  Doc.InitArray(['one',2,3]);
  s := FormatUtf8('[%,%,%]',Doc.ToArrayOfConst,[],true);
  // here s='[one,2,3]') since % would be replaced by Args[] parameters
  s := FormatUtf8('[?,?,?]',[],Doc.ToArrayOfConst,true);
  // here s='["one",2,3]') since ? would be escaped by Params[] parameters

function ToCsv(const Separator: RawUtf8 = ','): RawUtf8;

Save a document as an CSV of UTF-8 encoded JSON
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- will use VariantToUtf8() to populate the result array: as a consequence, any nested custom variant types (e.g. TDocVariant) will be stored as JSON


function ToJson(const Prefix, Suffix: RawUtf8; Format: TTextWriterJsonFormat): RawUtf8; overload;

Save a document as UTF-8 encoded JSON


function ToJson: RawUtf8; overload;

Save a document as UTF-8 encoded JSON
- will write either a JSON object or array, depending of the internal layout of this instance (i.e. Kind property value)
- will write 'null' if Kind is dvUndefined
- implemented as just a wrapper around DocVariantType.ToJson()


function ToNonExpandedJson: RawUtf8;

Save an array of objects as UTF-8 encoded non expanded layout JSON
- returned content would be a JSON object in mORMot's TOrmTableJson non expanded format, with reduced JSON size, i.e.

 {"fieldCount":2,"values":["f1","f2","1v1",1v2,"2v1",2v2...],"rowCount":20}

- will write '' if Kind is dvUndefined or dvObject
- will raise an exception if the array document is not an array of objects with identical field names
- can be unserialized using the InitArrayFromResults() method


function ToRawUtf8DynArray: TRawUtf8DynArray; overload;

Save a document as an array of UTF-8 encoded JSON
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- will use VariantToUtf8() to populate the result array: as a consequence, any nested custom variant types (e.g. TDocVariant) will be stored as JSON


function ToTextPairs(const NameValueSep: RawUtf8 = '='; const ItemSep: RawUtf8 = #13#10; Escape: TTextWriterKind = twJsonEscape): RawUtf8;

Save a document as UTF-8 encoded Name=Value pairs
- will follow by default the .INI format, but you can specify your own expected layout


function ToUrlEncode(const UriRoot: RawUtf8): RawUtf8;

Save an object document as an URI-encoded list of parameters
- object field names should be plain ASCII-7 RFC compatible identifiers (0..9a..zA..Z_.~), otherwise their values are skipped


procedure AddByPath(const aSource: TDocVariantData; const aPaths: array of RawUtf8; aPathDelim: AnsiChar = '.');

Add one or several properties, specified by path, from another object
- path are defined as open array, e.g. ['doc','glossary','title'], but could also contained nested paths, e.g. ['doc.glossary', title'] or ['doc', 'glossary/title'] of aPathDelim is '/'
- matching values would be added as root values, with the path as name
- instance and supplied aSource should be a dvObject


procedure AddFrom(const aDocVariant: Variant);

Add one or several values from another document
- supplied document should be of the same kind than the current one, otherwise nothing is added
- for an object, dvoCheckForDuplicatedNames flag is used: use AddOrUpdateFrom() to force objects merging


procedure AddItems(const aValue: array of const);

Add one or several values to this document, handled as array
- if instance's Kind is dvObject, it will raise an EDocVariant exception


procedure AddNameValuesToObject(const NameValuePairs: array of const);

Add some properties to a TDocVariantData dvObject
- data is supplied two by two, as Name,Value pairs
- caller should ensure that Kind=dvObject, otherwise it won't do anything
- any existing Name would be duplicated - use Update() if you want to replace any existing value


procedure AddObject(const aNameValuePairs: array of const; const aName: RawUtf8 = '');

Add one object document to this document
- if the document is an array, keep aName=''
- if the document is an object, set the new object property as aName
- new object will keep the same options as this document
- slightly faster than AddItem(_Obj(...)) or AddValue(aName, _Obj(...))


procedure AddOrUpdateFrom(const aDocVariant: Variant; aOnlyAddMissing: boolean = false);

Merge (i.e. add or update) several values from another object
- current document should be an object


procedure AddOrUpdateNameValuesToObject(const NameValuePairs: array of const);

Deprecated method which redirects to Update()


procedure AddOrUpdateObject(const NewValues: variant; OnlyAddMissing: boolean = false; RecursiveUpdate: boolean = false);

Merge some TDocVariantData dvObject properties to a TDocVariantData dvObject
- data is supplied two by two, as Name,Value pairs
- caller should ensure that both variants have Kind=dvObject, otherwise it won't do anything
- any existing Name would be updated with the new Value, unless OnlyAddMissing is set to TRUE, in which case existing values would remain


procedure Clear;

To be called before any Init*() method call, when a previous Init*() has already be performed on the same instance, to avoid memory leaks
- for instance:

var
  Doc: TDocVariantData; // stack-allocated variable
begin
  Doc.InitArray(['one',2,3.0]); // no need of any Doc.Clear here
  assert(Doc.Count=3);
  Doc.Clear; // to release memory before following InitObject()
  Doc.InitObject(['name','John','year',1972]);
end;

- will check the VType, and call ClearFast private method


procedure FillZero;

Fill all Values[] with #0, then delete all values
- could be used to specifically remove sensitive information from memory


procedure Init(const aOptions: TDocVariantOptions; aKind: TDocVariantKind); overload;

Initialize a TDocVariantData to store a content of some known type
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure Init(aModel: TDocVariantModel; aKind: TDocVariantKind = dvUndefined); overload;

Initialize a TDocVariantData to store some document-based content
- use the options corresponding to the supplied TDocVariantModel
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure Init(const aOptions: TDocVariantOptions = []); overload;

Initialize a TDocVariantData to store some document-based content
- can be used with a stack-allocated TDocVariantData variable:

var
  Doc: TDocVariantData; // stack-allocated variable
begin
  Doc.Init;
  Doc.AddValue('name','John');
  assert(Doc.Value['name']='John');
  assert(variant(Doc).name='John');
end;

- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitArray(const aItems: array of const; aOptions: TDocVariantOptions = []); overload;

Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied as parameters, e.g.

var
  Doc: TDocVariantData; // stack-allocated variable
begin
  Doc.InitArray(['one',2,3.0]);
  assert(Doc.Count=3);
end;

which is the same as:

 var Doc: TDocVariantData;
     i: integer;
begin
  Doc.Init;
  Doc.AddItem('one');
  Doc.AddItem(2);
  Doc.AddItem(3.0);
  assert(Doc.Count=3);
  for i := 0 to Doc.Count-1 do
    writeln(Doc.Value[i]);
end;

- this method is called e.g. by _Arr() and _ArrFast() global functions
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitArray(const aItems: array of const; aModel: TDocVariantModel); overload;

Initialize a variant instance to store some document-based array content
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitArrayFrom(const aSource: TDocVariantData; aOptions: TDocVariantOptions; aOffset: integer = 0; aLimit: integer = 0); overload;

Create a TDocVariant array, from a sub-range of this document array
- returned variant instance is a dvArray containing only the specified rows

 new.InitArrayFrom(src) returns a copy of src array
 new.InitArrayFrom(src, 10) returns items 10..Count-1 of src
 new.InitArrayFrom(src, 0, 10) returns first 0..9 items of src
 new.InitArrayFrom(src, 10, 20) returns items 10..29 - truncated if Count<30
 new.InitArrayFrom(src, -10) returns last Count-10..Count-1 items of src

procedure InitArrayFrom(const aItems: TInt64DynArray; aOptions: TDocVariantOptions; aCount: integer = -1); overload;

Initialize a variant instance to store some 64-bit integer array content


procedure InitArrayFrom(var aItems; ArrayInfo: PRttiInfo; aOptions: TDocVariantOptions; ItemsCount: PInteger = nil); overload;

Initialize a variant instance to store some dynamic array content


procedure InitArrayFrom(const aItems: TDoubleDynArray; aOptions: TDocVariantOptions; aCount: integer = -1); overload;

Initialize a variant instance to store some double array content


procedure InitArrayFrom(const aItems: TDynArray; aOptions: TDocVariantOptions = JSON_FAST_FLOAT); overload;

Initialize a variant instance to store some TDynArray content


procedure InitArrayFrom(const aItems: TRawUtf8DynArray; aOptions: TDocVariantOptions; aCount: integer = -1); overload;

Initialize a variant instance to store some RawUtf8 array content


procedure InitArrayFrom(const aItems: TIntegerDynArray; aOptions: TDocVariantOptions; aCount: integer = -1); overload;

Initialize a variant instance to store some 32-bit integer array content


procedure InitArrayFromCsv(const aCsv: RawUtf8; aOptions: TDocVariantOptions; aSeparator: AnsiChar = #0; aTrimItems: boolean = false; aAddVoidItems: boolean = false; aQuote: AnsiChar = #0);

Initialize a variant instance from some 'a,b,c' CSV one-line content
- is by default separator tolerant, i.e. will detect ',' ';' or #9 in text


procedure InitArrayFromCsvFile(const aCsv: RawUtf8; aOptions: TDocVariantOptions; aSeparator: AnsiChar = #0; aQuote: AnsiChar = #0);

Initialize a variant instance from a CSV file content with header
- stored objects names will be retrieved from the first CSV line
- is by default separator tolerant, i.e. will detect ',' ';' or #9 in text


procedure InitArrayFromObjArray(const ObjArray; aOptions: TDocVariantOptions; aWriterOptions: TTextWriterWriteObjectOptions = [woDontStoreDefault]; aCount: integer = -1);

Initialize a variant instance to store a T*ObjArray content
- will call internally ObjectToVariant() to make the conversion


procedure InitArrayFromObjectNames(const aObject: variant; aOptions: TDocVariantOptions = []; aItemsCopiedByReference: boolean = true);

Initialize a variant array instance from an object Names[]


procedure InitArrayFromObjectValues(const aObject: variant; aOptions: TDocVariantOptions = []; aItemsCopiedByReference: boolean = true);

Initialize a variant array instance from an object Values[]


procedure InitArrayFromVariants(const aItems: TVariantDynArray; aOptions: TDocVariantOptions = []; aItemsCopiedByReference: boolean = true; aCount: integer = -1);

Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied as variant dynamic array
- if Items is [], the variant will be set as null
- will be almost immediate, since TVariantDynArray is reference-counted, unless ItemsCopiedByReference is set to FALSE
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitClone(const CloneFrom: TDocVariantData);

Clone a document-based variant with the very same options but no data
- the same options will be used, without the dvArray/dvObject flags
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitCopy(const SourceDocVariant: variant; aOptions: TDocVariantOptions);

Ensure a document-based variant instance will have one unique options set
- this will create a copy of the supplied TDocVariant instance, forcing all nested events to have the same set of Options
- you can use this function to ensure that all internal properties of this variant will be copied e.g. per-reference (if you set JSON_[mDefault]) or per-value (if you set JSON_[mDefault]) whatever options the nested objects or arrays were created with
- will raise an EDocVariant if the supplied variant is not a TDocVariant
- you may rather use _Unique() or _UniqueFast() wrappers if you want to ensure that a TDocVariant instance is unique
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitFast(InitialCapacity: integer; aKind: TDocVariantKind); overload;

Initialize a TDocVariantData to store per-reference document-based content
- this overloaded method allows to specify an estimation of how many properties or items this aKind document would contain


procedure InitFast(aKind: TDocVariantKind = dvUndefined); overload;

Initialize a TDocVariantData to store per-reference document-based content
- same as Doc.Init(JSON_FAST);
- can be used with a stack-allocated TDocVariantData variable:

var
  Doc: TDocVariantData; // stack-allocated variable
begin
  Doc.InitFast;
  Doc.AddValue('name','John');
  assert(Doc.Value['name']='John');
  assert(variant(Doc).name='John');
end;

- see also TDocVariant.NewFast() if you want to initialize several TDocVariantData variable instances at once
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitFromPairs(aPairs: PUtf8Char; aOptions: TDocVariantOptions; NameValueSep: AnsiChar = '='; ItemSep: AnsiChar = #10; DoTrim: boolean = true); overload;

Initialize a variant instance to store some document-based object content from a supplied name=value list of UTF-8 encoded text (e.g. .ini file)
- previous name InitCsv() was very misleading, because it was no CSV content
- the supplied content may have been generated by ToTextPairs() method
- if ItemSep=#10, then any kind of line feed (CRLF or LF) will be handled
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitFromPairs(const aPairs: RawUtf8; aOptions: TDocVariantOptions; NameValueSep: AnsiChar = '='; ItemSep: AnsiChar = #10; DoTrim: boolean = true); overload;

Initialize a variant instance to store some document-based object content from a supplied name=value list of UTF-8 encoded text (e.g. .ini file)
- previous name InitCsv() was very misleading, because it was no CSV content
- the supplied content may have been generated by ToTextPairs() method
- if ItemSep = #10, then any kind of line feed (CRLF or LF) will be handled
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitObject(const NameValuePairs: array of const; Model: TDocVariantModel); overload;

Initialize a TDocVariantData to store document-based object content
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitObject(const NameValuePairs: array of const; aOptions: TDocVariantOptions = []); overload;

Initialize a TDocVariantData to store document-based object content
- object will be initialized with data supplied two by two, as Name,Value pairs, e.g.

var
  Doc: TDocVariantData; // stack-allocated variable
begin
  Doc.InitObject(['name','John','year',1972]);

which is the same as:

 var Doc: TDocVariantData;
begin
  Doc.Init;
  Doc.AddValue('name','John');
  Doc.AddValue('year',1972);

- this method is called e.g. by _Obj() and _ObjFast() global functions
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitObjectFromPath(const aPath: RawUtf8; const aValue: variant; aOptions: TDocVariantOptions = []; aPathDelim: AnsiChar = '.');

Initialize a variant instance to store a document-based object with a single property
- the supplied path could be 'Main.Second.Third', to create nested objects, e.g. {"Main":{"Second":{"Third":value}}}
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure InitObjectFromVariants(const aNames: TRawUtf8DynArray; const aValues: TVariantDynArray; aOptions: TDocVariantOptions = []);

Initialize a variant instance to store some document-based object content
- object will be initialized with names and values supplied as dynamic arrays
- if aNames and aValues are [] or do have matching sizes, the variant will be set as null
- will be almost immediate, since Names and Values are reference-counted
- if you call Init*() methods in a row, ensure you call Clear in-between


procedure Reduce(const aPropNames: array of RawUtf8; aCaseSensitive: boolean; var result: TDocVariantData; aDoNotAddVoidProp: boolean = false); overload;

Create a TDocVariant object, from a selection of properties of the objects of this document array, by property name
- if the document is a dvObject, to reduction will be applied to all its properties
- if the document is a dvArray, the reduction will be applied to each stored item, if it is a document


procedure ReduceAsArray(const aPropName: RawUtf8; var result: TDocVariantData; const OnReduce: TOnReducePerItem = nil); overload;

Create a TDocVariant array, from the values of a single property of the objects of this document array, specified by name
- you can optionally apply an additional filter to each reduced item


procedure ReduceAsArray(const aPropName: RawUtf8; var result: TDocVariantData; const OnReduce: TOnReducePerValue); overload;

Create a TDocVariant array, from the values of a single property of the objects of this document array, specified by name
- this overloaded method accepts an additional filter to each reduced item


procedure ReduceFilter(const aKey: RawUtf8; const aValue: variant; aMatch: TCompareOperator; aCompare: TVariantCompare; aLimit: integer; aPathDelim: AnsiChar; var result: TDocVariantData); overload;

Create a TDocVariant array, matching a filtering set of raw parameters


procedure ReduceFilter(const aExpression: RawUtf8; var result: TDocVariantData; aLimit: integer = 0; aCompare: TVariantCompare = nil; aPathDelim: AnsiChar = #0); overload;

Create a TDocVariant array, matching a filtering expression
- expressions are e.g. 'name=Synopse' or 'price<100'


procedure ReduceFilter(const aExpression: RawUtf8; const aValue: variant; var result: TDocVariantData; aCompare: TVariantCompare = nil; aLimit: integer = 0; aPathDelim: AnsiChar = #0); overload;

Create a TDocVariant array, matching a filtering expression
- e.g. ReduceFilter('name=','Synopse') or ReduceFilter('price<',MaxPrice)


procedure Reset;

Delete all internal stored values
- like Clear + Init() with the same options
- will reset Kind to dvUndefined


procedure RetrieveNameOrRaiseException(Index: integer; var Dest: RawUtf8);

Retrieve an item in this document from its index, and returns its Name
- raise an EDocVariant if the supplied Index is not in the 0..Count-1 range and dvoReturnNullForUnknownProperty is set in Options


procedure RetrieveValueOrRaiseException(Index: integer; var Dest: variant; DestByRef: boolean); overload;

Retrieve an item in this document from its index, and returns its value
- raise an EDocVariant if the supplied Index is not in the 0..Count-1 range and dvoReturnNullForUnknownProperty is set in Options
- create a copy of the variant by default, unless DestByRef is TRUE


procedure Reverse;

Inverse the order of Names and Values of this document
- could be applied after a content sort if needed


procedure SaveToJsonFile(const FileName: TFileName);

Save a document as UTF-8 encoded JSON file
- you may then use InitJsonFromFile() to load and parse this file


procedure SetCount(aCount: integer);

Low-level method to force a number of items
- could be used to fast add items to the internal Values[]/Names[] arrays
- just set protected VCount field, do not resize the arrays: caller should ensure that Capacity is big enough and to call Void if aCount=0


procedure SetValueOrRaiseException(Index: integer; const NewValue: variant);

Set an item in this document from its index
- raise an EDocVariant if the supplied Index is not in 0..Count-1 range


procedure SortArrayByField(const aItemPropName: RawUtf8; aValueCompare: TVariantCompare = nil; aValueCompareReverse: boolean = false; aNameSortedCompare: TUtf8Compare = nil);

Sort the document array values by a field of some stored objet values
- do nothing if the document is not a dvArray, or if the items are no dvObject
- aValueCompare will be called with the aItemPropName values, not row
- will sort by UTF-8 text (VariantCompare) if no custom aValueCompare is supplied
- this method is faster than SortByValue/SortByRow


procedure SortArrayByFields(const aItemPropNames: array of RawUtf8; aValueCompare: TVariantCompare = nil; const aValueCompareField: TVariantCompareField = nil; aValueCompareReverse: boolean = false; aNameSortedCompare: TUtf8Compare = nil);

Sort the document array values by field(s) of some stored objet values
- allow up to 4 fields (aItemPropNames[0]..aItemPropNames[3])
- do nothing if the document is not a dvArray, or if the items are no dvObject
- will sort by UTF-8 text (VariantCompare) if no aValueCompareField is supplied


procedure SortByName(SortCompare: TUtf8Compare = nil; SortCompareReversed: boolean = false; SortNested: boolean = false);

Sort the document object values by name
- do nothing if the document is not a dvObject
- will follow case-insensitive order (@StrIComp) by default, but you can specify @StrComp as comparer function for case-sensitive ordering
- once sorted, you can use GetVarData(..,Compare) or GetAs*(..,Compare) methods for much faster O(log(n)) binary search


procedure SortByRow(const SortComparer: TVariantComparer; SortComparerReversed: boolean = false);

Sort the document object values by value using a comparison method
- work for both dvObject and dvArray documents
- you should supply a TVariantComparer callback method


procedure SortByValue(SortCompare: TVariantCompare = nil; SortCompareReversed: boolean = false);

Sort the document object values by value using a comparison function
- work for both dvObject and dvArray documents
- will sort by UTF-8 text (VariantCompare) if no custom aCompare is supplied


procedure ToArrayOfConst(out Result: TTVarRecDynArray); overload;

Save an array document as an array of TVarRec, i.e. an array of const
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- values will be passed by referenced as vtVariant to @VValue[ndx]
- would allow to write code as such:

  Doc.InitArray(['one',2,3]);
  Doc.ToArrayOfConst(vr);
  s := FormatUtf8('[%,%,%]',vr,[],true);
  // here s='[one,2,3]') since % would be replaced by Args[] parameters
  s := FormatUtf8('[?,?,?]',[],vr,true);
  // here s='["one",2,3]') since ? would be escaped by Params[] parameters

procedure ToRawUtf8DynArray(out Result: TRawUtf8DynArray); overload;

Save a document as an array of UTF-8 encoded JSON
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- will use VariantToUtf8() to populate the result array: as a consequence, any nested custom variant types (e.g. TDocVariant) will be stored as JSON


procedure ToTextPairsVar(out result: RawUtf8; const NameValueSep: RawUtf8 = '='; const ItemSep: RawUtf8 = #13#10; Escape: TTextWriterKind = twJsonEscape);

Save a document as UTF-8 encoded Name=Value pairs
- will follow by default the .INI format, but you can specify your own expected layout


procedure Update(const NameValuePairs: array of const);

Merge some properties to a TDocVariantData dvObject
- data is supplied two by two, as Name,Value pairs
- caller should ensure that Kind=dvObject, otherwise it won't do anything
- any existing Name would be updated with the new Value


procedure Void;

Keep the current Options and Kind, but reset all data and VCount to 0


property A[const aName: RawUtf8]: PDocVariantData read GetArrayExistingByName;

Direct access to a dvObject existing dvArray property from its name
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- A['prop'] would return a fake void TDocVariant if the property is not existing or not a dvArray, just like GetAsDocVariantSafe()
- use A_['prop'] to force adding any missing property


property A_[const aName: RawUtf8]: PDocVariantData read GetArrayOrAddByName;

Direct access or add a dvObject's dvArray property from its name
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- A_['prop'] would add a new property if there is none existing, or overwrite an existing property which is not a dvArray
- the new property array would inherit from the Options of this instance


property B[const aName: RawUtf8]: boolean read GetBooleanByName write SetBooleanByName;

Direct access to a dvObject boolean stored property value from its name
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsBoolean if you want to check the availability of the field
- B['prop'] := true would add a new property, or overwrite an existing


property Capacity: integer read GetCapacity write SetCapacity;

The current capacity of this document
- allow direct access to VValue[] length


property Count: integer read VCount;

Number of items stored in this document
- always 0 for Kind=dvUndefined
- the number of name/value pairs for Kind=dvObject (may be 0 if void)
- the number of items for Kind=dvArray (may be 0 if void)


property D[const aName: RawUtf8]: Double read GetDoubleByName write SetDoubleByName;

Direct access to a dvObject floating-point stored property value from its name
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsDouble if you want to check the availability of the field
- D['prop'] := 1.23 would add a new property, or overwrite an existing


property I[const aName: RawUtf8]: Int64 read GetInt64ByName write SetInt64ByName;

Direct access to a dvObject integer stored property value from its name
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsInt/GetAsInt64 if you want to check the availability of the field
- I['prop'] := 123 would add a new property, or overwrite an existing


property Kind: TDocVariantKind read GetKind;

Returns the document internal layout
- just after initialization, it will return dvUndefined
- most of the time, you will add named values with AddValue() or by setting the variant properties: it will return dvObject
- but is you use AddItem(), values will have no associated names: the document will be a dvArray
- is computed from the dvoArray or dvoObject flags presence in Options


property Names: TRawUtf8DynArray read VName;

Direct acces to the low-level internal array of names
- is void (nil) if Kind is not dvObject
- note that length(Names)=Capacity and not Count, so copy(Names, 0, Count) or use FieldNames iterator or GetNames if you want the exact count
- transtyping a variant and direct access to TDocVariantData is the fastest way of accessing all properties of a given dvObject:

 with _Safe(aVariantObject)^ do
   for i := 0 to Count-1 do
     writeln(Names[i],'=',Values[i]);

property O[const aName: RawUtf8]: PDocVariantData read GetObjectExistingByName;

Direct access to a dvObject existing dvObject property from its name
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- O['prop'] would return a fake void TDocVariant if the property is not existing or not a dvObject, just like GetAsDocVariantSafe()
- use O_['prop'] to force adding any missing property


property Options: TDocVariantOptions read VOptions write SetOptions;

How this document will behave
- those options are set when creating the instance
- dvoArray and dvoObject are not options, but define the document Kind, so those items are ignored when assigned to this property


property O_[const aName: RawUtf8]: PDocVariantData read GetObjectOrAddByName;

Direct access or add a dvObject's dvObject property from its name
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- O_['prop'] would add a new property if there is none existing, or overwrite an existing property which is not a dvObject
- the new property object would inherit from the Options of this instance


property P[const aNameOrPath: RawUtf8]: Variant read GetVariantByPath;

Direct access to a dvObject value stored property value from its path name
- default Value[] will check only names in the current object properties, whereas this property will recognize e.g. 'parent.child' nested objects
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options


property S[const aName: RawUtf8]: string read GetStringByName write SetStringByName;

Direct string access to a dvObject UTF-8 stored property value from its name
- just a wrapper around U[] property, to avoid a compilation warning when using plain string variables (internally, RawUtf8 will be used for storage)
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsRawUtf8() if you want to check the availability of the field
- S['prop'] := 'value' would add a new property, or overwrite an existing


property U[const aName: RawUtf8]: RawUtf8 read GetRawUtf8ByName write SetRawUtf8ByName;

Direct access to a dvObject UTF-8 stored property value from its name
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsRawUtf8() if you want to check the availability of the field
- U['prop'] := 'value' would add a new property, or overwrite an existing


property Value[const aNameOrIndex: Variant]: Variant read GetValueOrItem write SetValueOrItem;

Find an item in this document, and returns its value
- raise an EDocVariant if aNameOrIndex is neither an integer nor a string
- raise an EDocVariant if Kind is dvArray and aNameOrIndex is a string or if Kind is dvObject and aNameOrIndex is an integer
- raise an EDocVariant if Kind is dvObject and if aNameOrIndex is a string, which is not found within the object property names and dvoReturnNullForUnknownProperty is set in Options
- raise an EDocVariant if Kind is dvArray and if aNameOrIndex is a integer, which is not within 0..Count-1 and dvoReturnNullForUnknownProperty is set in Options
- so you can use directly:

 // for an array document:
 aVariant := TDocVariant.NewArray(['one',2,3.0]);
 for i := 0 to TDocVariantData(aVariant).Count-1 do
   aValue := TDocVariantData(aVariant).Value[i];
 // for an object document:
 aVariant := TDocVariant.NewObject(['name','John','year',1972]);
 assert(aVariant.Name=TDocVariantData(aVariant)['name']);
 assert(aVariant.year=TDocVariantData(aVariant)['year']);

- due to the internal implementation of variant execution (somewhat slow _DispInvoke() function), it is a bit faster to execute:

 aValue := TDocVariantData(aVariant).Value['name'];

or

 aValue := _Safe(aVariant).Value['name'];

instead of

 aValue := aVariant.name;

but of course, if want to want to access the content by index (typically for a dvArray), using Values[] - and Names[] - properties is much faster than this variant-indexed pseudo-property:

 with TDocVariantData(aVariant) do
   for i := 0 to Count-1 do
     Writeln(Values[i]);

is faster than:

 with TDocVariantData(aVariant) do
   for i := 0 to Count-1 do
     Writeln(Value[i]);

which is faster than:

 for i := 0 to aVariant.Count-1 do
   Writeln(aVariant._(i));

- this property will return the value as varByRef (just like with variant late binding of any TDocVariant instance), so you can write:

var
  Doc: TDocVariantData; // stack-allocated variable
begin
  Doc.InitJson('{arr:[1,2]}');
  assert(Doc.Count=2);
  Doc.Value['arr'].Add(3);  // works since Doc.Value['arr'] is varByRef
  writeln(Doc.ToJson);      // will write '{"arr":[1,2,3]}'
end;

- if you want to access a property as a copy, i.e. to assign it to a variant variable which will stay alive after this TDocVariant instance is release, you should not use Value[] but rather GetValueOrRaiseException or GetValueOrNull/GetValueOrEmpty
- see U[] I[] B[] D[] O[] O_[] A[] A_[] _[] properties for direct access of strong typed values, or P[] to retrieve a variant from its path


property Values: TVariantDynArray read VValue;

Direct acces to the low-level internal array of values
- note that length(Values)=Capacity and not Count, so copy(Values, 0, Count) or use FieldValues iterator if you want the exact count
- transtyping a variant and direct access to TDocVariantData is the fastest way of accessing all properties of a given dvObject:

 with _Safe(aVariantObject)^ do
   for i := 0 to Count-1 do
     writeln(Names[i],'=',Values[i]);

- or to access a dvArray items (e.g. a MongoDB collection):

 with TDocVariantData(aVariantArray) do
   for i := 0 to Count-1 do
     writeln(Values[i]);

property VarType: word read VType;

Return the custom variant type identifier, i.e. DocVariantType.VarType


property _[aIndex: integer]: PDocVariantData read GetAsDocVariantByIndex;

Direct access to a dvArray's TDocVariant property from its index
- simple values may directly use Values[] dynamic array, but to access a TDocVariantData members, this property is safer
- follows dvoReturnNullForUnknownProperty option to raise an exception
- _[ndx] would return a fake void TDocVariant if aIndex is out of range, if the property is not existing or not a TDocVariantData (just like GetAsDocVariantSafe)


1.3.6. IDocAny

IDocAny = interface(ISerializable)

Abstract parent with common methods to IDocList/IDocDict wrappers


function AsDict: IDocDict;

Returns itself as a IDocDic, or nil if is a IDocList


function AsList: IDocList;

Returns itself as a IDocList, or nil if is a IDocDict


function AsVariant: variant;

Returns the associated TDocVariant instance


function Kind: TDocVariantKind;

Equals dvArray for IDocList, dvObject for IDocDict


function Len: integer;

How many items or name/value pairs are stored in this instance


function Model: TDocVariantModel;

The known model of the internal TDocVariantData storage


function Value: PDocVariantData;

Low-level access to the internal TDocVariantData storage
- warning: is a weak reference pointer to the main IDocList/IDocDict, so you need to copy it to use it outside of this instance


procedure Clear;

Remove all elements from the list/dictionary


1.3.7. EDocList

EDocList = class(EDocVariant)

Exception raised by IDocList


1.3.8. EDocDict

EDocDict = class(EDocVariant)

Exception raised by IDocDict


1.3.9. IDocList

IDocList = interface(IDocAny)

A List, used to store multiple values
- implemented via an internal TDocVariantData dvArray
- follows most Python Lists naming and conventions


function Append(const value: RawUtf8): integer; overload;

Adds an UTF-8 text element at the end of the list


function Append(const value: variant): integer; overload;

Adds an element at the end of the list


function AppendDoc(const value: IDocAny): integer;

Adds an IDocList/IDocDict element at the end of the list


function Compare(const another: IDocList; caseinsensitive: boolean = false): integer;

Compare this IDocList value with another instance
- each element of the list will be compared, in their expected order


function Copy(start: integer = 0; stop: integer = 0): IDocList;

Return a of a (sub-range) copy of this IDocList
- consider Range() if you want just to loop over some sub-range, and do not need to allocate a new IDocList instance
- returns a new IDocList instance as Python list[start:stop] range, stop position being *excluded* to the result:

 list.Copy returns a copy of the whole list
 list.Copy(10) returns elements #10..#Count-1, i.e. list[10:]
 list.Copy(-2) returns last #Count-2..#Count-1 items, i.e. list[-2:]
 list.Copy(1, 9) returns elements #1..#8, i.e. list[1..9]
 list.Copy(1, -2) returns elements #1..#Count-3, i.e. list[1:-2]

function Count(const value: RawUtf8): integer; overload;

Counts the number of elements with the specified value


function Count(const value: variant): integer; overload;

Counts the number of elements with the specified value


function Del(position: integer): boolean;

Removes the element at the specified position, not returning it


function Exists(const value: RawUtf8; caseinsensitive: boolean = false): boolean; overload;

Check if a specified text value is present in the list


function Exists(const value: variant): boolean; overload;

Check if a specified value is present in the list


function Filter(const expression: RawUtf8; pathdelim: AnsiChar = '.'): IDocList; overload;

Search matching expression over IDocDict kind of elements in this list
- expressions are e.g. 'name=Synopse' or 'info.price<100'


function Filter(const expression: RawUtf8; const value: variant; limit: integer = 0; pathdelim: AnsiChar = '.'): IDocList; overload;

Search matching expression over IDocDict kind of elements in this list
- use e.g. Filter('name=', 'Synopse') or Filter('info.price<', MaxPrice)


function Filter(const key: RawUtf8; const value: variant; limit: integer; match: TCompareOperator; compare: TVariantCompare; pathdelim: AnsiChar = '.'): IDocList; overload;

Search matching key/value over IDocDict kind of elements in this list
- raw search for compare(object.key,value)=match
- default compare=nil will use VariantCompare


function First(const expression: RawUtf8; const value: variant): variant; overload;

Search the first matching expression over IDocDict kind of elements


function First(const expression: RawUtf8): variant; overload;

Search the first matching expression over IDocDict kind of elements


function GetB(position: integer): boolean;

Methods used as getter/setter for properties


function Index(const value: variant): integer; overload;

Returns the position at the first occurrence of the specified value


function Index(const value: RawUtf8; caseinsensitive: boolean = false): integer; overload;

Returns the position at the first occurrence of the specified text value


function Insert(position: integer; const value: RawUtf8): integer; overload;

Inserts the specified value at the specified position


function Insert(position: integer; const value: variant): integer; overload;

Inserts the specified value at the specified position


function ObjectsDictDynArray: IDocDictDynArray;

Returns all IDocDict kind of elements of this IDocList
- the list should consist e.g. of a JSON array of JSON objects
- will just ignore any element of the IDocList which is not a IDocDict


function Pop(position: integer = -1): variant;

Removes the element at the specified position, and returns it
- raise an EDocList on invalid supplied position


function PopItem(out value: IDocDict; position: integer = -1): boolean; overload;

Removes the last inserted IDocDict, with no out-of-range error raised
- you may change the extraction position (negatives from Len)
- returns false if there is no value at this position, or it is no IDocDict


function PopItem(out value: variant; position: integer = -1): boolean; overload;

Removes the last inserted element into a value-owned IDocDict
- returns false if there is no value at this position (raise no EDocList)
- you may change the extraction position (negatives from Len)


function Reduce(const keys: array of RawUtf8): IDocList;

Extract a list of IDocDict elements which contains only specified keys
- could be used to filter a list of objects into a smaller dataset


function Remove(const value: variant): integer; overload;

Removes the first occurrence of the element with the specified value


function Remove(const value: RawUtf8; caseinsensitive: boolean = false): integer; overload;

Removes the first occurrence of the element with the specified value


function ValueAt(position: integer): PVariant;

Low-level direct access to a stored element in TDocVariantData.Value[]


procedure Extend(const value: IDocList); overload;

Add the elements of a list, to the end of the current list


procedure Extend(const value: array of const); overload;

Add the supplied elements, to the end of the current list


procedure Reverse;

Reverses the sorting order of the elements


procedure Sort(reverse: boolean = false; compare: TVariantCompare = nil);

Sorts the list ascending by default


procedure SortByKeyValue(const keys: array of RawUtf8; reverse: boolean = false; valuecompare: TVariantCompare = nil); overload;

Sorts the IDocDict objects in the list by several key names


procedure SortByKeyValue(const key: RawUtf8; reverse: boolean = false; valuecompare: TVariantCompare = nil); overload;

Sorts the IDocDict objects in the list by a given key name


property A[position: integer]: IDocList read GetL write SetL;

Access one element in the list, as IDocList/IDocArray
- property alias, for compatibility with existing code
- warning: weak reference to the main list, unless you explicitly Copy it


property B[position: integer]: boolean read GetB write SetB;

Access one element in the list, as boolean


property C[position: integer]: currency read GetC write SetC;

Access one element in the list, as fixed precision Currency


property D[position: integer]: IDocDict read GetD write SetD;

Access one element in the list, as IDocDict (Dictionary)
- warning: weak reference to the main list, unless you explicitly Copy it


property F[position: integer]: double read GetF write SetF;

Access one element in the list, as floating-point Double


property I[position: integer]: Int64 read GetI write SetI;

Access one element in the list, as Integer


property Item[position: integer]: variant read GetItem write SetItem;

Access one element in the list, as variant
- this is the default property of this instance so list[n] gives direct access to the element at index 0 <= n < len -1 in the IDocList
- negative positions are retrieved from the end, e.g. list[-1] maps the last element of the list
- raise an EDocList exception on out-of-range position
- U[] S[] I[] F[] C[] B[] L[] D[] are faster and safer if you expect to retrieve a specific value type


property L[position: integer]: IDocList read GetL write SetL;

Access one element in the list, as IDocList (List)
- warning: weak reference to the main list, unless you explicitly Copy it


property O[position: integer]: IDocDict read GetD write SetD;

Access one element in the list, as IDocDict/IDocObject
- property alias, for compatibility with existing code
- warning: weak reference to the main list, unless you explicitly Copy it


property S[position: integer]: string read GetS write SetS;

Access one element in the list, as RTL String text


property U[position: integer]: RawUtf8 read GetU write SetU;

Access one element in the list, as UTF-8 text


1.3.10. IDocDict

IDocDict = interface(IDocAny)

A Dictionary, used to store key:value pairs
- implemented via an internal TDocVariantData dvObject
- follows most Python Dictionaries naming and conventions
- keys are by default searched on the ground object, but you can set PathDelim e.g. to '.' to enable sub-object location (and insertion)


function Compare(const another: IDocDict; const keys: array of RawUtf8; caseinsensitive: boolean = false): integer; overload;

Compare the specified keys of this IDocDict value with another instance


function Compare(const another: IDocDict; caseinsensitive: boolean = false): integer; overload;

Compare this IDocDict value with another instance
- each key/value pair will be compared, in their expected order


function Copy: IDocDict;

Returns a copy of the specified dictionary


function Del(const key: RawUtf8): boolean;

Removes the element at the specified key, not returning it


function Exists(const key: RawUtf8): boolean;

Check if the specified key exists in the dictionary


function Get(const key: RawUtf8; var value: string): boolean; overload;

Access one element in the dictionary, as RTL string text
- if the key does not exist, returns false


function Get(const key: RawUtf8; var value: boolean): boolean; overload;

Access one element in the dictionary, as boolean
- if the key does not exist or is not an integer, returns false


function Get(const key: RawUtf8; var value: integer): boolean; overload;

Access one element in the dictionary, as 32-bit integer
- if the key does not exist or is not an integer, returns false


function Get(const key: RawUtf8): variant; overload;

Access one element in the dictionary, as variant
- if the key does not exist, returns varEmpty and raise no exception


function Get(const key: RawUtf8; var value: variant): boolean; overload;

Access one element in the dictionary, as variant
- if the key does not exist, returns false


function Get(const key: RawUtf8; var value: RawUtf8): boolean; overload;

Access one element in the dictionary, as UTF-8 text
- if the key does not exist, returns false


function Get(const key: RawUtf8; var value: IDocList): boolean; overload;

Access one element in the dictionary, as by-reference IDocList
- if the key does not exist or is not a IDocList, returns false


function Get(const key: RawUtf8; var value: IDocDict): boolean; overload;

Access one element in the dictionary, as a by-reference IDocDict
- if the key does not exist or is not a IDocDict, returns false


function Get(const key: RawUtf8; var value: PDocVariantData): boolean; overload;

Access one element in the dictionary, as by-reference TDocVariantData
- if the key does not exist or is not a IDocList, returns false


function Get(const key: RawUtf8; var value: Int64): boolean; overload;

Access one element in the dictionary, as 64-bit integer
- if the key does not exist or is not an integer, returns false


function Get(const key: RawUtf8; var value: double): boolean; overload;

Access one element in the dictionary, as floating-point double
- if the key does not exist or can not be converted, returns false


function Get(const key: RawUtf8; var value: currency): boolean; overload;

Access one element in the dictionary, fixed precision currency
- if the key does not exist or can not be converted, returns false


function GetB(const key: RawUtf8): boolean;

Methods used as getter/setter for properties


function GetDef(const key: RawUtf8; const default: RawUtf8): variant; overload;

Access one element in the dictionary, as variant
- if the key does not exist, returns the supplied default value


function GetDef(const key: RawUtf8; const default: variant): variant; overload;

Access one element in the dictionary, as variant
- if the key does not exist, returns the supplied default value


function Pop(const key: RawUtf8): variant; overload;

Removes the specified element from the dictionary
- if the key does not exist, raise a EDocDict exception


function Pop(const key: RawUtf8; const default: variant): variant; overload;

Removes the specified element from the dictionary
- if the key does not exist, returns the supplied default value


function PopItem(out key: RawUtf8; out value: variant; position: integer = -1): boolean;

Removes the last inserted key-value pair into the dictionary
- returns false if the dictionary is empty
- you may change the extraction position (negatives from Len)


function Reduce(const keys: array of RawUtf8): IDocDict;

Extract into a new IDocDict which contains only specified keys
- could be used to filter unneeded fields in an object


function SetDefault(const key: RawUtf8; const default: variant): variant; overload;

Returns the value of the specified key, or insert the specified value


function SetDefault(const key: RawUtf8): variant; overload;

Returns the value of the specified key, or insert null for this key


function ValueAt(const key: RawUtf8): PVariant;

Low-level direct access to a stored element in TDocVariantData.Value[]


procedure Sort(reverse: boolean = false; keycompare: TUtf8Compare = nil; nestedDict: boolean = false);

Sorts the dictionary content by their key names
- follow dvoNameCaseSensitive option by default, or supplied keycompare
- can optionnaly sort the nested dictionaries of the dictionary
- once sorted, key lookup will use O(log(n)) - faster than default O(n)


procedure Update(const source: IDocDict; addonlymissing: boolean = false); overload;

Updates (or inserts) the specified key/value pairs of another IDocDict


procedure Update(const key: RawUtf8; const value: variant); overload;

Updates (or inserts) the specified key/value pair


procedure Update(const keyvalues: array of const); overload;

Updates (or inserts) the specified key/value pairs


property A[const key: RawUtf8]: IDocList read GetL write SetL;

Access one element in the dictionary from its key, as IDocList/IDocArray
- property alias, for compatibility with existing code


property B[const key: RawUtf8]: boolean read GetB write SetB;

Access one element in the dictionary from its key, as boolean


property C[const key: RawUtf8]: currency read GetC write SetC;

Access one element in the dictionary from its key, as fixed precision currency


property D[const key: RawUtf8]: IDocDict read GetD write SetD;

Access one element in the dictionary from its key, as IDocDict


property F[const key: RawUtf8]: double read GetF write SetF;

Access one element in the dictionary from its key, as floating-point double


property I[const key: RawUtf8]: Int64 read GetI write SetI;

Access one element in the dictionary from its key, as integer


property Item[const key: RawUtf8]: variant read GetItem write SetItem;

Access one element in the dictionary from its key, as variant
- this is the default property of this instance so dict[name] gives direct access to each value in the IDocDict
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- see Get() overloaded methods to silently check for a key existence
- PathDelim can be set to locate (and create) the key by its full path
- U[] S[] I[] F[] C[] B[] L[] D[] are faster and safer if you expect to retrieve a specific value type


property L[const key: RawUtf8]: IDocList read GetL write SetL;

Access one element in the dictionary from its key, as IDocList


property O[const key: RawUtf8]: IDocDict read GetD write SetD;

Access one element in the dictionary from its key, as IDocDict/IDocObject
- property alias, for compatibility with existing code


property PathDelim: AnsiChar read GetPathDelim write SetPathDelim;

Enable nested objects location in keys for Get() and Item[]
- equals #0 by default, meaning only root object keys are located, e.g. dict.D['child2']
- if PathDelim is e.g. set to '.', then dict.U['child2.name'] matches dict.D['child2'].U['name']
- note that if the sub object does not exist, setting a value will force its creation (and all needed hierarchy)


property S[const key: RawUtf8]: string read GetS write SetS;

Access one element in the dictionary from its key, as RTL string text


property U[const key: RawUtf8]: RawUtf8 read GetU write SetU;

Access one element in the dictionary from its key, as UTF-8 text


1.4. Types implemented in the mormot.core.variants unit

1.4.1. IDocArray

IDocArray = IDocList;

Alias to our interface list type, for compatibility with existing code


1.4.2. IDocDictDynArray

IDocDictDynArray = array of IDocDict;

A dynamic array of IDocDict instances


1.4.3. IDocObject

IDocObject = IDocDict;

Alias to our interface dictionary type, for compatibility with existing code


1.4.4. PDocVariantData

PDocVariantData = ^TDocVariantData;

Pointer to a TDocVariant storage
- since variants may be stored by reference (i.e. as varByRef), it may be a good idea to use such a pointer via DocVariantData(aVariant)^ or _Safe(aVariant)^ instead of TDocVariantData(aVariant), if you are not sure how aVariant was allocated (may be not _Obj/_Json)
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData


1.4.5. PDocVariantDataDynArray

PDocVariantDataDynArray = array of PDocVariantData;

Pointer to a dynamic array of TDocVariant storage


1.4.6. TDocVariantKind

TDocVariantKind = ( dvUndefined, dvArray, dvObject );

Define the TDocVariant storage layout
- if it has no name property, it is a dvArray
- if it has one or more named properties, it is a dvObject


1.4.7. TDocVariantModel

TDocVariantModel = ( mVoid, mDefault, mFast, mFastFloat, mFastStrict, mFastExtended, mFastExtendedIntern, mNameValue, mNameValueExtended, mNameValueIntern, mNameValueInternExtended );

JSON_[] constant convenient TDocVariant options
- mVoid defines a safe (and slow) full-copy behavior with [] (no option)
- mDefault defines a safe (and slow) full-copy behavior, returning null for unknown fields, as defined e.g. by _Json() and _JsonFmt() functions or JSON_OPTIONS[false]
- mFast will copy-by-reference any TDocVariantData content, as defined e.g. by _JsonFast() and _JsonFastFmt() functions or JSON_OPTIONS[true]
- mFastFloat will copy-by-reference and can parse floating points as double
- mFastStrict will copy-by-reference and only parse strict (quoted) JSON, as defined by JSON_FAST_STRICT global variable
- mFastExtended will copy-by-reference and write extended (unquoted) JSON, as defined by JSON_FAST_EXTENDED global variable
- mFastExtendedIntern will copy-by-reference, write extended JSON and intern names and values, as defined by JSON_FAST_EXTENDEDINTERN variable
- mNameValue will copy-by-reference and check field names case-sensitively, as defined by JSON_NAMEVALUE[false] global variable
- mNameValueExtended will copy-by-reference, check field names case-sensitively and write extended (unquoted) JSON, as defined by JSON_NAMEVALUE[true] global variable
- mNameValueIntern will copy-by-reference, check field names case-sensitively and intern names and values, as defined by JSON_NAMEVALUEINTERN[false] global variable
- mNameValueInternExtended will copy-by-reference, check field names case-sensitively, write extended JSON and intern names and values, as defined by JSON_NAMEVALUEINTERN[true] global variable


1.4.8. TOnReducePerItem

TOnReducePerItem = function(Item: PDocVariantData): boolean of object;

Method used by TDocVariantData.ReduceAsArray to filter each object
- should return TRUE if the item match the expectations


1.4.9. TOnReducePerValue

TOnReducePerValue = function(const Value: variant): boolean of object;

Method used by TDocVariantData.ReduceAsArray to filter each object
- should return TRUE if the item match the expectations


1.4.10. TSearchDuplicate

TSearchDuplicate = ( sdNone, sdCaseSensitive, sdCaseInsensitive );

How duplicated values could be searched


1.4.11. TSynInvokeableVariantTypeClass

TSynInvokeableVariantTypeClass = class of TSynInvokeableVariantType;

Class-reference type (metaclass) of custom variant type definition
- used by SynRegisterCustomVariantType() function


1.4.12. TSynInvokeableVariantTypeOptions

TSynInvokeableVariantTypeOptions = set of ( sioHasTryJsonToVariant, sioHasToJson, sioCanIterate);

Define how our custom variant types behave, i.e. its methods featureset


1.4.13. TVarDataTypes

TVarDataTypes = set of 0..31;

A set of simple TVarData.VType values, as specified to VarIs()


1.4.14. TVariantCompare

TVariantCompare = function(const V1, V2: variant): PtrInt;

Function prototype used internally for variant comparison
- as used e.g. by TDocVariantData.SortByValue


1.4.15. TVariantCompareField

TVariantCompareField = function(const FieldName: RawUtf8; const V1, V2: variant): PtrInt of object;

Function prototype used internally for extended variant comparison
- as used by TDocVariantData.SortArrayByFields


1.4.16. TVariantComparer

TVariantComparer = function(const V1, V2: variant): PtrInt of object;

Function prototype used internally for extended variant comparison
- as used by TDocVariantData.SortByRow


1.5. Constants implemented in the mormot.core.variants unit

1.5.1. DocVariantDataFake

DocVariantDataFake: TDocVariantData = ( VType: varNull; VOptions: [dvoReturnNullForUnknownProperty]);

Constant used e.g. by _Safe() and _DV() overloaded functions
- will be in code section of the exe, so will be read-only by design
- would have Kind=dvUndefined and Count=0, so _Safe() would return a valid, but void document
- its VType is varNull, so would be viewed as a null variant
- dvoReturnNullForUnknownProperty is defined, so that U[]/I[]... methods won't raise any exception about unexpected field name


1.5.2. JSON_FAST

JSON_FAST = [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference];

MVoid mDefault mFast mFastFloat mFastStrict mFastExtended mFastExtendedIntern mNameValue mNameValueExtended mNameValueIntern mNameValueInternExtended same as JSON_[mFast], but can not be used as PDocVariantOptions
- handle only currency for floating point values: use JSON_FAST_FLOAT if you want to support double values, with potential precision loss


1.5.3. JSON_FAST_FLOAT

JSON_FAST_FLOAT = [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoAllowDoubleValue];

Same as JSON_FAST, but including dvoAllowDoubleValue for floating point values parsing into double, with potential precision loss


1.6. Functions or procedures implemented in the mormot.core.variants unit

Functions or proceduresDescription
CustomVariantToJsonTry to serialize a custom variant value into JSON
DocDictCreate a IDocDict as weak reference to a TDocVariantData dvObject
DocDictCreate a self-owned IDocDict from a set of key,value pairs
DocDictCreate a self-owned IDocDict from a JSON object
DocDictCreate a self-owned void IDocDict
DocDictCopyCreate a self-owned IDocDict as full copy of a TDocVariant dvObject
DocDictCopyCreate a self-owned IDocDict as full copy of a TDocVariantData dvObject
DocDictCopyCreate a self-owned IDocDict as full copy of a TDocVariantData dvObject and a specific options model
DocDictDynArrayCreate an array of self-owned IDocDict from a JSON array of JSON objects
DocDictFromCreate a IDocDict as weak reference to a TDocVariant dvObject
DocDictFromKeysCreate a self-owned IDocDict from a set of keys and a gien value
DocDictFromKeysCreate a self-owned IDocDict from a set of keys - values will be Null
DocListCreate a IDocList as weak reference to a TDocVariantData dvArray
DocListCreate a self-owned IDocList from a set of values
DocListCreate a self-owned void IDocList
DocListCreate a self-owned IDocList from a JSON array
DocListCopyCreate a self-owned IDocList as full copy of a TDocVariant dvArray
DocListCopyCreate a self-owned IDocList as full copy of a TDocVariantData dvArray
DocListCopyCreate a self-owned IDocList as full copy of a TDocVariantData dvArray and a specific options model
DocListFromCreate a self-owned IDocList from a dynamic array of IDocDict values
DocListFromCreate a IDocList as weak reference to a TDocVariant dvArray
DocListFromResultsCreate a self-owned IDocList from TOrmTableJson ORM/DB dual JSON formats
DocVariantDataDirect access to a TDocVariantData from a given variant instance
DocVariantToObjArrayFill a T*ObjArray variable from a TDocVariant array document values
DocVariantToObjectFill a class instance from a TDocVariant object document properties
FastVarDataCompInternal function as called by inlined VariantCompare/VariantCompareI and the SortDynArrayVariantComp() function overriden by this unit
FillZeroFill all bytes of the value's memory buffer with zeros, i.e. 'toto' -> #0#0#0#0
FindSynVariantTypeSearch of a registered custom variant type from its low-level VarType
FromVarVariantRetrieve a variant value from variable-length buffer
GetJsonToAnyVariantLow-level function to parse a JSON content into a variant
GetNextItemToVariantConvert the next CSV item into a variant number or RawUtf8 varString
GetNumericVariantFromJsonLow-level function to parse a variant from an unescaped JSON number
GetVariantFromJsonFieldLow-level function to set a variant from an unescaped JSON number or string
GetVariantFromNotStringJsonLow-level function to set a variant from an unescaped JSON non string
InitializeVariantsJsonInternal initialization function called from mormot.core.json
JsonToAnyVariantLow-level function to parse a JSON buffer content into a variant
JsonToVariantJust a wrapper around VariantLoadJson() with some TDocVariantOptions
JsonToVariantDynArrayConvert a JSON array into a dynamic array of variants
JsonToVariantInPlaceJust a wrapper around JsonToAnyVariant() with some TDocVariantOptions
MultiPartToDocVariantDecode multipart/form-data POST request content into a TDocVariantData
ObjectDefaultToVariantWill convert a blank TObject into a TDocVariant document instance
ObjectToVariantWill convert any TObject into a TDocVariant document instance
ObjectToVariantWill convert any TObject into a TDocVariant document instance
ObjectToVariantDebugWill serialize any TObject into a TDocVariant debugging document
ParseSortMatchParse a "key<value" or "key<" expression for SortMatch() comparison
RawUtf8DynArrayToArrayOfConstConvert an array of RawUtf8 to open array (const Args: array of const) arguments
RawUtf8ToVariantConvert an UTF-8 encoded text buffer into a variant RawUtf8 varString
SetNameToVariantGet the enumeration names corresponding to a set value, as a JSON array
SetNameToVariantGet the enumeration names corresponding to a set value, as a JSON array
SetVariantByRefSame as Dest := Source, but copying by reference
SetVariantByValueSame as Dest := Source, but copying by value
SortCompToLow-level conversion of a Compare() result to TCustomVariantType.Compare
SynRegisterCustomVariantTypeRegister a custom variant type to handle properties
TextBufferToVariantConvert some UTF-8 buffer into a variant, detecting JSON numbers or constants
TextToVariantConvert some UTF-8 into a variant, detecting JSON numbers or constants
TextToVariantNumberTypeIdentify either varInt64, varDouble, varCurrency types following JSON format
TextToVariantNumberTypeNoDoubleIdentify either varInt64 or varCurrency types following JSON format
ToTextRetrieve the text representation of a TDocVairnatKind
UniqueVariantConvert some UTF-8 text buffer into a variant, with string interning
ValuesToVariantDynArrayConvert an open array list into a dynamic array of variants
VariantCompareTVariantCompare-compatible case-sensitive comparison function
VariantCompareITVariantCompare-compatible case-insensitive comparison function
VariantDynArrayToJsonConvert a dynamic array of variants into its JSON serialization
VariantDynArrayToRawUtf8DynArrayConvert a dynamic array of variants into its text values
VariantEqualsFast comparison of a Variant and UTF-8 encoded String (or number)
VariantLoadRetrieve a variant value from our optimized binary serialization format
VariantLoadRetrieve a variant value from our optimized binary serialization format
VariantLoadJsonRetrieve a variant value from a JSON number or string
VariantLoadJsonRetrieve a variant value from a JSON number or string
VariantSaveSave a Variant content into a binary buffer
VariantSaveSave a Variant content into a destination memory buffer
VariantSaveLengthCompute the number of bytes needed to save a Variant content using the VariantSave() function
VariantsToArrayOfConstConvert a variant array to open array (const Args: array of const) arguments
VariantsToArrayOfConstConvert a variant array to open array (const Args: array of const) arguments
VariantToStringConvert any Variant into a RTL string type
VariantToStringConvert any Variant into a RTL string type
VariantToVarRecConvert a variant to an open array (const Args: array of const) argument
VariantTypeNameReturn the variant VType as text, e.g. 'Integer', 'String' or 'DocVariant'
VariantTypeNameReturn the TVarData.VType as text, e.g. 'Integer', 'String' or 'DocVariant'
VarIsAllow to check for a specific set of TVarData.VType
VarIsVoidFastcheck if a variant hold a value
VarRecToVariantConvert an open array (const Args: array of const) argument to a variant
VarRecToVariantConvert an open array (const Args: array of const) argument to a variant
VarStringOrNullReturns a supplied string as variant, or null if v is void ('')
ZeroFillSame as FillChar(Value^,SizeOf(TVarData),0)
_ArrInitialize a variant instance to store some document-based array content
_ArrFastInitialize a variant instance to store some document-based array content
_ByRefCopy a TDocVariant to another variable, changing the options on the fly
_ByRefCopy a TDocVariant to another variable, changing the options on the fly
_CopyReturn a full nested copy of a document-based variant instance
_CopyFastReturn a full nested copy of a document-based variant instance
_CsvConvert a TDocVariantData array or a string value into a CSV
_DVDirect copy of a TDocVariantData from a given variant instance
_DVDirect copy of a TDocVariantData from a given variant instance
_DVDirect copy of a TDocVariantData from a given variant instance
_JsonInitialize a variant instance to store some document-based content from a supplied (extended) JSON content
_JsonInitialize a variant instance to store some document-based content from a supplied (extended) JSON content
_JsonFastInitialize a variant instance to store some document-based content from a supplied (extended) JSON content
_JsonFastExtInitialize a variant instance to store some extended document-based content
_JsonFastFloatInitialize a variant instance to store some document-based content from a supplied (extended) JSON content, with double conversion
_JsonFastFmtInitialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
_JsonFmtInitialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
_JsonFmtInitialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
_ObjDelphi has troubles inlining goto/label initialize a variant instance to store some document-based object content
_ObjAddPropAdd a property value to a document-based object content
_ObjAddPropAdd a document property value to a document-based object content
_ObjAddPropsAdd some property values to a document-based object content
_ObjAddPropsAdd the property values of a document to a document-based object content
_ObjAddPropUAdd a RawUtf8 property value to a document-based object content
_ObjFastInitialize a variant instance to store some document-based object content
_ObjFastInitialize a variant instance to store any object as a TDocVariant
_SafeDirect access to a TDocVariantData from a given variant instance
_SafeDelphi has problems inlining this :( direct access to a TDocVariantData from a given variant instance
_SafeDirect access to a TDocVariantData from a given variant instance
_SafeArrayDirect access to a TDocVariantData array from a given variant instance
_SafeArrayDirect access to a TDocVariantData array from a given variant instance
_SafeObjectDirect access to a TDocVariantData object from a given variant instance
_UniqueEnsure a document-based variant instance will have only per-value nested objects or array documents
_UniqueFastEnsure a document-based variant instance will have only per-value nested objects or array documents

1.6.1. CustomVariantToJson

function CustomVariantToJson(W: TJsonWriter; Value: PVarData; Escape: TTextWriterKind): boolean;

Try to serialize a custom variant value into JSON
- as used e.g. by TJsonWriter.AddVariant


1.6.2. DocDict

function DocDict(const json: RawUtf8; model: TDocVariantModel = mFastFloat): IDocDict; overload;

Create a self-owned IDocDict from a JSON object


1.6.3. DocDict

function DocDict(model: TDocVariantModel = mFastFloat): IDocDict; overload;

Create a self-owned void IDocDict


1.6.4. DocDict

function DocDict(const dv: TDocVariantData): IDocDict; overload;

Create a IDocDict as weak reference to a TDocVariantData dvObject


1.6.5. DocDict

function DocDict(const keyvalues: array of const; model: TDocVariantModel = mFastFloat): IDocDict; overload;

Create a self-owned IDocDict from a set of key,value pairs


1.6.6. DocDictCopy

function DocDictCopy(const dv: TDocVariantData; model: TDocVariantModel): IDocDict; overload;

Create a self-owned IDocDict as full copy of a TDocVariantData dvObject and a specific options model


1.6.7. DocDictCopy

function DocDictCopy(const dv: TDocVariantData): IDocDict; overload;

Create a self-owned IDocDict as full copy of a TDocVariantData dvObject


1.6.8. DocDictCopy

function DocDictCopy(const v: variant): IDocDict; overload;

Create a self-owned IDocDict as full copy of a TDocVariant dvObject


1.6.9. DocDictDynArray

function DocDictDynArray(const json: RawUtf8; model: TDocVariantModel = mFastFloat; jsonfromresults: boolean = false): IDocDictDynArray;

Create an array of self-owned IDocDict from a JSON array of JSON objects
- set jsonfromresults=true if input is TOrmTableJson ORM/DB dual JSON formats
- any element of the JSON array which is not a JSON object will be ignored


1.6.10. DocDictFrom

function DocDictFrom(const v: variant): IDocDict;

Create a IDocDict as weak reference to a TDocVariant dvObject


1.6.11. DocDictFromKeys

function DocDictFromKeys(const keys: array of RawUtf8; model: TDocVariantModel = mFastFloat): IDocDict; overload;

Create a self-owned IDocDict from a set of keys - values will be Null


1.6.12. DocDictFromKeys

function DocDictFromKeys(const keys: array of RawUtf8; const value: variant; model: TDocVariantModel = mFastFloat): IDocDict; overload;

Create a self-owned IDocDict from a set of keys and a gien value


1.6.13. DocList

function DocList(model: TDocVariantModel = mFastFloat): IDocList; overload;

Create a self-owned void IDocList


1.6.14. DocList

function DocList(const json: RawUtf8; model: TDocVariantModel = mFastFloat): IDocList; overload;

Create a self-owned IDocList from a JSON array


1.6.15. DocList

function DocList(const dv: TDocVariantData): IDocList; overload;

Create a IDocList as weak reference to a TDocVariantData dvArray


1.6.16. DocList

function DocList(const values: array of const; model: TDocVariantModel = mFastFloat): IDocList; overload;

Create a self-owned IDocList from a set of values


1.6.17. DocListCopy

function DocListCopy(const dv: TDocVariantData; model: TDocVariantModel): IDocList; overload;

Create a self-owned IDocList as full copy of a TDocVariantData dvArray and a specific options model


1.6.18. DocListCopy

function DocListCopy(const dv: TDocVariantData): IDocList; overload;

Create a self-owned IDocList as full copy of a TDocVariantData dvArray


1.6.19. DocListCopy

function DocListCopy(const v: variant): IDocList; overload;

Create a self-owned IDocList as full copy of a TDocVariant dvArray


1.6.20. DocListFrom

function DocListFrom(const v: variant): IDocList; overload;

Create a IDocList as weak reference to a TDocVariant dvArray


1.6.21. DocListFrom

function DocListFrom(const dictarray: IDocDictDynArray): IDocList; overload;

Create a self-owned IDocList from a dynamic array of IDocDict values


1.6.22. DocListFromResults

function DocListFromResults(const json: RawUtf8; model: TDocVariantModel = mFastFloat): IDocList;

Create a self-owned IDocList from TOrmTableJson ORM/DB dual JSON formats


1.6.23. DocVariantData

function DocVariantData(const DocVariant: variant): PDocVariantData;

Direct access to a TDocVariantData from a given variant instance
- return a pointer to the TDocVariantData corresponding to the variant instance, which may be of kind varByRef (e.g. when retrieved by late binding)
- raise an EDocVariant exception if the instance is not a TDocVariant
- the following direct trans-typing may fail, e.g. for varByRef value:

 TDocVariantData(aVarDoc.ArrayProp).Add('new item');

- so you can write the following:

 DocVariantData(aVarDoc.ArrayProp).AddItem('new item');

- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData


1.6.24. DocVariantToObjArray

procedure DocVariantToObjArray(var arr: TDocVariantData; var objArray; objClass: TClass);

Fill a T*ObjArray variable from a TDocVariant array document values
- will always erase the T*ObjArray instance, and fill it from arr values


1.6.25. DocVariantToObject

function DocVariantToObject(var doc: TDocVariantData; obj: TObject; objRtti: TRttiCustom = nil): boolean;

Fill a class instance from a TDocVariant object document properties
- returns FALSE if the variant is not a dvObject, TRUE otherwise


1.6.26. FastVarDataComp

function FastVarDataComp(A, B: PVarData; caseInsensitive: boolean): integer;

Internal function as called by inlined VariantCompare/VariantCompareI and the SortDynArrayVariantComp() function overriden by this unit


1.6.27. FillZero

procedure FillZero(var value: variant); overload;

Fill all bytes of the value's memory buffer with zeros, i.e. 'toto' -> #0#0#0#0
- may be used to cleanup stack-allocated content


1.6.28. FindSynVariantType

function FindSynVariantType(aVarType: cardinal): TSynInvokeableVariantType;

Search of a registered custom variant type from its low-level VarType
- returns the matching custom variant type, nil if not found


1.6.29. FromVarVariant

procedure FromVarVariant(var Source: PByte; var Value: variant; CustomVariantOptions: PDocVariantOptions; SourceMax: PByte);

Retrieve a variant value from variable-length buffer
- matches TFileBufferWriter.Write()
- how custom type variants are created can be defined via CustomVariantOptions
- is just a wrapper around VariantLoad/BinaryLoad


1.6.30. GetJsonToAnyVariant

procedure GetJsonToAnyVariant(var Value: variant; var Json: PUtf8Char; EndOfObject: PUtf8Char; Options: PDocVariantOptions; AllowDouble: boolean); overload;

Low-level function to parse a JSON content into a variant


1.6.31. GetNextItemToVariant

function GetNextItemToVariant(var P: PUtf8Char; out Value: Variant; Sep: AnsiChar = ','; AllowDouble: boolean = true): boolean;

Convert the next CSV item into a variant number or RawUtf8 varString
- just a wrapper around GetNextItem() + TextToVariant()


1.6.32. GetNumericVariantFromJson

function GetNumericVariantFromJson(Json: PUtf8Char; var Value: TVarData; AllowVarDouble: boolean): PUtf8Char;

Low-level function to parse a variant from an unescaped JSON number
- returns the position after the number, and set Value to a variant of type varInteger/varInt64/varCurrency (or varDouble if AllowVarDouble is true)
- returns nil if JSON can't be converted to a number - it is likely a string
- handle only up to 4 decimals (i.e. currency) if AllowVarDouble is false
- matches TextToVariantNumberType/TextToVariantNumberTypeNoDouble() logic
- see GetVariantFromNotStringJson() to check the whole Json input, and parse null/false/true values


1.6.33. GetVariantFromJsonField

procedure GetVariantFromJsonField(Json: PUtf8Char; wasString: boolean; var Value: variant; TryCustomVariants: PDocVariantOptions = nil; AllowDouble: boolean = false; JsonLen: integer = 0);

Low-level function to set a variant from an unescaped JSON number or string
- expect the JSON input buffer to be already unescaped and #0 terminated, e.g. by TGetJsonField, and having set properly the wasString flag
- set the varString or call GetVariantFromNotStringJson() if TryCustomVariants=nil
- or call JsonToAnyVariant() to support TryCustomVariants^ complex input


1.6.34. GetVariantFromNotStringJson

function GetVariantFromNotStringJson(Json: PUtf8Char; var Value: TVarData; AllowDouble: boolean): boolean;

Low-level function to set a variant from an unescaped JSON non string
- expect the JSON input buffer to be already unescaped and #0 terminated, e.g. by TGetJsonField, and having returned wasString=false
- is called e.g. by function GetVariantFromJsonField()
- will recognize null, boolean, integer, Int64, currency, double (if AllowDouble is true) input, then set Value and return TRUE
- returns FALSE if the supplied input has no expected JSON format


1.6.35. InitializeVariantsJson

procedure InitializeVariantsJson;

Internal initialization function called from mormot.core.json


1.6.36. JsonToAnyVariant

procedure JsonToAnyVariant(var Value: variant; var Info: TGetJsonField; Options: PDocVariantOptions; AllowDouble: boolean = false);

Low-level function to parse a JSON buffer content into a variant
- warning: will decode in the Json buffer memory itself (no memory allocation or copy), for faster process - so take care that it is not shared
- internal method used by VariantLoadJson(), GetVariantFromJsonField() and TDocVariantData.InitJson()
- will instantiate either an integer, Int64, currency, double or string value (as RawUtf8), guessing the best numeric type according to the textual content, and string in all other cases, except TryCustomVariants points to some options (e.g. @JSON_[mFast] for fast instance) and input is a known object or array, either encoded as strict-JSON (i.e. {..} or [..]), or with some extended (e.g. BSON) syntax


1.6.37. JsonToVariant

function JsonToVariant(const Json: RawUtf8; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]; AllowDouble: boolean = false): variant;

Just a wrapper around VariantLoadJson() with some TDocVariantOptions
- make a temporary copy of the input Json before parsing


1.6.38. JsonToVariantDynArray

function JsonToVariantDynArray(const Json: RawUtf8): TVariantDynArray;

Convert a JSON array into a dynamic array of variants
- will use a TDocVariantData temporary storage


1.6.39. JsonToVariantInPlace

function JsonToVariantInPlace(var Value: Variant; Json: PUtf8Char; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]; AllowDouble: boolean = false): PUtf8Char;

Just a wrapper around JsonToAnyVariant() with some TDocVariantOptions


1.6.40. MultiPartToDocVariant

procedure MultiPartToDocVariant(const MultiPart: TMultiPartDynArray; var Doc: TDocVariantData; Options: PDocVariantOptions = nil);

Decode multipart/form-data POST request content into a TDocVariantData
- following RFC 1867
- decoded sections are encoded as Doc JSON object with its textual values, or with nested objects, if the data was supplied as binary:

 {"name1":{"data":..,"filename":...,"contenttype":...},"name2":...}

1.6.41. ObjectDefaultToVariant

function ObjectDefaultToVariant(aClass: TClass; aOptions: TDocVariantOptions): variant; overload;

Will convert a blank TObject into a TDocVariant document instance


1.6.42. ObjectToVariant

procedure ObjectToVariant(Value: TObject; var result: variant; Options: TTextWriterWriteObjectOptions = [woDontStoreDefault]); overload;

Will convert any TObject into a TDocVariant document instance
- fast processing function as used by _ObjFast(Value)
- note that the result variable should already be cleared: no VarClear() is done by this function
- would be used e.g. by VarRecToVariant() function
- if you expect lazy-loading of a TObject, see TObjectVariant.New()


1.6.43. ObjectToVariant

function ObjectToVariant(Value: TObject; EnumSetsAsText: boolean): variant; overload;

Will convert any TObject into a TDocVariant document instance
- convenient overloaded function to include woEnumSetsAsText option


1.6.44. ObjectToVariantDebug

function ObjectToVariantDebug(Value: TObject; const ContextFormat: RawUtf8; const ContextArgs: array of const; const ContextName: RawUtf8 = 'context'): variant; overload;

Will serialize any TObject into a TDocVariant debugging document
- just a wrapper around _JsonFast(ObjectToJsonDebug()) with an optional "Context":"..." text message
- if the supplied context format matches '{....}' then it will be added as a corresponding TDocVariant JSON object


1.6.45. ParseSortMatch

function ParseSortMatch(Expression: PUtf8Char; out Key: RawUtf8; out Match: TCompareOperator; Value: PVariant): boolean;

Parse a "key<value" or "key<" expression for SortMatch() comparison


1.6.46. RawUtf8DynArrayToArrayOfConst

function RawUtf8DynArrayToArrayOfConst(const V: array of RawUtf8): TTVarRecDynArray;

Convert an array of RawUtf8 to open array (const Args: array of const) arguments
- RawUtf8 are accessed by reference as vtAnsiString so should remain available


1.6.47. RawUtf8ToVariant

procedure RawUtf8ToVariant(const Txt: RawUtf8; var Value: TVarData; ExpectedValueType: cardinal); overload;

Convert an UTF-8 encoded text buffer into a variant RawUtf8 varString
- this overloaded version expects a destination variant type (e.g. varString varOleStr / varUString) - if the type is not handled, will raise an EVariantTypeCastError


1.6.48. SetNameToVariant

function SetNameToVariant(Value: cardinal; Info: TRttiCustom; FullSetsAsStar: boolean = false): variant; overload;

Get the enumeration names corresponding to a set value, as a JSON array


1.6.49. SetNameToVariant

function SetNameToVariant(Value: cardinal; Info: PRttiInfo; FullSetsAsStar: boolean = false): variant; overload;

Get the enumeration names corresponding to a set value, as a JSON array


1.6.50. SetVariantByRef

procedure SetVariantByRef(const Source: Variant; var Dest: Variant);

Same as Dest := Source, but copying by reference
- i.e. VType is defined as varVariant or varByRef / varVariantByRef
- for instance, it will be used for late binding of TDocVariant properties, to let following statements work as expected:

 V := _Json('{arr:[1,2]}');
 V.arr.Add(3);   // will work, since V.arr will be returned by reference
 writeln(V);     // will write '{"arr":[1,2,3]}'

1.6.51. SetVariantByValue

procedure SetVariantByValue(const Source: Variant; var Dest: Variant);

Same as Dest := Source, but copying by value
- will unreference any varByRef content
- will convert any string value into RawUtf8 (varString) for consistency


1.6.52. SortCompTo

function SortCompTo(cmp: integer): TVarCompareResult;

Low-level conversion of a Compare() result to TCustomVariantType.Compare


1.6.53. SynRegisterCustomVariantType

function SynRegisterCustomVariantType( aClass: TSynInvokeableVariantTypeClass): TSynInvokeableVariantType;

Register a custom variant type to handle properties
- the registration process is thread-safe
- this will implement an internal mechanism used to bypass the default _DispInvoke() implementation in Variant.pas, to use a faster version
- is called in case of TDocVariant, TBsonVariant or TSqlDBRowVariant


1.6.54. TextBufferToVariant

procedure TextBufferToVariant(aValue: PUtf8Char; AllowVarDouble: boolean; out aDest: variant);

Convert some UTF-8 buffer into a variant, detecting JSON numbers or constants
- first try GetVariantFromNotStringJson() then fallback to RawUtf8ToVariant()


1.6.55. TextToVariant

procedure TextToVariant(const aValue: RawUtf8; AllowVarDouble: boolean; out aDest: variant);

Convert some UTF-8 into a variant, detecting JSON numbers or constants
- first try GetVariantFromNotStringJson() then fallback to RawUtf8ToVariant()


1.6.56. TextToVariantNumberType

function TextToVariantNumberType(Json: PUtf8Char): cardinal;

Identify either varInt64, varDouble, varCurrency types following JSON format
- any non valid number is returned as varString
- warning: supplied JSON is expected to be not nil


1.6.57. TextToVariantNumberTypeNoDouble

function TextToVariantNumberTypeNoDouble(Json: PUtf8Char): cardinal;

Identify either varInt64 or varCurrency types following JSON format
- this version won't return varDouble, i.e. won't handle more than 4 exact decimals (as varCurrency), nor scientific notation with exponent (1.314e10)
- this will ensure that any incoming JSON will converted back with its exact textual representation, without digit truncation due to limited precision
- any non valid number is returned as varString
- warning: supplied JSON is expected to be not nil


1.6.58. ToText

function ToText(kind: TDocVariantKind): PShortString; overload;

Retrieve the text representation of a TDocVairnatKind


1.6.59. UniqueVariant

procedure UniqueVariant(Interning: TRawUtf8Interning; var aResult: variant; aText: PUtf8Char; aTextLen: PtrInt; aAllowVarDouble: boolean = false); overload;

Convert some UTF-8 text buffer into a variant, with string interning
- similar to TextToVariant(), but with string interning (if Interning<>nil)
- first try GetVariantFromNotStringJson() then fallback to RawUtf8ToVariant()


1.6.60. ValuesToVariantDynArray

function ValuesToVariantDynArray(const items: array of const): TVariantDynArray;

Convert an open array list into a dynamic array of variants
- will use a TDocVariantData temporary storage


1.6.61. VariantCompare

function VariantCompare(const V1, V2: variant): PtrInt;

TVariantCompare-compatible case-sensitive comparison function
- just a wrapper around FastVarDataComp(caseInsensitive=false)


1.6.62. VariantCompareI

function VariantCompareI(const V1, V2: variant): PtrInt;

TVariantCompare-compatible case-insensitive comparison function
- just a wrapper around FastVarDataComp(caseInsensitive=true)


1.6.63. VariantDynArrayToJson

function VariantDynArrayToJson(const V: TVariantDynArray): RawUtf8;

Convert a dynamic array of variants into its JSON serialization
- will use a TDocVariantData temporary storage


1.6.64. VariantDynArrayToRawUtf8DynArray

function VariantDynArrayToRawUtf8DynArray(const V: TVariantDynArray): TRawUtf8DynArray;

Convert a dynamic array of variants into its text values


1.6.65. VariantEquals

function VariantEquals(const V: Variant; const Str: RawUtf8; CaseSensitive: boolean = true): boolean; overload;

Fast comparison of a Variant and UTF-8 encoded String (or number)
- slightly faster than plain V=Str, which computes a temporary variant
- here Str='' equals unassigned (varEmpty), null or false
- if CaseSensitive is false, will use PropNameEquals() for comparison


1.6.66. VariantLoad

function VariantLoad(var Value: variant; Source: PAnsiChar; CustomVariantOptions: PDocVariantOptions; SourceMax: PAnsiChar = nil ): PAnsiChar; overload;

Retrieve a variant value from our optimized binary serialization format
- follow the data layout as used by RecordLoad() or VariantSave() function
- return nil if the Source buffer is incorrect
- in case of success, return the memory buffer pointer just after the read content
- how custom type variants are created can be defined via CustomVariantOptions
- is a wrapper around BinaryLoad(rkVariant)


1.6.67. VariantLoad

function VariantLoad(const Bin: RawByteString; CustomVariantOptions: PDocVariantOptions): variant; overload;

Retrieve a variant value from our optimized binary serialization format
- follow the data layout as used by RecordLoad() or VariantSave() function
- return varEmpty if the Source buffer is incorrect
- just a wrapper around VariantLoad()
- how custom type variants are created can be defined via CustomVariantOptions
- is a wrapper around BinaryLoad(rkVariant)


1.6.68. VariantLoadJson

function VariantLoadJson(var Value: Variant; const Json: RawUtf8; TryCustomVariants: PDocVariantOptions = nil; AllowDouble: boolean = false): boolean; overload;

Retrieve a variant value from a JSON number or string
- follows TJsonWriter.AddVariant() format (calls JsonToAnyVariant)
- make a temporary copy before parsing - use JsonToAnyVariant() on a buffer
- return true and set Value on success, or false and empty Value on error


1.6.69. VariantLoadJson

function VariantLoadJson(const Json: RawUtf8; TryCustomVariants: PDocVariantOptions = nil; AllowDouble: boolean = false): variant; overload;

Retrieve a variant value from a JSON number or string
- just wrap VariantLoadJson(Value,Json...) procedure as a function


1.6.70. VariantSave

function VariantSave(const Value: variant; Dest: PAnsiChar): PAnsiChar; overload; deprecated;

Save a Variant content into a destination memory buffer
- Dest must be at least VariantSaveLength() bytes long
- will handle standard Variant types and custom types (serialized as JSON)
- will return nil in case of an invalid (not handled) Variant type
- will use a proprietary binary format, with some variable-length encoding of the string length
- warning: will encode RTL string fields as within the variant type itself: using this function between UNICODE and NOT UNICODE versions of Delphi, will propably fail - you have been warned!
- deprecated function - use overloaded BinarySave() functions instead


1.6.71. VariantSave

function VariantSave(const Value: variant): RawByteString; overload;

Save a Variant content into a binary buffer
- will handle standard Variant types and custom types (serialized as JSON)
- will return '' in case of an invalid (not handled) Variant type
- just a wrapper around VariantSaveLength()+VariantSave()
- warning: will encode RTL string fields as within the variant type itself: using this function between UNICODE and NOT UNICODE versions of Delphi, will propably fail - you have been warned!
- is a wrapper around BinarySave(rkVariant)


1.6.72. VariantSaveLength

function VariantSaveLength(const Value: variant): integer; deprecated;

Compute the number of bytes needed to save a Variant content using the VariantSave() function
- will return 0 in case of an invalid (not handled) Variant type
- deprecated function - use overloaded BinarySave() functions instead


1.6.73. VariantsToArrayOfConst

function VariantsToArrayOfConst(const V: array of variant): TTVarRecDynArray; overload;

Convert a variant array to open array (const Args: array of const) arguments
- variants are accessed by reference as vtVariant so should remain available


1.6.74. VariantsToArrayOfConst

procedure VariantsToArrayOfConst(const V: array of variant; VCount: PtrInt; out result: TTVarRecDynArray); overload;

Convert a variant array to open array (const Args: array of const) arguments
- variants are accessed by reference as vtVariant so should remain available


1.6.75. VariantToString

procedure VariantToString(const V: Variant; var result: string); overload;

Convert any Variant into a RTL string type


1.6.76. VariantToString

function VariantToString(const V: Variant): string; overload;

Convert any Variant into a RTL string type
- expects any varString value to be stored as a RawUtf8
- prior to Delphi 2009, use VariantToString(aVariant) instead of string(aVariant) to safely retrieve a string=AnsiString value from a variant generated by our framework units - otherwise, you may loose encoded characters
- for Unicode versions of Delphi, there won't be any potential data loss, but this version may be slightly faster than a string(aVariant)


1.6.77. VariantToVarRec

procedure VariantToVarRec(const V: variant; var result: TVarRec);

Convert a variant to an open array (const Args: array of const) argument
- variant is accessed by reference as vtVariant so should remain available


1.6.78. VariantTypeName

function VariantTypeName(V: PVarData): PShortString; overload;

Return the TVarData.VType as text, e.g. 'Integer', 'String' or 'DocVariant'


1.6.79. VariantTypeName

function VariantTypeName(const V: variant): PShortString; overload;

Return the variant VType as text, e.g. 'Integer', 'String' or 'DocVariant'


1.6.80. VarIs

function VarIs(const V: Variant; const VTypes: TVarDataTypes): boolean;

Allow to check for a specific set of TVarData.VType


1.6.81. VarIsVoid

function VarIsVoid(const V: Variant): boolean;

Fastcheck if a variant hold a value
- varEmpty, varNull or a '' string would be considered as void
- varBoolean=false or varDate=0 would be considered as void
- a TDocVariantData with Count=0 would be considered as void
- any other value (e.g. floats or integer) would be considered as not void


1.6.82. VarRecToVariant

procedure VarRecToVariant(const V: TVarRec; var result: variant); overload;

Convert an open array (const Args: array of const) argument to a variant
- note that, due to a Delphi compiler limitation, cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be converted)
- vt*String or vtVariant arguments are returned as varByRef


1.6.83. VarRecToVariant

function VarRecToVariant(const V: TVarRec): variant; overload;

Convert an open array (const Args: array of const) argument to a variant
- note that, due to a Delphi compiler limitation, cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be converted)
- vt*String or vtVariant arguments are returned as varByRef


1.6.84. VarStringOrNull

function VarStringOrNull(const v: RawUtf8): variant;

Returns a supplied string as variant, or null if v is void ('')


1.6.85. ZeroFill

procedure ZeroFill(Value: PVarData);

Same as FillChar(Value^,SizeOf(TVarData),0)
- so can be used for TVarData or Variant
- it will set V.VType := varEmpty, so Value will be Unassigned
- it won't call VarClear(variant(Value)): it should have been cleaned before


1.6.86. _Arr

function _Arr(const Items: array of const; Options: TDocVariantOptions = []): variant;

Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied as parameters, e.g.

 aVariant := _Arr(['one',2,3.0]);

- this global function is an alias to TDocVariant.NewArray()
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set Options = [dvoValueCopiedByReference] or using _ArrFast() will increase the process speed a lot


1.6.87. _ArrFast

function _ArrFast(const Items: array of const): variant; overload;

Initialize a variant instance to store some document-based array content
- this global function is an handy alias to:

 _Array(Items, JSON_FAST);

- so all created objects and arrays will be handled by reference, for best speed - but you should better write on the resulting variant tree with caution


1.6.88. _ByRef

function _ByRef(const DocVariant: variant; Options: TDocVariantOptions): variant; overload;

Copy a TDocVariant to another variable, changing the options on the fly
- note that the content (items or properties) is copied by reference, so consider using _Copy() instead if you expect to safely modify its content
- will return null if the supplied variant is not a TDocVariant


1.6.89. _ByRef

procedure _ByRef(const DocVariant: variant; out Dest: variant; Options: TDocVariantOptions); overload;

Copy a TDocVariant to another variable, changing the options on the fly
- note that the content (items or properties) is copied by reference, so consider using _Copy() instead if you expect to safely modify its content
- will return null if the supplied variant is not a TDocVariant


1.6.90. _Copy

function _Copy(const DocVariant: variant): variant;

Return a full nested copy of a document-based variant instance
- is just a wrapper around:

 TDocVariant.NewUnique(DocVariant,JSON_[mDefault])

- you can use this function to ensure that all internal properties of this variant will be copied per-value whatever options the nested objects or arrays were created with: to be used on a value returned as varByRef (e.g. by _() pseudo-method)
- for huge document with a big depth of nested objects or arrays, a full per-value copy may be time and resource consuming, but will be also safe - consider using _ByRef() instead if a fast copy-by-reference is enough
- will raise an EDocVariant if the supplied variant is not a TDocVariant or a varByRef pointing to a TDocVariant


1.6.91. _CopyFast

function _CopyFast(const DocVariant: variant): variant;

Return a full nested copy of a document-based variant instance
- is just a wrapper around:

 TDocVariant.NewUnique(DocVariant, JSON_FAST)

- you can use this function to ensure that all internal properties of this variant will be copied per-value whatever options the nested objects or arrays were created with: to be used on a value returned as varByRef (e.g. by _() pseudo-method)
- for huge document with a big depth of nested objects or arrays, a full per-value copy may be time and resource consuming, but will be also safe - consider using _ByRef() instead if a fast copy-by-reference is enough
- will raise an EDocVariant if the supplied variant is not a TDocVariant or a varByRef pointing to a TDocVariant


1.6.92. _Csv

function _Csv(const DocVariantOrString: variant): RawUtf8;

Convert a TDocVariantData array or a string value into a CSV
- will call either TDocVariantData.ToCsv, or return the string
- returns '' if the supplied value is neither a TDocVariant or a string
- could be used e.g. to store either a JSON CSV string or a JSON array of strings in a settings property


1.6.93. _DV

function _DV(const DocVariant: variant): TDocVariantData; overload;

Direct copy of a TDocVariantData from a given variant instance
- slower, but maybe used instead of _Safe() e.g. on Delphi 11


1.6.94. _DV

function _DV(const DocVariant: variant; var DV: TDocVariantData): boolean; overload;

Direct copy of a TDocVariantData from a given variant instance
- slower, but maybe used instead of _Safe() e.g. on Delphi 11


1.6.95. _DV

function _DV(const DocVariant: variant; ExpectedKind: TDocVariantKind): TDocVariantData; overload;

Direct copy of a TDocVariantData from a given variant instance
- slower, but maybe used instead of _Safe() e.g. on Delphi 11


1.6.96. _Json

function _Json(const Json: RawUtf8; var Value: variant; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): boolean; overload;

Initialize a variant instance to store some document-based content from a supplied (extended) JSON content
- this global function is an alias to TDocVariant.NewJson(), and will return TRUE if JSON content was correctly converted into a variant
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names or ObjectID()
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, add dvoValueCopiedByReference in Options will increase the process speed a lot, or use _JsonFast()


1.6.97. _Json

function _Json(const Json: RawUtf8; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): variant; overload;

Initialize a variant instance to store some document-based content from a supplied (extended) JSON content
- this global function is an alias to TDocVariant.NewJson(), and return an Unassigned (varEmpty) variant if JSON content was not correctly converted
- object or array will be initialized from the supplied JSON content, e.g.

 aVariant := _Json('{"id":10,"doc":{"name":"John","birthyear":1972}}');
 // now you can access to the properties via late binding
 assert(aVariant.id=10);
 assert(aVariant.doc.name='John');
 assert(aVariant.doc.birthYear=1972);
 // and also some pseudo-properties:
 assert(aVariant._count=2);
 assert(aVariant.doc._kind=ord(dvObject));
 // or with a JSON array:
 aVariant := _Json('["one",2,3]');
 assert(aVariant._kind=ord(dvArray));
 for i := 0 to aVariant._count-1 do
   writeln(aVariant._(i));

- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names:

 aVariant := _Json('{id:10,doc:{name:"John",birthyear:1972}}');

- if the mormot.db.nosql.bson unit is used in the application, the MongoDB Shell syntax will also be recognized to create TBsonVariant, like

 new Date()   ObjectId()   MinKey   MaxKey  /<jRegex>/<jOptions>

see @http://docs.mongodb.org/manual/reference/mongodb-extended-json
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, add dvoValueCopiedByReference in Options will increase the process speed a lot, or use _JsonFast()
- handle only currency for floating point values: call _JsonFastFloat or set dvoAllowDoubleValue option to support double, with potential precision loss


1.6.98. _JsonFast

function _JsonFast(const Json: RawUtf8): variant;

Initialize a variant instance to store some document-based content from a supplied (extended) JSON content
- this global function is an handy alias to:

 _Json(JSON, JSON_FAST);

so returns an Unassigned (varEmpty) variant if JSON content was not correct
- so all created objects and arrays will be handled by reference, for best speed - but you should better write on the resulting variant tree with caution
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names or ObjectID()
- will handle only currency for floating point values to avoid precision loss: use _JsonFastFloat() instead if you want to support double values


1.6.99. _JsonFastExt

function _JsonFastExt(const Json: RawUtf8): variant;

Initialize a variant instance to store some extended document-based content
- this global function is an handy alias to:

 _Json(JSON, JSON_FAST_EXTENDED);

1.6.100. _JsonFastFloat

function _JsonFastFloat(const Json: RawUtf8): variant;

Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with double conversion
- _JsonFast() will support only currency floats: use this method instead if your JSON input is likely to require double values - with potential precision loss


1.6.101. _JsonFastFmt

function _JsonFastFmt(const Format: RawUtf8; const Args, Params: array of const): variant;

Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
- this global function is an handy alias e.g. to:

 aVariant := _JsonFmt('{%:{$in:[?,?]}}',['type'],['food','snack'], JSON_FAST);

- so all created objects and arrays will be handled by reference, for best speed - but you should better write on the resulting variant tree with caution
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names or ObjectID():


1.6.102. _JsonFmt

function _JsonFmt(const Format: RawUtf8; const Args, Params: array of const; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): variant; overload;

Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
- wrapper around the _Json(FormatUtf8(...,JsonFormat=true)) function, i.e. every Args[] will be inserted for each % and Params[] for each ?, with proper JSON escaping of string values, and writing nested _Obj() / _Arr() instances as expected JSON objects / arrays
- typical use (in the context of mormot.db.nosql.bson unit) could be:

 aVariant := _JsonFmt('{%:{$in:[?,?]}}',['type'],['food','snack']);
 aVariant := _JsonFmt('{type:{$in:?}}',[],[_Arr(['food','snack'])]);
 // which are the same as:
 aVariant := _JsonFmt('{type:{$in:["food","snack"]}}');
 // in this context:
 u := VariantSaveJson(aVariant);
 assert(u='{"type":{"$in":["food","snack"]}}');
 u := VariantSaveMongoJson(aVariant,modMongoShell);
 assert(u='{type:{$in:["food","snack"]}}');

- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, add dvoValueCopiedByReference in Options will increase the process speed a lot, or use _JsonFast()


1.6.103. _JsonFmt

procedure _JsonFmt(const Format: RawUtf8; const Args, Params: array of const; Options: TDocVariantOptions; out Result: variant); overload;

Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
- this overload function will set directly a local variant variable, and would be used by inlined _JsonFmt/_JsonFastFmt functions


1.6.104. _Obj

function _Obj(const NameValuePairs: array of const; Options: TDocVariantOptions = []): variant;

Delphi has troubles inlining goto/label initialize a variant instance to store some document-based object content
- object will be initialized with data supplied two by two, as Name,Value pairs, e.g.

 aVariant := _Obj(['name','John','year',1972]);

or even with nested objects:

 aVariant := _Obj(['name','John','doc',_Obj(['one',1,'two',2.0])]);

- this global function is an alias to TDocVariant.NewObject()
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set Options=[dvoValueCopiedByReference] or using _ObjFast() will increase the process speed a lot


1.6.105. _ObjAddProp

procedure _ObjAddProp(const Name: RawUtf8; const Value: TDocVariantData; var Obj: variant); overload;

Add a document property value to a document-based object content


1.6.106. _ObjAddProp

procedure _ObjAddProp(const Name: RawUtf8; const Value: variant; var Obj: variant); overload;

Add a property value to a document-based object content
- if Obj is a TDocVariant object, will add the Name/Value pair
- if Obj is not a TDocVariant, will create a new fast document, initialized with supplied the Name/Value pairs
- this function will also ensure that ensure Obj is not stored by reference, but as a true TDocVariantData


1.6.107. _ObjAddProps

procedure _ObjAddProps(const Document: variant; var Obj: variant); overload;

Add the property values of a document to a document-based object content
- if Document is not a TDocVariant object, will do nothing
- if Obj is a TDocVariant object, will add Document fields to its content
- if Obj is not a TDocVariant object, Document will be copied to Obj


1.6.108. _ObjAddProps

procedure _ObjAddProps(const NameValuePairs: array of const; var Obj: variant); overload;

Add some property values to a document-based object content
- if Obj is a TDocVariant object, will add the Name/Value pairs
- if Obj is not a TDocVariant, will create a new fast document, initialized with supplied the Name/Value pairs
- this function will also ensure that ensure Obj is not stored by reference, but as a true TDocVariantData


1.6.109. _ObjAddPropU

procedure _ObjAddPropU(const Name: RawUtf8; const Value: RawUtf8; var Obj: variant);

Add a RawUtf8 property value to a document-based object content


1.6.110. _ObjFast

function _ObjFast(aObject: TObject; aOptions: TTextWriterWriteObjectOptions = [woDontStoreDefault]): variant; overload;

Initialize a variant instance to store any object as a TDocVariant
- is a wrapper around ObjectToVariant(aObject, result, aOptions)


1.6.111. _ObjFast

function _ObjFast(const NameValuePairs: array of const): variant; overload;

Initialize a variant instance to store some document-based object content
- this global function is an handy alias to:

 Obj(NameValuePairs, JSON_FAST);

- so all created objects and arrays will be handled by reference, for best speed - but you should better write on the resulting variant tree with caution


1.6.112. _Safe

function _Safe(const DocVariant: variant; out DV: PDocVariantData): boolean; overload;

Direct access to a TDocVariantData from a given variant instance
- return true and set DocVariant with a pointer to the TDocVariantData corresponding to the variant instance, which may be of kind varByRef (e.g. when retrieved by late binding)
- return false if the supplied Value is not a TDocVariant, but e.g. a string, a number or another type of custom variant
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData


1.6.113. _Safe

function _Safe(const DocVariant: variant; ExpectedKind: TDocVariantKind): PDocVariantData; overload;

Delphi has problems inlining this :( direct access to a TDocVariantData from a given variant instance
- return a pointer to the TDocVariantData corresponding to the variant instance, which may be of kind varByRef (e.g. when retrieved by late binding)
- will check the supplied document kind, i.e. either dvObject or dvArray and raise a EDocVariant exception if it does not match
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData


1.6.114. _Safe

function _Safe(const DocVariant: variant): PDocVariantData; overload;

Direct access to a TDocVariantData from a given variant instance
- return a pointer to the TDocVariantData corresponding to the variant instance, which may be of kind varByRef (e.g. when retrieved by late binding)
- will return a read-only fake TDocVariantData with Kind=dvUndefined if the supplied variant is not a TDocVariant instance, so could be safely used in a with block (use "with" moderation, of course):

 with _Safe(aDocVariant)^ do
   for ndx := 0 to Count-1 do // here Count=0 for the "fake" result
     writeln(Names[ndx]);

or excluding the "with" statement, as more readable code:

 var dv: PDocVariantData;
     ndx: PtrInt;
 begin
   dv := _Safe(aDocVariant);
   for ndx := 0 to dv.Count-1 do // here Count=0 for the "fake" result
     writeln(dv.Names[ndx]);

- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData


1.6.115. _SafeArray

function _SafeArray(const Value: variant; ExpectedCount: integer; out DV: PDocVariantData): boolean; overload;

Direct access to a TDocVariantData array from a given variant instance
- overload to check for a given number of itemsin the array


1.6.116. _SafeArray

function _SafeArray(const Value: variant; out DV: PDocVariantData): boolean; overload;

Direct access to a TDocVariantData array from a given variant instance
- return true and set DV with a pointer to the TDocVariantData corresponding to the variant instance, if it is a dvArray
- return false if the supplied Value is not an array TDocVariant
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData


1.6.117. _SafeObject

function _SafeObject(const Value: variant; out DV: PDocVariantData): boolean;

Direct access to a TDocVariantData object from a given variant instance
- return true and set DV with a pointer to the TDocVariantData corresponding to the variant instance, if it is a dvObject
- return false if the supplied Value is not an object TDocVariant
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData


1.6.118. _Unique

procedure _Unique(var DocVariant: variant);

Ensure a document-based variant instance will have only per-value nested objects or array documents
- is just a wrapper around:

 TDocVariantData(DocVariant).InitCopy(DocVariant, JSON_[mDefault])

- you can use this function to ensure that all internal properties of this variant will be copied per-value whatever options the nested objects or arrays were created with
- for huge document with a big depth of nested objects or arrays, a full per-value copy may be time and resource consuming, but will be also safe
- will raise an EDocVariant if the supplied variant is not a TDocVariant or a varByRef pointing to a TDocVariant


1.6.119. _UniqueFast

procedure _UniqueFast(var DocVariant: variant);

Ensure a document-based variant instance will have only per-value nested objects or array documents
- is just a wrapper around:

 TDocVariantData(DocVariant).InitCopy(DocVariant, JSON_FAST)

- you can use this function to ensure that all internal properties of this variant will be copied per-reference whatever options the nested objects or arrays were created with
- for huge document with a big depth of nested objects or arrays, it will first create a whole copy of the document nodes, but further assignments of the resulting value will be per-reference, so will be almost instant
- will raise an EDocVariant if the supplied variant is not a TDocVariant or a varByRef pointing to a TDocVariant


1.7. Variables implemented in the mormot.core.variants unit

1.7.1. DocAnyDefaultModel

DocAnyDefaultModel: TDocVariantModel = mFastFloat;

Default TDocVariant model for IDocList/IDocDict


1.7.2. DocVariantType

DocVariantType: TDocVariant;

The internal custom variant type used to register TDocVariant


1.7.3. DocVariantVType

DocVariantVType: cardinal;

Copy of DocVariantType.VarType
- as used by inlined functions of TDocVariantData


1.7.4. DV_FAST

DV_FAST: array[TDocVariantKind] of TVarData;

Defined here for inlining - properly filled in initialization section below


1.7.5. JSON_

JSON_: array[TDocVariantModel] of TDocVariantOptions = ( [], [dvoReturnNullForUnknownProperty], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoAllowDoubleValue], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoJsonParseDoNotTryCustomVariants], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoSerializeAsExtendedJson], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoSerializeAsExtendedJson, dvoJsonParseDoNotTryCustomVariants, dvoInternNames, dvoInternValues], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoNameCaseSensitive], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoNameCaseSensitive, dvoSerializeAsExtendedJson], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoNameCaseSensitive, dvoInternNames, dvoInternValues], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoNameCaseSensitive, dvoInternNames, dvoInternValues, dvoSerializeAsExtendedJson] );

Some convenient TDocVariant options, e.g. as JSON_[fDefault]


1.7.6. JSON_FAST_EXTENDED

JSON_FAST_EXTENDED: TDocVariantOptions;

TDocVariant options to be used so that JSON serialization would use the unquoted JSON syntax for field names
- you could use it e.g. on a TOrm variant published field to reduce the JSON escape process during storage in the database, by customizing your TOrmModel instance:

  (aModel.Props[TOrmMyRecord]['VariantProp'] as TOrmPropInfoRttiVariant).
    DocVariantOptions := JSON_FAST_EXTENDED;

or - in a cleaner way - by overriding TOrm.InternalDefineModel():

 class procedure TOrmMyRecord.InternalDefineModel(Props: TOrmProperties);
 begin
   (Props.Fields.ByName('VariantProp') as TOrmPropInfoRttiVariant).
     DocVariantOptions := JSON_FAST_EXTENDED;
 end;

or to set all variant fields at once:

 class procedure TOrmMyRecord.InternalDefineModel(Props: TOrmProperties);
 begin
   Props.SetVariantFieldsDocVariantOptions(JSON_FAST_EXTENDED);
 end;

- consider using JSON_NAMEVALUE[true] for case-sensitive TSynNameValue-like storage, or JSON_FAST_EXTENDEDINTERN if you expect RawUtf8 names and values interning


1.7.7. JSON_FAST_EXTENDEDINTERN

JSON_FAST_EXTENDEDINTERN: TDocVariantOptions;

TDocVariant options for JSON serialization with efficient storage
- i.e. unquoted JSON syntax for field names and RawUtf8 interning
- may be used e.g. for efficient persistence of similar data
- consider using JSON_FAST_EXTENDED if you don't expect RawUtf8 names and values interning, or need BSON variants parsing


1.7.8. JSON_FAST_STRICT

JSON_FAST_STRICT: TDocVariantOptions;

TDocVariant options which may be used for plain JSON parsing
- this won't recognize any extended syntax


1.7.9. JSON_NAMEVALUE

JSON_NAMEVALUE: TDocVariantOptionsBool;

TDocVariant options to be used for case-sensitive TSynNameValue-like storage, with optional extended JSON syntax serialization
- consider using JSON_FAST_EXTENDED for case-insensitive objects


1.7.10. JSON_NAMEVALUEINTERN

JSON_NAMEVALUEINTERN: TDocVariantOptionsBool;

TDocVariant options to be used for case-sensitive TSynNameValue-like storage, RawUtf8 interning and optional extended JSON syntax serialization
- consider using JSON_FAST_EXTENDED for case-insensitive objects, or JSON_NAMEVALUE[] if you don't expect names and values interning


1.7.11. JSON_OPTIONS

JSON_OPTIONS: TDocVariantOptionsBool;

- JSON_OPTIONS[false] is e.g. _Json() and _JsonFmt() functions default
- JSON_OPTIONS[true] are used e.g. by _JsonFast() and _JsonFastFmt() functions
- handle only currency for floating point values: use JSON_FAST_FLOAT/JSON_[mFastFloat] if you want to support double values, with potential precision loss


1.7.12. JSON_OPTIONS_FAST_STRICT

JSON_OPTIONS_FAST_STRICT: TDocVariantOptions absolute JSON_FAST_STRICT;

Some slightly more verbose backward compatible options


1.7.13. SynVariantTypes

SynVariantTypes: array of TSynInvokeableVariantType;

Internal list of our TSynInvokeableVariantType instances
- SynVariantTypes[0] is always DocVariantVType
- SynVariantTypes[1] is e.g. BsonVariantType from mormot.db.nosql.bson
- instances are owned by Variants.pas as TInvokeableVariantType instances
- is defined here for proper FindSynVariantType inlining