2017 © Pedro Peláez
 

project phpwind

使用 PHP 和 MySQL 开发的高性能社区系统。

image

medz/phpwind

使用 PHP 和 MySQL 开发的高性能社区系统。

  • Saturday, June 23, 2018
  • by medz
  • Repository
  • 22 Watchers
  • 161 Stars
  • 6 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 44 Forks
  • 37 Open issues
  • 17 Versions
  • 0 % Grown

The README.md

, (*1)

✨ OvO ✨

OvO is a Dart-first schema declaration and validation library. , (*2)

Introduction

OvO is a Dart-first schema declaration and validation library. We use the technical term "Schema" to define any data type, from simple single data (for example: string/int, etc.) to complex nested Map., (*3)

OvO is designed to be as user-friendly and developer-friendly as possible, with the goal of eliminating tedious type checking and object deserialization. It is easy to compose complex data structure validation using simple declaration validation., (*4)

several important aspects, (*5)

  • A fun walkthrough of Dart type extensions
  • Simple and chained interface calls
  • Can be used on any Dart platform (Dart, Web, Flutter)

Sponsors

I am very grateful and encouraged for any level of sponsorship, which will help me continue to develop and maintain this project., (*6)

Installation

We are more aggressive and use higher versions of Dart stable versions as much as possible., (*7)

Install from command line

# Dart project
dart pub add ovo

# Flutter project
flutter pub add ovo

Install from pubspec.yaml

dependencies:
  ovo: latest

Basic Usage

Create a simple string schema:, (*8)

import 'package:ovo/ovo.dart' as ovo;

// Create a schema for string.
final schema = ovo.String();

// Parsing
await schema.parse('Hello World'); // => 'Hello World'
await schema.parse(123); // => throws OvOException

Creating an JSON schema:, (*9)

import 'package:ovo/ovo.dart' as ovo;

final schema = ovo.Object({
    'name': ovo.String(),
});

await schema.parse({
    'name': 'John',
}); // => {'name': 'John'}

Types

OvO provides type validation with dependent type parameters, and also built-in some common types. You can declare a type validation by OvO<T>, where T is a type parameter and can be any type., (*10)

Let's try to create a String type validation:, (*11)

import 'package:ovo/ovo.dart' as ovo;

final schema = ovo.OvO<String>();

await schema.parse('Hello World'); // => 'Hello World'
await schema.parse(123); // => throws OvOException

Or, we create a validation of Record type that is not built-in:, (*12)

import 'package:ovo/ovo.dart' as ovo;

final schema = ovo.OvO<(int, String)>();

await schema.parse((123, 'Hello World')); // => (123, 'Hello World')

Of course, you can also use it to validate a custom class:, (*13)

import 'package:ovo/ovo.dart' as ovo;

class User {
    final String name;
    final int age;

    User(this.name, this.age);
}

final schema = ovo.OvO<User>();

await schema.parse(User('John', 18)); // => User('John', 18)

Basic type validation depends on the built-in is keyword in Dart, which is fully capable of most type validation. However, if you need more complex type validation, you can use the constructor of OvO<T> to create a custom type validation., (*14)

import 'package:ovo/ovo.dart' as ovo;

class User {
    final String name;
    final int age;

    User(this.name, this.age);

    factory User.fromJson(Map<String, dynamic> json) {
        return User(json['name'], json['age']);
    }
}

class MyOvO implements ovo.OvO<User> {
    @override
    Future<User> parse(ovo.Context, dynamic value) {
        if (value is Map<String, dynamic>) {
            return User.fromJson(value);
        }
        throw ovo.OvOException('Invalid value');
    }
}

final schema = ovo.Object({
    'data': MyOvO(),
    'status': ovo.Boolean(),
});

final data = {
    'data': {
        'name': 'John',
        'age': 18,
    },
    'status': true,
};

await schema.parse(data); // => {'data': User('John', 18), 'status': true}

Any

Any type validation can accept a non-null value of any type. It is an alias of OvO<Object>., (*15)

Array

Array type validation can accept an iterable value (for example: List, Set, Iterable, etc.). It is not an alias of OvO<Iterable<T>>, but a specific type validation., (*16)

Array accepts a parameter of type OvO<T> to validate each element in the array., (*17)

import 'package:ovo/ovo.dart' as ovo;

final schema = ovo.Array(ovo.String());

await schema.parse(['Hello', 'World']); // => ['Hello', 'World']
await schema.parse([123, 456]); // => throws OvOException

.min/.max/.size

.min/.max/.size have the same parameters and type signatures, and they all accept a parameter of type int to validate the length of the array., (*18)

  • .min validates that the length of the array must be greater than or equal to the specified length.
  • .max validates that the length of the array must be less than or equal to the specified length.
  • .size validates that the length of the array must be equal to the specified length.
ovo.Array(ovo.String()).min(2); // must contain at least 2 elements
ovo.Array(ovo.String()).max(2); // must contain no more than 2 elements
ovo.Array(ovo.String()).size(2); // must contain exactly 2 elements

.unique

.unique validates that the elements in the array must be unique, similar to Set in Dart., (*19)

ovo.Array(ovo.String()).unique(); // must contain unique elements

Boolean

Boolean type validation can accept a value of type bool. It is an alias of OvO<bool>., (*20)

另外,他还有两个额外的扩展方法:, (*21)

In addition, it has two additional extension methods:, (*22)

  • .isTrue - 验证值必须为 true
  • .isFalse - 验证值必须为 false。, (*23)

  • .isTrue - validates that the value must be true., (*24)

  • .isFalse - validates that the value must be false.
ovo.Boolean(); // must be a boolean, `true` or `false`
ovo.Boolean().isTrue(); // must be true
ovo.Boolean().isFalse(); // must be false

Of course, you can use OvO<bool> instead of Boolean type validation, but Boolean type validation is more semantic., (*25)

Number

Number type validation can accept a value of type num. It is an alias of OvO<num>., (*26)

ovo.Number(); // must be a number, `int` or `double`

If you need to validate an integer, you can use the Integer type validation, which is an alias of OvO<int>. To validate a floating-point number, you can use the Double type validation, which is an alias of OvO<double>., (*27)

Integer and Double are both subtypes of Number:, (*28)

ovo.Integer(); // must be an integer, `int`
ovo.Double(); // must be a double, `double`

OvO<num> also contains some additional methods:, (*29)

ovo.Number().gt(10); // must be greater than 10
ovo.Number().gte(10); // must be greater than or equal to 10
ovo.Number().lt(10); // must be less than 10
ovo.Number().lte(10); // must be less than or equal to 10
ovo.Number().finite(); // must be finite
ovo.Number().negative(); // must be negative

String

String type validation can accept a value of type String. It is an alias of OvO<String>., (*30)

ovo.String(); // must be a string, `String`

OvO<String> also contains some additional methods:, (*31)

// Validations
ovo.String().min(5); // must be at least 5 characters long
ovo.String().max(5); // must be no more than 5 characters long
ovo.String().length(5); // must be exactly 5 characters long
ovo.String().regex(RegExp(r'^[a-z]+$')); // must match the regular expression
ovo.String().contains('abc'); // must contain the substring
ovo.String().isNotEmpty(); // must not be empty
ovo.String().startsWith('abc'); // must start with the substring
ovo.String().endsWith('abc'); // must end with the substring
ovo.String().equals('abc'); // must be equal to the string

// Transformations
ovo.String().trim(); // trim whitespace
ovo.String().toLowerCase(); // convert to lowercase
ovo.String().toUpperCase(); // convert to uppercase

Object

Object type validation can accept a value of type Map. It is an implementation of OvO<Map<String, T>>., (*32)

import 'package:ovo/ovo.dart' as ovo;

final user = ovo.Object({
    'name': ovo.String(),
    'age': ovo.Number(),
});

await user.parse({
    'name': 'John',
    'age': 18,
}); // => {'name': 'John', 'age': 18}

await user.parse({
    'name': 'John',
    'age': '18',
}); // => throws OvOException

Of course, if you just want to simply validate a value of type Map<K, T>, you can use OvO<Map<K, T>> instead of Object type validation., (*33)

import 'package:ovo/ovo.dart' as ovo;

final user = ovo.OvO<Map<String, dynamic>>();

await user.parse({
    'name': 'John',
    'age': 18,
}); // => {'name': 'John', 'age': 18}

await user.parse({
    'name': 'John',
    'age': '18',
}); // => {'name': 'John', 'age': '18'}

Functional

.nullable

The .nullable method can convert a type validation to a type validation that accepts null., (*34)

ovo.String().nullable(); // must be a string or null

.refine

.refine is a method that allows you to customize the validation. It accepts a validation function of FutureOr<bool> Function(T data) to facilitate validation according to the actual situation., (*35)

ovo.String().refine(
    (value) => value.length > 5,
    message: 'must be greater than 5',
); // must be a string and length greater than 5

It is worth noting that many of the built-in extension methods are implemented based on the .refine method., (*36)

.transform

.transform is a method that allows you to customize the method of converting data types. It works on the principle of Onion Model., (*37)

Pre-transformation

Pre-transformation allows you to pre-process the raw data to be parsed, and then hand it over to the next converter, and finally hand it over to the type validator for verification:, (*38)


final schema = ovo.String().transform( (ovo.Context context, dynamic data, Future<T> Function(dynamic data) next) { // data convert to string return next(data.toString()); } ); await schema.parse(123); // => '123' await schema.parse(#symbol); // => '#symbol'

Post-transformation

Using the next parameter in the callback, you can perform post-transformation of the data after the type validator is verified successfully:, (*39)

final schema = ovo.String().transform(
    (ovo.Context context, dynamic data, Future<T> Function(dynamic data) next) async {
        final value = await next(data);

        // value convert to int
        return int.parse(value);
    }
);

await schema.parse('123'); // => 123

.withDefault

.withDefault allows a nullable value T? to be replaced with a default value T when the value is null., (*40)

final schema = ovo.String().withDefault('Hello World'); // must be a string or null, default value is 'Hello World'

await schema.parse(null); // => 'Hello World'
await schema.parse('Hello'); // => 'Hello'

As you can see, the .withDefault method will automatically attach the .nullable method, so you don't need to call the .nullable method manually., (*41)

Compositions

AnyOf (OR)

AnyOf type validation can accept any of the multiple type validations., (*42)

ovo.AnyOf([
    ovo.String(),
    ovo.Integer(),
]); // must be a string or an integer

AllOf (AND)

AllOf type validation can accept all types in multiple type validations., (*43)

ovo.AllOf([
    ovo.Double(),
    ovo.Integer(),
]); // must be a double and an integer

OneOf (XOR)

OneOf type validation can accept one type in multiple type validations. If multiple validations match, an exception is thrown., (*44)

final schema = ovo.OneOf([
    ovo.String().size(5),
    ovo.String().size(10),
]);

await schema.parse('12345'); // => '12345'
await schema.parse('1234567890'); // => '1234567890'
await schema.parse('123456'); // => throws OvOException

Not (NOT)

Not type validation can accept any type validation, but if the specified type validation is matched, an exception is thrown., (*45)

final schema = ovo.Not(ovo.String());

await schema.parse(123); // => 123
await schema.parse({'name': 'Seven'}) // => {'name': 'Seven'}
await schema.parse('123'); // => throws OvOException

Const

Const type validation can accept a constant value., (*46)

ovo.Const(123); // must be 123

Using Const we can implement string literals in JSON:, (*47)

final schema = ovo.OneOf([
    ovo.Const('mobile'),
    ovo.Const('web'),
]);

await schema.parse('mobile'); // => 'mobile'
await schema.parse('web'); // => 'web'

Used in conjunction with conversion, we can implement Enum type validation:, (*48)

enum MyEnum {
    mobile,
    web,
}

final schema = ovo.OneOf(
    MyEnum.values.map((e) => ovo.Const(e.name)),
).transform<MyEnum>(
    (ovo.Context context, dynamic data, Future<T> Function(dynamic data) next) async {
        final value = await next(data);

        return MyEnum.values.firstWhere((e) => e.name == value);
    }
);

await schema.parse('mobile'); // => MyEnum.mobile
await schema.parse('web'); // => MyEnum.web
await schema.parse('desktop'); // => throws OvOException

The Versions

13/01 2018

1.0.x-dev

1.0.9999999.9999999-dev http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

php medz phpwind

18/06 2017

v1.1.0-alpha.2

1.1.0.0-alpha2 https://medz.github.io/phpwind/

使用 PHP 和 MySQL 开发的高性能社区系统。

  Sources   Download

MIT

The Requires

 

The Development Requires

php medz phpwind

30/05 2017

v1.1.0-alpha.1

1.1.0.0-alpha1 https://medz.github.io/phpwind/

使用 PHP 和 MySQL 开发的高性能社区系统。

  Sources   Download

MIT

The Requires

 

The Development Requires

php medz phpwind

12/03 2017

1.0.10

1.0.10.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

php medz phpwind

03/03 2017

v1.0.9

1.0.9.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

php medz phpwind

03/02 2017

v1.0.8

1.0.8.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

php medz phpwind

27/12 2016

v1.0.7

1.0.7.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

php medz phpwind

09/12 2016

v1.0.6

1.0.6.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

php medz phpwind

23/11 2016

v1.0.5

1.0.5.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

The Development Requires

php medz phpwind

16/11 2016

v1.0.4

1.0.4.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

The Development Requires

php medz phpwind

14/11 2016

v1.0.2

1.0.2.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

The Development Requires

php medz phpwind

08/11 2016

v1.0.1

1.0.1.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

The Development Requires

php medz phpwind

07/11 2016

v1.0.0

1.0.0.0 http://www.phpwind.com

采用PHP+MySQL方式运行的开源社区程序

  Sources   Download

MIT

The Requires

 

The Development Requires

php medz phpwind