add: adding collections package
This commit is contained in:
parent
56743e5b56
commit
f82eb07b64
11 changed files with 562 additions and 0 deletions
7
packages/collections/.gitignore
vendored
Normal file
7
packages/collections/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# https://dart.dev/guides/libraries/private-files
|
||||||
|
# Created by `dart pub`
|
||||||
|
.dart_tool/
|
||||||
|
|
||||||
|
# Avoid committing pubspec.lock for library packages; see
|
||||||
|
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||||
|
pubspec.lock
|
3
packages/collections/CHANGELOG.md
Normal file
3
packages/collections/CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
- Initial version.
|
10
packages/collections/LICENSE.md
Normal file
10
packages/collections/LICENSE.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
The Laravel Framework is Copyright (c) Taylor Otwell
|
||||||
|
The Fabric Framework is Copyright (c) Vieo, Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
91
packages/collections/README.md
Normal file
91
packages/collections/README.md
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
# Platform Collections
|
||||||
|
|
||||||
|
A Dart implementation of Laravel-inspired collections, providing a fluent, convenient wrapper for working with arrays of data.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Chainable methods for manipulating collections of data
|
||||||
|
- Type-safe operations
|
||||||
|
- Null-safe implementation
|
||||||
|
- Inspired by Laravel's collection methods
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Add this package to your `pubspec.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
platform_collections: ^1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run `dart pub get` or `flutter pub get` to install the package.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Here's a simple example of how to use the `Collection` class:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'package:platform_collections/platform_collections.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
final numbers = Collection([1, 2, 3, 4, 5]);
|
||||||
|
|
||||||
|
// Using various collection methods
|
||||||
|
final result = numbers
|
||||||
|
.whereCustom((n) => n % 2 == 0)
|
||||||
|
.mapCustom((n) => n * 2)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
print(result); // [4, 8]
|
||||||
|
|
||||||
|
// Chaining methods
|
||||||
|
final sum = numbers
|
||||||
|
.whereCustom((n) => n > 2)
|
||||||
|
.fold(0, (prev, curr) => prev + curr);
|
||||||
|
|
||||||
|
print(sum); // 12
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available Methods
|
||||||
|
|
||||||
|
- `all()`: Returns all items in the collection
|
||||||
|
- `avg()`: Calculates the average of the collection
|
||||||
|
- `chunk()`: Chunks the collection into smaller collections
|
||||||
|
- `collapse()`: Collapses a collection of arrays into a single collection
|
||||||
|
- `concat()`: Concatenates the given array or collection
|
||||||
|
- `contains()`: Determines if the collection contains a given item
|
||||||
|
- `count()`: Returns the total number of items in the collection
|
||||||
|
- `each()`: Iterates over the items in the collection
|
||||||
|
- `everyNth()`: Creates a new collection consisting of every n-th element
|
||||||
|
- `except()`: Returns all items except for those with the specified keys
|
||||||
|
- `filter()` / `whereCustom()`: Filters the collection using a callback
|
||||||
|
- `first()` / `firstWhere()`: Returns the first element that passes the given truth test
|
||||||
|
- `flatten()`: Flattens a multi-dimensional collection
|
||||||
|
- `flip()`: Flips the items in the collection
|
||||||
|
- `fold()`: Reduces the collection to a single value
|
||||||
|
- `groupBy()`: Groups the collection's items by a given key
|
||||||
|
- `join()`: Joins the items in a collection
|
||||||
|
- `last()` / `lastOrNull()`: Returns the last element in the collection
|
||||||
|
- `map()` / `mapCustom()`: Runs a map over each of the items
|
||||||
|
- `mapSpread()`: Runs a map over each nested chunk of items
|
||||||
|
- `max()`: Returns the maximum value in the collection
|
||||||
|
- `merge()`: Merges the given array into the collection
|
||||||
|
- `min()`: Returns the minimum value in the collection
|
||||||
|
- `only()`: Returns only the items from the collection with the specified keys
|
||||||
|
- `pluck()`: Retrieves all of the collection values for a given key
|
||||||
|
- `random()`: Returns a random item from the collection
|
||||||
|
- `reverse()`: Reverses the order of the collection's items
|
||||||
|
- `search()`: Searches the collection for a given value
|
||||||
|
- `shuffle()`: Shuffles the items in the collection
|
||||||
|
- `slice()`: Returns a slice of the collection
|
||||||
|
- `sort()` / `sortCustom()`: Sorts the collection
|
||||||
|
- `take()`: Takes the first or last {n} items
|
||||||
|
|
||||||
|
## Additional Information
|
||||||
|
|
||||||
|
For more detailed examples, please refer to the `example/collections_example.dart` file in the package.
|
||||||
|
|
||||||
|
If you encounter any issues or have feature requests, please file them on the [issue tracker](https://github.com/yourusername/platform_collections/issues).
|
||||||
|
|
||||||
|
Contributions are welcome! Please read our [contributing guidelines](https://github.com/yourusername/platform_collections/blob/main/CONTRIBUTING.md) before submitting a pull request.
|
21
packages/collections/analysis_options.yaml
Normal file
21
packages/collections/analysis_options.yaml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
include: package:lints/recommended.yaml
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
exclude:
|
||||||
|
- "**/*.g.dart"
|
||||||
|
- "**/*.freezed.dart"
|
||||||
|
language:
|
||||||
|
strict-casts: true
|
||||||
|
strict-raw-types: true
|
||||||
|
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
- always_declare_return_types
|
||||||
|
- cancel_subscriptions
|
||||||
|
- close_sinks
|
||||||
|
- comment_references
|
||||||
|
- one_member_abstracts
|
||||||
|
- only_throw_errors
|
||||||
|
- package_api_docs
|
||||||
|
- prefer_final_in_for_each
|
||||||
|
- prefer_single_quotes
|
65
packages/collections/example/collections_example.dart
Normal file
65
packages/collections/example/collections_example.dart
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import 'package:platform_collections/platform_collections.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Create a new collection
|
||||||
|
final numbers = Collection([1, 2, 3, 4, 5]);
|
||||||
|
|
||||||
|
print('Original collection: ${numbers.all()}');
|
||||||
|
|
||||||
|
// Demonstrate some collection methods
|
||||||
|
print('Average: ${numbers.avg()}');
|
||||||
|
print('Chunks of 2: ${numbers.chunk(2).map((chunk) => chunk.all())}');
|
||||||
|
print('Every 2nd item: ${numbers.everyNth(2).all()}');
|
||||||
|
print('Except indices [1, 3]: ${numbers.except([1, 3]).all()}');
|
||||||
|
print('First even number: ${numbers.firstWhere((n) => n % 2 == 0)}');
|
||||||
|
print('Reversed: ${numbers.reverse().all()}');
|
||||||
|
|
||||||
|
// Demonstrate map and filter operations
|
||||||
|
final doubled = numbers.mapCustom((n) => n * 2);
|
||||||
|
print('Doubled: ${doubled.all()}');
|
||||||
|
|
||||||
|
final evenNumbers = numbers.whereCustom((n) => n % 2 == 0);
|
||||||
|
print('Even numbers: ${evenNumbers.all()}');
|
||||||
|
|
||||||
|
// Demonstrate reduce operation
|
||||||
|
final sum = numbers.fold<int>(0, (prev, curr) => prev + curr);
|
||||||
|
print('Sum: $sum');
|
||||||
|
|
||||||
|
// Demonstrate sorting
|
||||||
|
final sortedDesc = numbers.sortCustom((a, b) => b.compareTo(a));
|
||||||
|
print('Sorted descending: ${sortedDesc.all()}');
|
||||||
|
|
||||||
|
// Demonstrate search
|
||||||
|
final searchResult = numbers.search(3);
|
||||||
|
print('Index of 3: $searchResult');
|
||||||
|
|
||||||
|
// Demonstrate JSON conversion
|
||||||
|
print('JSON representation: ${numbers.toJson()}');
|
||||||
|
|
||||||
|
// Demonstrate operations with non-numeric collections
|
||||||
|
final fruits = Collection(['apple', 'banana', 'cherry', 'date']);
|
||||||
|
print('\nFruits: ${fruits.all()}');
|
||||||
|
print(
|
||||||
|
'Fruits starting with "b": ${fruits.whereCustom((f) => f.startsWith('b')).all()}');
|
||||||
|
print(
|
||||||
|
'Fruit names in uppercase: ${fruits.mapCustom((f) => f.toUpperCase()).all()}');
|
||||||
|
|
||||||
|
// Demonstrate nested collections
|
||||||
|
final nested = Collection([
|
||||||
|
[1, 2],
|
||||||
|
[3, 4],
|
||||||
|
[5, 6],
|
||||||
|
]);
|
||||||
|
print('\nNested collection: ${nested.all()}');
|
||||||
|
print('Flattened: ${nested.flatten().all()}');
|
||||||
|
|
||||||
|
// Demonstrate grouping
|
||||||
|
final people = Collection([
|
||||||
|
{'name': 'Alice', 'age': 25},
|
||||||
|
{'name': 'Bob', 'age': 30},
|
||||||
|
{'name': 'Charlie', 'age': 25},
|
||||||
|
{'name': 'David', 'age': 30},
|
||||||
|
]);
|
||||||
|
final groupedByAge = people.groupBy((person) => person['age']);
|
||||||
|
print('\nPeople grouped by age: $groupedByAge');
|
||||||
|
}
|
3
packages/collections/lib/collections.dart
Normal file
3
packages/collections/lib/collections.dart
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
library collections;
|
||||||
|
|
||||||
|
export 'src/collection.dart';
|
3
packages/collections/lib/platform_collections.dart
Normal file
3
packages/collections/lib/platform_collections.dart
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
library platform_collections;
|
||||||
|
|
||||||
|
export 'src/collection.dart';
|
262
packages/collections/lib/src/collection.dart
Normal file
262
packages/collections/lib/src/collection.dart
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
import 'dart:collection';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
/// A collection class inspired by Laravel's Collection, implemented in Dart.
|
||||||
|
class Collection<T> with ListMixin<T> {
|
||||||
|
final List<T> _items;
|
||||||
|
|
||||||
|
/// Creates a new [Collection] instance.
|
||||||
|
Collection([Iterable<T>? items]) : _items = List<T>.from(items ?? <T>[]);
|
||||||
|
|
||||||
|
/// Creates a new [Collection] instance from a [Map].
|
||||||
|
factory Collection.fromMap(Map<dynamic, T> map) {
|
||||||
|
return Collection(map.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get length => _items.length;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set length(int newLength) {
|
||||||
|
_items.length = newLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
T operator [](int index) => _items[index];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void operator []=(int index, T value) {
|
||||||
|
_items[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns all items in the collection.
|
||||||
|
List<T> all() => _items.toList();
|
||||||
|
|
||||||
|
/// Returns the average value of the collection.
|
||||||
|
double? avg([num Function(T element)? callback]) {
|
||||||
|
if (isEmpty) return null;
|
||||||
|
num sum = 0;
|
||||||
|
for (final item in _items) {
|
||||||
|
sum += callback != null ? callback(item) : (item as num);
|
||||||
|
}
|
||||||
|
return sum / length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Chunks the collection into smaller collections of a given size.
|
||||||
|
Collection<Collection<T>> chunk(int size) {
|
||||||
|
return Collection(
|
||||||
|
List.generate(
|
||||||
|
(length / size).ceil(),
|
||||||
|
(index) => Collection(_items.skip(index * size).take(size)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collapses a collection of arrays into a single, flat collection.
|
||||||
|
Collection<dynamic> collapse() {
|
||||||
|
return Collection(_items.expand((e) => e is Iterable ? e : [e]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether the collection contains a given item.
|
||||||
|
@override
|
||||||
|
bool contains(Object? item) => _items.contains(item);
|
||||||
|
|
||||||
|
/// Returns the total number of items in the collection.
|
||||||
|
int count() => length;
|
||||||
|
|
||||||
|
/// Executes a callback over each item.
|
||||||
|
void each(void Function(T item) callback) {
|
||||||
|
for (final item in _items) {
|
||||||
|
callback(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new collection consisting of every n-th element.
|
||||||
|
Collection<T> everyNth(int step) {
|
||||||
|
return Collection(_items.where((item) => _items.indexOf(item) % step == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns all items except for those with the specified keys.
|
||||||
|
Collection<T> except(List<int> keys) {
|
||||||
|
return Collection(
|
||||||
|
_items.where((item) => !keys.contains(_items.indexOf(item))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Filters the collection using the given callback.
|
||||||
|
Collection<T> whereCustom(bool Function(T element) test) {
|
||||||
|
return Collection(_items.where(test));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the first element in the collection that passes the given truth test.
|
||||||
|
@override
|
||||||
|
T firstWhere(bool Function(T element) test, {T Function()? orElse}) {
|
||||||
|
return _items.firstWhere(test, orElse: orElse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flattens a multi-dimensional collection into a single dimension.
|
||||||
|
Collection<dynamic> flatten({int depth = 1}) {
|
||||||
|
List<dynamic> flattenHelper(dynamic item, int currentDepth) {
|
||||||
|
if (currentDepth == 0 || item is! Iterable) return [item];
|
||||||
|
return item.expand((e) => flattenHelper(e, currentDepth - 1)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collection(
|
||||||
|
flattenHelper(_items, depth).expand((e) => e is Iterable ? e : [e]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flips the items in the collection.
|
||||||
|
Collection<T> flip() {
|
||||||
|
return Collection(_items.reversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes an item from the collection by its key.
|
||||||
|
T? pull(int index) {
|
||||||
|
if (index < 0 || index >= length) return null;
|
||||||
|
return removeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Concatenates the given array or collection with the original collection.
|
||||||
|
Collection<T> concat(Iterable<T> items) {
|
||||||
|
return Collection([..._items, ...items]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reduces the collection to a single value.
|
||||||
|
@override
|
||||||
|
U fold<U>(U initialValue, U Function(U previousValue, T element) combine) {
|
||||||
|
return _items.fold(initialValue, combine);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Groups the collection's items by a given key.
|
||||||
|
Map<K, List<T>> groupBy<K>(K Function(T element) keyFunction) {
|
||||||
|
return _items.fold<Map<K, List<T>>>({}, (map, element) {
|
||||||
|
final key = keyFunction(element);
|
||||||
|
map.putIfAbsent(key, () => []).add(element);
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Joins the items in a collection with a string.
|
||||||
|
@override
|
||||||
|
String join([String separator = '']) => _items.join(separator);
|
||||||
|
|
||||||
|
/// Returns a new collection with the keys of the collection items.
|
||||||
|
Collection<int> keys() => Collection(List.generate(length, (index) => index));
|
||||||
|
|
||||||
|
/// Returns the last element in the collection.
|
||||||
|
T? lastOrNull() => isNotEmpty ? _items.last : null;
|
||||||
|
|
||||||
|
/// Runs a map over each of the items.
|
||||||
|
Collection<R> mapCustom<R>(R Function(T e) toElement) {
|
||||||
|
return Collection(_items.map(toElement));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a map over each nested chunk of items.
|
||||||
|
Collection<R> mapSpread<R>(R Function(dynamic e) toElement) {
|
||||||
|
return Collection(_items
|
||||||
|
.expand((e) => e is Iterable ? e.map(toElement) : [toElement(e)]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the maximum value of a given key.
|
||||||
|
T? max([Comparable<dynamic> Function(T element)? callback]) {
|
||||||
|
if (isEmpty) return null;
|
||||||
|
return _items.reduce((a, b) {
|
||||||
|
final compareA =
|
||||||
|
callback != null ? callback(a) : a as Comparable<dynamic>;
|
||||||
|
final compareB =
|
||||||
|
callback != null ? callback(b) : b as Comparable<dynamic>;
|
||||||
|
return compareA.compareTo(compareB) > 0 ? a : b;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the minimum value of a given key.
|
||||||
|
T? min([Comparable<dynamic> Function(T element)? callback]) {
|
||||||
|
if (isEmpty) return null;
|
||||||
|
return _items.reduce((a, b) {
|
||||||
|
final compareA =
|
||||||
|
callback != null ? callback(a) : a as Comparable<dynamic>;
|
||||||
|
final compareB =
|
||||||
|
callback != null ? callback(b) : b as Comparable<dynamic>;
|
||||||
|
return compareA.compareTo(compareB) < 0 ? a : b;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns only the items from the collection with the specified keys.
|
||||||
|
Collection<T> only(List<int> keys) {
|
||||||
|
return Collection(
|
||||||
|
_items.where((item) => keys.contains(_items.indexOf(item))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves all of the collection values for a given key.
|
||||||
|
Collection<R> pluck<R>(R Function(T element) callback) {
|
||||||
|
return Collection(_items.map(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes and returns the last item from the collection.
|
||||||
|
T? pop() => isNotEmpty ? removeLast() : null;
|
||||||
|
|
||||||
|
/// Adds an item to the beginning of the collection.
|
||||||
|
void prepend(T value) => insert(0, value);
|
||||||
|
|
||||||
|
/// Adds an item to the end of the collection.
|
||||||
|
void push(T value) => add(value);
|
||||||
|
|
||||||
|
/// Returns a random item from the collection.
|
||||||
|
T? random() => isEmpty ? null : this[_getRandomIndex()];
|
||||||
|
|
||||||
|
/// Reverses the order of the collection's items.
|
||||||
|
Collection<T> reverse() => Collection(_items.reversed);
|
||||||
|
|
||||||
|
/// Searches the collection for a given value and returns the corresponding key if successful.
|
||||||
|
int? search(T item, {bool Function(T, T)? compare}) {
|
||||||
|
compare ??= (a, b) => a == b;
|
||||||
|
final index = _items.indexWhere((element) => compare!(element, item));
|
||||||
|
return index != -1 ? index : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shuffles the items in the collection.
|
||||||
|
@override
|
||||||
|
void shuffle([Random? random]) {
|
||||||
|
_items.shuffle(random);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a slice of the collection starting at the given index.
|
||||||
|
Collection<T> slice(int offset, [int? length]) {
|
||||||
|
return Collection(
|
||||||
|
_items.skip(offset).take(length ?? _items.length - offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sorts the collection.
|
||||||
|
Collection<T> sortCustom([int Function(T a, T b)? compare]) {
|
||||||
|
final sorted = [..._items];
|
||||||
|
sorted.sort(compare);
|
||||||
|
return Collection(sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes the first or last {n} items.
|
||||||
|
@override
|
||||||
|
Collection<T> take(int count) {
|
||||||
|
if (count < 0) {
|
||||||
|
return Collection(_items.skip(_items.length + count));
|
||||||
|
}
|
||||||
|
return Collection(_items.take(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a JSON representation of the collection.
|
||||||
|
String toJson() =>
|
||||||
|
'[${_items.map((e) => e is Map ? _mapToJson(e as Map<dynamic, dynamic>) : e.toString()).join(',')}]';
|
||||||
|
|
||||||
|
/// Merges the given array or collection with the original collection.
|
||||||
|
Collection<T> merge(Iterable<T> items) {
|
||||||
|
return Collection([..._items, ...items]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods
|
||||||
|
int _getRandomIndex() =>
|
||||||
|
(DateTime.now().millisecondsSinceEpoch % length).abs();
|
||||||
|
|
||||||
|
String _mapToJson(Map<dynamic, dynamic> map) {
|
||||||
|
final pairs = map.entries.map((e) =>
|
||||||
|
'"${e.key}":${e.value is Map ? _mapToJson(e.value as Map<dynamic, dynamic>) : '"${e.value}"'}');
|
||||||
|
return '{${pairs.join(',')}}';
|
||||||
|
}
|
||||||
|
}
|
13
packages/collections/pubspec.yaml
Normal file
13
packages/collections/pubspec.yaml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
name: platform_collections
|
||||||
|
description: A Dart implementation of Laravel-inspired collections.
|
||||||
|
version: 1.0.0
|
||||||
|
homepage: https://github.com/yourusername/collections
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
|
||||||
|
dependencies: {}
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
test: ^1.16.0
|
||||||
|
lints: ^2.0.0
|
84
packages/collections/test/collection_test.dart
Normal file
84
packages/collections/test/collection_test.dart
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import 'package:platform_collections/platform_collections.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('Collection', () {
|
||||||
|
test('creates a collection from a list', () {
|
||||||
|
final collection = Collection([1, 2, 3]);
|
||||||
|
expect(collection.all(), equals([1, 2, 3]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('avg calculates the average', () {
|
||||||
|
final collection = Collection([1, 2, 3, 4, 5]);
|
||||||
|
expect(collection.avg(), equals(3));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('chunk splits the collection into smaller collections', () {
|
||||||
|
final collection = Collection([1, 2, 3, 4, 5]);
|
||||||
|
final chunked = collection.chunk(2);
|
||||||
|
expect(
|
||||||
|
chunked.map((c) => c.all()),
|
||||||
|
equals([
|
||||||
|
[1, 2],
|
||||||
|
[3, 4],
|
||||||
|
[5]
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('whereCustom filters the collection', () {
|
||||||
|
final collection = Collection([1, 2, 3, 4, 5]);
|
||||||
|
final filtered = collection.whereCustom((n) => n % 2 == 0);
|
||||||
|
expect(filtered.all(), equals([2, 4]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mapCustom transforms the collection', () {
|
||||||
|
final collection = Collection([1, 2, 3]);
|
||||||
|
final mapped = collection.mapCustom((n) => n * 2);
|
||||||
|
expect(mapped.all(), equals([2, 4, 6]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fold reduces the collection', () {
|
||||||
|
final collection = Collection([1, 2, 3, 4, 5]);
|
||||||
|
final sum = collection.fold<int>(0, (prev, curr) => prev + (curr as int));
|
||||||
|
expect(sum, equals(15));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sortCustom sorts the collection', () {
|
||||||
|
final collection = Collection([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]);
|
||||||
|
final sorted = collection.sortCustom((a, b) => a.compareTo(b));
|
||||||
|
expect(sorted.all(), equals([1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('flatten flattens nested collections', () {
|
||||||
|
final collection = Collection([
|
||||||
|
[1, 2],
|
||||||
|
[3, 4],
|
||||||
|
[5, 6]
|
||||||
|
]);
|
||||||
|
final flattened = collection.flatten();
|
||||||
|
expect(flattened.all(), equals([1, 2, 3, 4, 5, 6]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('groupBy groups collection items', () {
|
||||||
|
final collection = Collection([
|
||||||
|
{'name': 'Alice', 'age': 25},
|
||||||
|
{'name': 'Bob', 'age': 30},
|
||||||
|
{'name': 'Charlie', 'age': 25},
|
||||||
|
{'name': 'David', 'age': 30},
|
||||||
|
]);
|
||||||
|
final grouped = collection.groupBy((item) => item['age']);
|
||||||
|
expect(
|
||||||
|
grouped,
|
||||||
|
equals({
|
||||||
|
25: [
|
||||||
|
{'name': 'Alice', 'age': 25},
|
||||||
|
{'name': 'Charlie', 'age': 25}
|
||||||
|
],
|
||||||
|
30: [
|
||||||
|
{'name': 'Bob', 'age': 30},
|
||||||
|
{'name': 'David', 'age': 30}
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue