Skip to content

Commit

Permalink
Add @s.defaultWith
Browse files Browse the repository at this point in the history
  • Loading branch information
DZakh committed Dec 8, 2023
1 parent dece003 commit 2349fd9
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 33 deletions.
22 changes: 18 additions & 4 deletions packages/rescript-schema-ppx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ Specifies custom schema for the type.

```rescript
@schema
type url = @s.matches(S.string->S.String.url) string
type t = @s.matches(S.string->S.String.url) string
// Generated by PPX ⬇️
let urlSchema = S.string->S.String.url
let schema = S.string->S.String.url
```

### `@s.default('value)`
Expand All @@ -138,8 +138,22 @@ Wraps the type expression schema into an option with the provided default value.

```rescript
@schema
type stringWithDefault = @s.default("Unknown") string
type t = @s.default("Unknown") string
// Generated by PPX ⬇️
let stringWithDefaultSchema = S.option(S.string)->S.Option.getOr("Unknown")
let schema = S.option(S.string)->S.Option.getOr("Unknown")
```

### `@s.defaultWith(unit => 'value)`

**Applies to**: type expressions

Wraps the type expression schema into an option with callback to get the default value.

```rescript
@schema
type t = @s.defaultWith(() => []) array<string>
// Generated by PPX ⬇️
let schema = S.option(S.array(S.string))->S.Option.getOrWith(() => [])
```
9 changes: 9 additions & 0 deletions packages/rescript-schema-ppx/src/ppx/Structure.ml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ and generateCoreTypeSchemaExpression {ptyp_desc; ptyp_loc; ptyp_attributes} =
S.Option.getOr (S.option [%e schema_expression]) [%e default_value]]
| Error s -> fail ptyp_loc s
in
let schema_expression =
match getAttributeByName ptyp_attributes "s.defaultWith" with
| Ok None -> schema_expression
| Ok (Some attribute) ->
let default_cb = getExpressionFromPayload attribute in
[%expr
S.Option.getOrWith (S.option [%e schema_expression]) [%e default_cb]]
| Error s -> fail ptyp_loc s
in
schema_expression

let generateTypeDeclarationSchemaExpression type_declaration =
Expand Down
23 changes: 17 additions & 6 deletions packages/tests/src/ppx/Ppx_Example_test.bs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,33 @@ Ava("Main example", (function (t) {
}), undefined);
}));

var urlSchema = S$RescriptSchema.$$String.url(S$RescriptSchema.string, undefined);
var matchesSchema = S$RescriptSchema.$$String.url(S$RescriptSchema.string, undefined);

Ava("@s.matches", (function (t) {
U.assertEqualSchemas(t, urlSchema, S$RescriptSchema.$$String.url(S$RescriptSchema.string, undefined), undefined);
U.assertEqualSchemas(t, matchesSchema, S$RescriptSchema.$$String.url(S$RescriptSchema.string, undefined), undefined);
}));

var stringWithDefaultSchema = S$RescriptSchema.$$Option.getOr(S$RescriptSchema.option(S$RescriptSchema.string), "Unknown");
var defaultSchema = S$RescriptSchema.$$Option.getOr(S$RescriptSchema.option(S$RescriptSchema.string), "Unknown");

Ava("@s.default", (function (t) {
U.assertEqualSchemas(t, stringWithDefaultSchema, S$RescriptSchema.$$Option.getOr(S$RescriptSchema.option(S$RescriptSchema.string), "Unknown"), undefined);
U.assertEqualSchemas(t, defaultSchema, S$RescriptSchema.$$Option.getOr(S$RescriptSchema.option(S$RescriptSchema.string), "Unknown"), undefined);
}));

var defaultWithSchema = S$RescriptSchema.$$Option.getOrWith(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string)), (function () {
return [];
}));

Ava("@s.defaultWith", (function (t) {
U.assertEqualSchemas(t, defaultWithSchema, S$RescriptSchema.$$Option.getOrWith(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string)), (function () {
return [];
})), undefined);
}));

export {
ratingSchema ,
filmSchema ,
urlSchema ,
stringWithDefaultSchema ,
matchesSchema ,
defaultSchema ,
defaultWithSchema ,
}
/* ratingSchema Not a pure module */
17 changes: 13 additions & 4 deletions packages/tests/src/ppx/Ppx_Example_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,22 @@ test("Main example", t => {
})

@schema
type url = @s.matches(S.string->S.String.url) string
type matches = @s.matches(S.string->S.String.url) string
test("@s.matches", t => {
t->assertEqualSchemas(urlSchema, S.string->S.String.url)
t->assertEqualSchemas(matchesSchema, S.string->S.String.url)
})

@schema
type stringWithDefault = @s.default("Unknown") string
type default = @s.default("Unknown") string
test("@s.default", t => {
t->assertEqualSchemas(stringWithDefaultSchema, S.option(S.string)->S.Option.getOr("Unknown"))
t->assertEqualSchemas(defaultSchema, S.option(S.string)->S.Option.getOr("Unknown"))
})

@schema
type defaultWith = @s.defaultWith(() => []) array<string>
test("@s.defaultWith", t => {
t->assertEqualSchemas(
defaultWithSchema,
S.option(S.array(S.string))->S.Option.getOrWith(() => []),
)
})
26 changes: 9 additions & 17 deletions packages/tests/src/utils/U.bs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,15 @@ function cleanUpSchema(schema) {
Object.entries(schema).forEach(function (param) {
var value = param[1];
var key = param[0];
switch (key) {
case "f" :
case "i" :
case "n" :
case "op" :
case "opa" :
case "os" :
case "p" :
case "s" :
return ;
default:
if (typeof value === "object" && value !== null) {
$$new[key] = cleanUpSchema(value);
} else {
$$new[key] = value;
}
return ;
if (key === "i" || typeof value === "function") {
return ;
} else {
if (typeof value === "object" && value !== null) {
$$new[key] = cleanUpSchema(value);
} else {
$$new[key] = value;
}
return ;
}
});
return $$new;
Expand Down
6 changes: 4 additions & 2 deletions packages/tests/src/utils/U.res
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ let rec cleanUpSchema = schema => {
->Dict.toArray
->Array.forEach(((key, value)) => {
switch key {
| "s" | "p" | "i" | "f" | "n" | "os" | "op" | "opa" => ()
| "i" => ()
| _ =>
if typeof(value) === #object && value !== %raw(`null`) {
if typeof(value) === #function {
()
} else if typeof(value) === #object && value !== %raw(`null`) {
new->Dict.set(
key,
cleanUpSchema(value->(magic: unknown => S.t<'a>))->(magic: S.t<'a> => unknown),
Expand Down

1 comment on commit 2349fd9

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 2349fd9 Previous: 1d28c51 Ratio
Parse string 819369968 ops/sec (±0.09%) 819610349 ops/sec (±0.10%) 1.00
Serialize string 820186035 ops/sec (±0.07%) 819846717 ops/sec (±0.06%) 1.00
Advanced object schema factory 439941 ops/sec (±0.39%) 447933 ops/sec (±1.47%) 1.02
Parse advanced object 46695852 ops/sec (±0.67%) 46531317 ops/sec (±1.53%) 1.00
Create and parse advanced object 34246 ops/sec (±1.51%) 33412 ops/sec (±1.40%) 0.98
Parse advanced strict object 22086890 ops/sec (±0.37%) 22330607 ops/sec (±0.65%) 1.01
Serialize advanced object 808353951 ops/sec (±0.24%) 808065693 ops/sec (±0.25%) 1.00

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.