diff --git a/lib/kiota_abstractions.dart b/lib/kiota_abstractions.dart index 47b501a..5a48977 100644 --- a/lib/kiota_abstractions.dart +++ b/lib/kiota_abstractions.dart @@ -12,12 +12,16 @@ import 'dart:typed_data'; import 'package:kiota_abstractions/src/case_insensitive_map.dart'; import 'package:std_uritemplate/std_uritemplate.dart'; +import 'package:uuid/uuid.dart'; part 'src/api_client_builder.dart'; part 'src/base_request_builder.dart'; +part 'src/date_only.dart'; part 'src/error_mappings.dart'; +part 'src/extensions/date_only_extensions.dart'; part 'src/extensions/map_extensions.dart'; part 'src/extensions/request_information_extensions.dart'; +part 'src/extensions/time_only_extensions.dart'; part 'src/http_headers.dart'; part 'src/http_method.dart'; part 'src/multipart_body.dart'; @@ -41,4 +45,5 @@ part 'src/serialization/parse_node_proxy_factory.dart'; part 'src/serialization/serialization_writer.dart'; part 'src/serialization/serialization_writer_factory.dart'; part 'src/serialization/serialization_writer_factory_registry.dart'; +part 'src/time_only.dart'; part 'src/serialization/serialization_writer_proxy_factory.dart'; diff --git a/lib/src/date_only.dart b/lib/src/date_only.dart new file mode 100644 index 0000000..3c2a0fb --- /dev/null +++ b/lib/src/date_only.dart @@ -0,0 +1,67 @@ +part of '../kiota_abstractions.dart'; + +/// Interface for a date only object. +/// +/// This interface provides an abstraction layer over date only objects. +/// It is used to represent date only values in a serialization format agnostic +/// way. +/// +/// It can only be used to represent a date in the Gregorian calendar. +abstract class DateOnly { + /// Extracts the date part of a [DateTime] and creates an object implementing + /// [DateOnly]. + factory DateOnly.fromDateTime(DateTime dateTime) { + return _DateOnlyImpl( + day: dateTime.day, + month: dateTime.month, + year: dateTime.year, + ); + } + + /// This factory uses the [DateTime.parse] method to create an object + /// implementing [DateOnly]. + factory DateOnly.fromDateTimeString(String dateTimeString) { + final date = DateTime.parse(dateTimeString); + + return DateOnly.fromDateTime(date); + } + + /// Creates an object implementing [DateOnly] from the provided components. + factory DateOnly.fromComponents( + int year, [ + int month = 1, + int day = 1, + ]) { + return _DateOnlyImpl( + day: day, + month: month, + year: year, + ); + } + + /// Gets the year of the date. + int get year; + + /// Gets the month of the date. + int get month; + + /// Gets the day of the date. + int get day; +} + +class _DateOnlyImpl implements DateOnly { + _DateOnlyImpl({ + required this.day, + required this.month, + required this.year, + }); + + @override + final int day; + + @override + final int month; + + @override + final int year; +} diff --git a/lib/src/extensions/date_only_extensions.dart b/lib/src/extensions/date_only_extensions.dart new file mode 100644 index 0000000..6a4c1d2 --- /dev/null +++ b/lib/src/extensions/date_only_extensions.dart @@ -0,0 +1,25 @@ +part of '../../kiota_abstractions.dart'; + +/// Extension methods for [DateOnly]. +extension DateOnlyExtensions on DateOnly { + /// Converts the [DateOnly] to a [DateTime]. + DateTime toDateTime() => DateTime(year, month, day); + + /// Combines the [DateOnly] with the given [TimeOnly]. + DateTime combine(TimeOnly time) { + return DateTime( + year, + month, + day, + time.hours, + time.minutes, + time.seconds, + time.milliseconds, + ); + } + + /// Converts the [DateOnly] to a string in the format `yyyy-MM-dd`. + String toRfc3339String() { + return '${year.toString().padLeft(4, '0')}-${month.toString().padLeft(2, '0')}-${day.toString().padLeft(2, '0')}'; + } +} diff --git a/lib/src/extensions/time_only_extensions.dart b/lib/src/extensions/time_only_extensions.dart new file mode 100644 index 0000000..33f35f0 --- /dev/null +++ b/lib/src/extensions/time_only_extensions.dart @@ -0,0 +1,46 @@ +part of '../../kiota_abstractions.dart'; + +/// Extension methods for [TimeOnly]. +extension TimeOnlyExtensions on TimeOnly { + /// Converts the [TimeOnly] to a [DateTime]. + DateTime toDateTime( + int year, [ + int month = 1, + int day = 1, + ]) => + DateTime( + year, + month, + day, + hours, + minutes, + seconds, + milliseconds, + ); + + /// Combines the [TimeOnly] with the given [DateOnly]. + DateTime combine(DateOnly date) { + return DateTime( + date.year, + date.month, + date.day, + hours, + minutes, + seconds, + milliseconds, + ); + } + + /// Converts the [TimeOnly] to a string in the format `HH:mm:ss` or + /// `HH:mm:ss.SSS` if milliseconds are present. + String toRfc3339String() { + final String fractionString; + if (milliseconds > 0) { + fractionString = '.${milliseconds.toString().padLeft(3, '0')}'; + } else { + fractionString = ''; + } + + return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}$fractionString'; + } +} diff --git a/lib/src/serialization/parse_node.dart b/lib/src/serialization/parse_node.dart index 2b8f735..d511a16 100644 --- a/lib/src/serialization/parse_node.dart +++ b/lib/src/serialization/parse_node.dart @@ -19,9 +19,21 @@ abstract class ParseNode { /// Gets the double value of the node. double? getDoubleValue(); + /// Gets the [UuidValue] value of the node. + UuidValue? getGuidValue(); + /// Gets the [DateTime] value of the node. DateTime? getDateTimeValue(); + /// Gets the [DateOnly] value of the node. + DateOnly? getDateOnlyValue(); + + /// Gets the [TimeOnly] value of the node. + TimeOnly? getTimeOnlyValue(); + + /// Gets the [Duration] value of the node. + Duration? getDurationValue(); + /// Gets the collection of primitive values of the node. Iterable getCollectionOfPrimitiveValues(); diff --git a/lib/src/time_only.dart b/lib/src/time_only.dart new file mode 100644 index 0000000..6f0cb0b --- /dev/null +++ b/lib/src/time_only.dart @@ -0,0 +1,75 @@ +part of '../kiota_abstractions.dart'; + +/// Interface for a time only object that represents a time of day. +/// +/// This interface provides an abstraction layer over time only objects. +/// It is used to represent time only values in a serialization format agnostic +/// way. +abstract class TimeOnly { + /// Extracts the time part of a [DateTime] and creates an object implementing + /// [TimeOnly]. + factory TimeOnly.fromDateTime(DateTime dateTime) { + return _TimeOnlyImpl( + hours: dateTime.hour, + minutes: dateTime.minute, + seconds: dateTime.second, + milliseconds: dateTime.millisecond, + ); + } + + /// This factory uses the [DateTime.parse] method to create an object + /// implementing [TimeOnly]. + factory TimeOnly.fromDateTimeString(String dateTimeString) { + final dateTime = DateTime.parse('2024-01-01 $dateTimeString'); + + return TimeOnly.fromDateTime(dateTime); + } + + /// Constructs an object implementing [TimeOnly] from the provided components. + factory TimeOnly.fromComponents( + int hours, + int minutes, [ + int seconds = 0, + int milliseconds = 0, + ]) { + return _TimeOnlyImpl( + hours: hours, + minutes: minutes, + seconds: seconds, + milliseconds: milliseconds, + ); + } + + /// Gets the hours of the time. + int get hours; + + /// Gets the minutes of the time. + int get minutes; + + /// Gets the seconds of the time. + int get seconds; + + /// Gets the milliseconds of the time. + int get milliseconds; +} + +class _TimeOnlyImpl implements TimeOnly { + _TimeOnlyImpl({ + required this.hours, + required this.minutes, + required this.seconds, + required this.milliseconds, + }); + + @override + final int hours; + + @override + final int minutes; + + @override + final int seconds; + + @override + final int milliseconds; +} diff --git a/pubspec.yaml b/pubspec.yaml index 0d18921..7805a1a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,6 +15,7 @@ environment: dependencies: std_uritemplate: ^0.0.52 + uuid: ^4.3.3 dev_dependencies: strict: ^2.0.0 diff --git a/test/date_only_test.dart b/test/date_only_test.dart new file mode 100644 index 0000000..9432377 --- /dev/null +++ b/test/date_only_test.dart @@ -0,0 +1,40 @@ +// ignore_for_file: avoid_redundant_argument_values + +import 'package:kiota_abstractions/kiota_abstractions.dart'; +import 'package:test/test.dart'; + +void main() { + group('DateOnly', () { + test('fromDateTimeString and toRfc3339String', () { + expect( + DateOnly.fromDateTimeString('2021-01-01').toRfc3339String(), + '2021-01-01', + ); + }); + + test('round trip', () { + final fromString = DateOnly.fromDateTimeString('2021-01-01'); + final toString = fromString.toRfc3339String(); + expect(toString, '2021-01-01'); + + final roundTrip = DateOnly.fromDateTimeString(toString); + final roundTripString = roundTrip.toRfc3339String(); + expect(roundTripString, '2021-01-01'); + }); + + test('fromDateTime', () { + final dateTime = DateTime(2024, 2, 3, 12, 34, 56); + expect( + DateOnly.fromDateTime(dateTime).toRfc3339String(), + '2024-02-03', + ); + }); + + test('fromComponents', () { + expect( + DateOnly.fromComponents(2021, 1, 1).toRfc3339String(), + '2021-01-01', + ); + }); + }); +} diff --git a/test/time_only_test.dart b/test/time_only_test.dart new file mode 100644 index 0000000..a0ec647 --- /dev/null +++ b/test/time_only_test.dart @@ -0,0 +1,54 @@ +import 'package:kiota_abstractions/kiota_abstractions.dart'; +import 'package:test/test.dart'; + +void main() { + group('TimeOnly', () { + test('fromDateTimeString and toRfc3339String', () { + expect( + TimeOnly.fromDateTimeString('12:34:56').toRfc3339String(), + '12:34:56', + ); + expect( + TimeOnly.fromDateTimeString('12:34').toRfc3339String(), + '12:34:00', + ); + expect( + TimeOnly.fromDateTimeString('12').toRfc3339String(), + '12:00:00', + ); + }); + + test('round trip', () { + final fromString = TimeOnly.fromDateTimeString('12:34:56.789'); + final toString = fromString.toRfc3339String(); + expect(toString, '12:34:56.789'); + + final roundTrip = TimeOnly.fromDateTimeString(toString); + final roundTripString = roundTrip.toRfc3339String(); + expect(roundTripString, '12:34:56.789'); + }); + + test('fromDateTime', () { + final dateTime = DateTime(2021, 1, 1, 12, 34, 56); + expect( + TimeOnly.fromDateTime(dateTime).toRfc3339String(), + '12:34:56', + ); + }); + + test('fromComponents', () { + expect( + TimeOnly.fromComponents(12, 34, 56, 789).toRfc3339String(), + '12:34:56.789', + ); + expect( + TimeOnly.fromComponents(12, 34, 56).toRfc3339String(), + '12:34:56', + ); + expect( + TimeOnly.fromComponents(12, 34).toRfc3339String(), + '12:34:00', + ); + }); + }); +}