aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/tests/s-expressions/suites/Casts
diff options
context:
space:
mode:
authorMaxim Yurchuk <maxim-yurchuk@ydb.tech>2024-11-20 17:37:57 +0000
committerGitHub <noreply@github.com>2024-11-20 17:37:57 +0000
commitf76323e9b295c15751e51e3443aa47a36bee8023 (patch)
tree4113c8cad473a33e0f746966e0cf087252fa1d7a /yql/essentials/tests/s-expressions/suites/Casts
parent753ecb8d410a4cb459c26f3a0082fb2d1724fe63 (diff)
parenta7b9a6afea2a9d7a7bfac4c5eb4c1a8e60adb9e6 (diff)
downloadydb-f76323e9b295c15751e51e3443aa47a36bee8023.tar.gz
Merge pull request #11788 from ydb-platform/mergelibs-241120-1113
Library import 241120-1113
Diffstat (limited to 'yql/essentials/tests/s-expressions/suites/Casts')
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToEnormousList.yql9
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataFloatTypes.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataIntegralTypes.yql37
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataTypes.yql35
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDict.yql21
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverList.yql29
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverNull.yql36
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverOptional.yql52
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverStruct.yql22
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverTuple.yql22
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/AlterToOverVariant.yql38
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/DoAlterTo.yql.txt14
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/HasNullFalse.yql57
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/HasNullTrue.yql54
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverDict.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverList.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverNull.yql38
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverOptional.yql76
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverResource.cfg2
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverResource.yql22
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverStream.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverStruct.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverTuple.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverVariant.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverDict.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverList.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverNull.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverOptional.yql76
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverStruct.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverTuple.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverVariant.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/TryRemoveAllOptionals.yql55
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/TryRemoveAllOptionals2.yql24
-rw-r--r--yql/essentials/tests/s-expressions/suites/Casts/default.cfg2
34 files changed, 1128 insertions, 0 deletions
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToEnormousList.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToEnormousList.yql
new file mode 100644
index 0000000000..95a0ec2555
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToEnormousList.yql
@@ -0,0 +1,9 @@
+(
+(let w (DataSink 'result))
+(let out '('('type) '('autoref) '('columns '('column0))))
+(let res (Write! world w (Key) (Unordered (EnsurePersistable (OrderedFlatMap (AsList (Uint32 '0)) (lambda '(stub) (block '(
+ (let $5 (AlterTo (ListFromRange (Minus (Int64 '1)) (Int64 '1000000000000)) (ListType (DataType 'Uint64)) (lambda '(x) x) (AsList (Uint64 '0))))
+ (return (AsList (AsStruct '('"column0" $5))))
+)))))) out))
+(return (CommitAll! (Commit! res w)))
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataFloatTypes.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataFloatTypes.yql
new file mode 100644
index 0000000000..157a109a64
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataFloatTypes.yql
@@ -0,0 +1,39 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+# Float -> Double (always success)
+(let world (Apply (bind alterto_module 'doAlterTo) world (Float '"1.0") (DataType 'Double) (Double '"0.0")))
+
+# Double -> Float (success)
+(let world (Apply (bind alterto_module 'doAlterTo) world (Double '"2.0") (DataType 'Float) (Float '"123456.0")))
+
+# Double -> Float (fail)
+(let world (Apply (bind alterto_module 'doAlterTo) world (Double '"3.0000001") (DataType 'Float) (Float '"123456.0")))
+
+# Float -> Integer (success)
+(let world (Apply (bind alterto_module 'doAlterTo) world (Float '"3.0") (DataType 'Uint32) (Uint32 '123456)))
+
+# Float -> Integer (success)
+(let world (Apply (bind alterto_module 'doAlterTo) world (Float '"-3.0") (DataType 'Int32) (Int32 '123456)))
+
+# Float -> Integer (fail)
+(let world (Apply (bind alterto_module 'doAlterTo) world (Float '"3.3") (DataType 'Uint32) (Uint32 '123456)))
+
+# Float -> Integer (fail)
+(let world (Apply (bind alterto_module 'doAlterTo) world (Float '"1e10") (DataType 'Uint32) (Uint32 '123456)))
+
+# Float -> Integer (fail)
+(let world (Apply (bind alterto_module 'doAlterTo) world (Float '"-3.0") (DataType 'Uint32) (Uint32 '123456)))
+
+# Float -> Integer (fail)
+(let inf (/ (Float '"1.0") (Int8 '0)))
+(let world (Apply (bind alterto_module 'doAlterTo) world inf (DataType 'Int64) (Int64 '123456789)))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataIntegralTypes.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataIntegralTypes.yql
new file mode 100644
index 0000000000..746f8f987d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataIntegralTypes.yql
@@ -0,0 +1,37 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+# Int32->Int16
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int32 '10) (DataType 'Int16) (Int16 '100)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int32 '32768) (DataType 'Int16) (Int16 '101)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int32 '"-32769") (DataType 'Int16) (Int16 '102)))
+
+# Int64->Uint16
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int64 '11) (DataType 'Uint16) (Uint16 '110)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int64 '65536) (DataType 'Uint16) (Uint16 '111)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int64 '"-1") (DataType 'Uint16) (Uint16 '112)))
+
+# Uint32->Int8
+(let world (Apply (bind alterto_module 'doAlterTo) world (Uint32 '12) (DataType 'Int8) (Int8 '120)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Uint32 '128) (DataType 'Int8) (Int8 '121)))
+
+# Uint64->Uint32
+(let world (Apply (bind alterto_module 'doAlterTo) world (Uint64 '13) (DataType 'Uint32) (Uint32 '130)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Uint64 '4294967296) (DataType 'Uint32) (Uint32 '131)))
+
+# Int64->Uint64
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int64 '14) (DataType 'Uint64) (Uint64 '140)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int64 '"-1") (DataType 'Uint64) (Uint64 '141)))
+
+# Int32->Uint32
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int32 '15) (DataType 'Uint32) (Uint32 '150)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Int32 '"-1") (DataType 'Uint32) (Uint32 '151)))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataTypes.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataTypes.yql
new file mode 100644
index 0000000000..fd605370d2
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDataTypes.yql
@@ -0,0 +1,35 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+# String->Utf8
+(let world (Apply (bind alterto_module 'doAlterTo) world (String 'OK) (DataType 'Utf8) (Utf8 'FAIL)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (String '"\xff\xfe") (DataType 'Utf8) (Utf8 'OK)))
+
+# TzDatetime->TzDate
+# 2019-01-09T00:00:00,Europe/Moscow
+(let world (Apply (bind alterto_module 'doAlterTo) world (TzDatetime '"1546981200,Europe/Moscow") (DataType 'TzDate) (TzDate '"1,GMT")))
+(let world (Apply (bind alterto_module 'doAlterTo) world (TzDatetime '"1546981201,Europe/Moscow") (DataType 'TzDate) (TzDate '"2,GMT")))
+
+# TzTimestamp->Date
+# 2019-01-09T00:00:00,GMT
+(let world (Apply (bind alterto_module 'doAlterTo) world (TzTimestamp '"1546992000000000,GMT") (DataType 'Date) (Date '3)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (TzTimestamp '"1546992000000001,GMT") (DataType 'Date) (Date '4)))
+# 2019-01-09T00:00:00,Europe/Moscow
+(let world (Apply (bind alterto_module 'doAlterTo) world (TzTimestamp '"1546981200000000,Europe/Moscow") (DataType 'Date) (Date '5)))
+# 2019-01-09T03:00:00,Europe/Moscow
+(let world (Apply (bind alterto_module 'doAlterTo) world (TzTimestamp '"1546992000000000,Europe/Moscow") (DataType 'Date) (Date '6)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (TzTimestamp '"1546992000000001,Europe/Moscow") (DataType 'Date) (Date '7)))
+
+# Datetime->Date
+# 2019-01-09T00:00:00Z
+(let world (Apply (bind alterto_module 'doAlterTo) world (Datetime '"1546992000") (DataType 'Date) (Date '8)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Datetime '"1546992001") (DataType 'Date) (Date '9)))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDict.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDict.yql
new file mode 100644
index 0000000000..95377162e7
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverDict.yql
@@ -0,0 +1,21 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+# Dict<Int32, String> -> Dict<Int32, Utf8>
+(let targetType (DictType (DataType 'Int32) (DataType 'Utf8)))
+(let emptyTarget (Dict targetType))
+(let src (AsDict '((Int32 '1) (String 'one)) '((Int32 '2) (String 'two)) '((Int32 '3) (String 'three))))
+(let world (Apply (bind alterto_module 'doAlterTo) world src targetType emptyTarget))
+
+# Dict<Int32, String> -> Dict<Int32, Utf8> (fail)
+(let src (AsDict '((Int32 '1) (String 'one)) '((Int32 '2) (String '"\xff\xfe")) '((Int32 '3) (String 'three))))
+(let world (Apply (bind alterto_module 'doAlterTo) world src targetType emptyTarget))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverList.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverList.yql
new file mode 100644
index 0000000000..6330d3262a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverList.yql
@@ -0,0 +1,29 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+# List<Int32> -> List<Uint16> (success)
+(let targetType (ListType (DataType 'Uint16)))
+(let emptyTarget (List targetType))
+(let src (AsList (Int32 '1) (Int32 '2) (Int32 '3)))
+(let world (Apply (bind alterto_module 'doAlterTo) world src targetType emptyTarget))
+
+# List<Int32> -> List<Uint16> (fail)
+(let targetType (ListType (DataType 'Uint16)))
+(let emptyTarget (List targetType))
+(let src (AsList (Int32 '1) (Int32 '"-2") (Int32 '3)))
+(let world (Apply (bind alterto_module 'doAlterTo) world src targetType emptyTarget))
+
+# List<Int32?> -> List<Uint16> (fail)
+(let targetType (ListType (DataType 'Uint16)))
+(let emptyTarget (List targetType))
+(let src (AsList (Just (Int32 '1)) (Null) (Just (Int32 '3))))
+(let world (Apply (bind alterto_module 'doAlterTo) world src targetType emptyTarget))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverNull.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverNull.yql
new file mode 100644
index 0000000000..6039cd0719
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverNull.yql
@@ -0,0 +1,36 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+# Null -> Uint16?
+(let targetType (OptionalType (DataType 'Uint16)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Null) targetType (Just (Uint16 '12345))))
+
+# Just(Null) -> Null
+(let alterToResult (AlterTo (Just (Null)) (NullType) (lambda '(x) (String 'OK)) (String 'FAIL)))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) alterToResult '('('type))))
+
+# Nothing(Null?) -> Null
+(let alterToResult (AlterTo (Nothing (OptionalType (NullType))) (NullType) (lambda '(x) (String 'OK)) (String 'FAIL)))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) alterToResult '('('type))))
+
+# Nothing(Uint16?) -> Null
+(let alterToResult (AlterTo (Nothing (OptionalType (DataType 'Uint16))) (NullType) (lambda '(x) (String 'OK)) (String 'FAIL)))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) alterToResult '('('type))))
+
+# Null -> Null?
+(let alterToResult (AlterTo (Null) (OptionalType (NullType)) (lambda '(x) (String 'OK)) (String 'FAIL)))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) alterToResult '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverOptional.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverOptional.yql
new file mode 100644
index 0000000000..9141b62154
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverOptional.yql
@@ -0,0 +1,52 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Int32? -> Uint16
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Int32 '1)) (DataType 'Uint16) (Uint16 '12345)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Int32 '1000000)) (DataType 'Uint16) (Uint16 '12345)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Nothing (OptionalType (DataType 'Int32))) (DataType 'Uint16) (Uint16 '12345)))
+
+# Int32? -> Uint16?
+(let targetType (OptionalType (DataType 'Uint16)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Int32 '1)) targetType (Just (Uint16 '12345))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Int32 '1000000)) targetType (Just (Uint16 '12345))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Nothing (OptionalType (DataType 'Int32))) targetType (Just (Uint16 '12345))))
+
+# Int32? -> Uint16???
+(let targetType (OptionalType (OptionalType (OptionalType (DataType 'Uint16)))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Int32 '1)) targetType (Just (Just (Just (Uint16 '12345))))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Int32 '1000000)) targetType (Just (Just (Just (Uint16 '12345))))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Nothing (OptionalType (DataType 'Int32))) targetType (Just (Just (Just (Uint16 '12345))))))
+
+# Int32??? -> Uint16?
+(let targetType (OptionalType (DataType 'Uint16)))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Just (Just (Int32 '1)))) targetType (Just (Uint16 '12345))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Just (Just (Int32 '1000000)))) targetType (Just (Uint16 '12345))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Nothing (OptionalType (OptionalType (OptionalType (DataType 'Int32))))) targetType (Just (Uint16 '12345))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Nothing (OptionalType (OptionalType (DataType 'Int32))))) targetType (Just (Uint16 '12345))))
+(let world (Apply (bind alterto_module 'doAlterTo) world (Just (Just (Nothing (OptionalType (DataType 'Int32))))) targetType (Just (Uint16 '12345))))
+
+# Int32? -> Null
+(let targetType (NullType))
+(let alterToResult (AlterTo (Just (Int32 '1)) targetType (lambda '(x) (String '"converted")) (String '"not converted")))
+(let world (Write! world res_sink (Key) alterToResult '('('type))))
+(let alterToResult (AlterTo (Nothing (OptionalType (DataType 'Int32))) targetType (lambda '(x) (String '"converted")) (String '"not converted")))
+(let world (Write! world res_sink (Key) alterToResult '('('type))))
+
+# Int64? -> Null?
+(let targetType (NullType))
+(let alterToResult (AlterTo (Just (Int64 '1)) targetType (lambda '(x) (String '"converted")) (String '"not converted")))
+(let world (Write! world res_sink (Key) alterToResult '('('type))))
+(let alterToResult (AlterTo (Nothing (OptionalType (DataType 'Int64))) targetType (lambda '(x) (String '"converted")) (String '"not converted")))
+(let world (Write! world res_sink (Key) alterToResult '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverStruct.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverStruct.yql
new file mode 100644
index 0000000000..6654166a27
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverStruct.yql
@@ -0,0 +1,22 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let targetType (StructType '('"a" (DataType 'Uint8)) '('"b" (DataType 'Utf8))))
+(let failValue (AsStruct '('a (Uint8 '0)) '('b (Utf8 '"not converted"))))
+
+# Struct<Int32, String> -> Struct<Uint8, Utf8>
+(let value (AsStruct '('a (Int32 '1)) '('b (String 'one))))
+(let world (Apply (bind alterto_module 'doAlterTo) world value targetType failValue))
+
+# Struct<Int32, String> -> Struct<Uint8, Utf8> (fail)
+(let value (AsStruct '('a (Int32 '"-1")) '('b (String 'one))))
+(let world (Apply (bind alterto_module 'doAlterTo) world value targetType failValue))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverTuple.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverTuple.yql
new file mode 100644
index 0000000000..3ad49c4744
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverTuple.yql
@@ -0,0 +1,22 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let targetType (TupleType (DataType 'Uint8) (DataType 'Utf8)))
+(let failValue '((Uint8 '0) (Utf8 '"not converted")))
+
+# (Int32, String) -> (Uint8, Utf8)
+(let value '((Int32 '1) (String 'one)))
+(let world (Apply (bind alterto_module 'doAlterTo) world value targetType failValue))
+
+# (Int32, String) -> (Uint8, Utf8) (fail)
+(let value '((Int32 '1) (String '"garbage\xff")))
+(let world (Apply (bind alterto_module 'doAlterTo) world value targetType failValue))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverVariant.yql b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverVariant.yql
new file mode 100644
index 0000000000..020cf59904
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/AlterToOverVariant.yql
@@ -0,0 +1,38 @@
+(
+
+(library "alterto.yql")
+(import alterto_module '"alterto.yql")
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+### Tuple
+
+(let srcType (VariantType (TupleType (DataType 'Int32) (DataType 'String))))
+(let targetType (VariantType (TupleType (DataType 'Uint8) (DataType 'Utf8))))
+(let failValue (Variant (Utf8 '"not converted") '1 targetType))
+
+# Variant<Tuple<Int32, String>> -> Variant<Tuple<Uint8, Utf8>>
+(let value (Variant (String 'one) '1 srcType))
+(let world (Apply (bind alterto_module 'doAlterTo) world value targetType failValue))
+
+# Variant<Tuple<Int32, String>> -> Variant<Tuple<Uint8, Utf8>> (fail)
+(let value (Variant (String '"garbage\xff") '1 srcType))
+(let world (Apply (bind alterto_module 'doAlterTo) world value targetType failValue))
+
+### Struct
+(let srcType (VariantType (StructType '('a (DataType 'Int32)) '('b (DataType 'String)))))
+(let targetType (VariantType (StructType '('a (DataType 'Uint8)) '('b (DataType 'Utf8)))))
+(let failValue (Variant (Uint8 '123) 'a targetType))
+
+# Variant<Struct<Int32, String>> -> Variant<Struct<Uint8, Utf8>>
+(let value (Variant (Int32 '1) 'a srcType))
+(let world (Apply (bind alterto_module 'doAlterTo) world value targetType failValue))
+
+# Variant<Struct<Int32, String>> -> Variant<Struct<Uint8, Utf8>> (fail)
+(let value (Variant (Int32 '"-1") 'a srcType))
+(let world (Apply (bind alterto_module 'doAlterTo) world value targetType failValue))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/DoAlterTo.yql.txt b/yql/essentials/tests/s-expressions/suites/Casts/DoAlterTo.yql.txt
new file mode 100644
index 0000000000..2278581ec9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/DoAlterTo.yql.txt
@@ -0,0 +1,14 @@
+(
+
+(let doAlterTo (lambda '(world src targetType failValue) ( block '(
+ (let res_sink (DataSink 'result))
+ (let identity (lambda '(x) x))
+ (let alterToResult (AlterTo src targetType identity failValue))
+ (let world (Write! world res_sink (Key) alterToResult '('('type))))
+ (let world (Commit! world res_sink))
+ (return world)
+))))
+
+(export doAlterTo)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/HasNullFalse.yql b/yql/essentials/tests/s-expressions/suites/Casts/HasNullFalse.yql
new file mode 100644
index 0000000000..8f253ab7a0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/HasNullFalse.yql
@@ -0,0 +1,57 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+
+# Data
+(let value (String 'test))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (Int32 '1))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (TzDatetime '"1546981200,Europe/Moscow"))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let valye (/ (Float '1) (Float '0)))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# Optional
+(let value (Just (Int32 '1)))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# Tuple
+(let value '((Int32 '1) (String 'test) (Float '1)))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value '())
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# Struct
+(let value (AsStruct '('a (Int32 '1)) '('b (String 'one))))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (Struct))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# Variant
+(let valueType (VariantType (TupleType (DataType 'Int32) (NullType))))
+(let value (Variant (Int32 '123) '0 valueType))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let valueType (VariantType (StructType '('a (DataType 'Int32)) '('b (OptionalType (DataType 'String))))))
+(let value (Variant (Int32 '1) 'a valueType))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# List
+(let value (AsList (Int32 '1) (Int32 '2) (Int32 '3)))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (List (ListType (NullType))))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/HasNullTrue.yql b/yql/essentials/tests/s-expressions/suites/Casts/HasNullTrue.yql
new file mode 100644
index 0000000000..a26295ffad
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/HasNullTrue.yql
@@ -0,0 +1,54 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+
+# Optional
+(let value (Nothing (OptionalType (DataType 'Int32))))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (Just (Nothing (OptionalType (DataType 'Int32)))))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# Null
+(let value (Null))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (Just (Null)))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (Nothing (OptionalType (NullType))))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (Just (Nothing (OptionalType (NullType)))))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# Tuple
+(let value '((Int32 '1) (String 'test) (Nothing (OptionalType (DataType 'Int32)))))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# Struct
+(let value (AsStruct '('a (Int32 '1)) '('b (Just (Nothing (OptionalType (DataType 'Int32)))))))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# Variant
+(let valueType (VariantType (TupleType (DataType 'Int32) (NullType))))
+(let value (Variant (Null) '1 valueType))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let valueType (VariantType (StructType '('a (DataType 'Int32)) '('b (OptionalType (DataType 'String))))))
+(let value (Variant (Nothing (OptionalType (DataType 'String))) 'b valueType))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+# List
+(let value (AsList (Null) (Int32 '1) (Int32 '2)))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let value (AsList (Int32 '1) (Int32 '2) (Null)))
+(let world (Write! world res_sink (Key) (HasNull value) '()))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverDict.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverDict.yql
new file mode 100644
index 0000000000..6dc4b237c5
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverDict.yql
@@ -0,0 +1,23 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Dict<Int32, String> -> Dict<Uint8, Utf8> (full)
+(let targetType (DictType (DataType 'Uint8) (DataType 'Utf8)))
+(let src (AsDict '((Int32 '1) (String 'one)) '((Int32 '2) (String 'two)) '((Int32 '3) (String 'three))))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Dict<Int32, String> -> Dict<Int64, Utf8> (less)
+(let targetType (DictType (DataType 'Int64) (DataType 'Utf8)))
+(let src (AsDict '((Int32 '1) (String 'one)) '((Int32 '2) (String '"\xff\xfe")) '((Int32 '3) (String 'three))))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverList.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverList.yql
new file mode 100644
index 0000000000..8f00b970d1
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverList.yql
@@ -0,0 +1,30 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# List<Int32> -> List<Uint16> (full)
+(let targetType (ListType (DataType 'Uint16)))
+(let src (AsList (Int32 '1) (Int32 '2) (Int32 '3)))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# List<Int32> -> List<Uint16> (less)
+(let targetType (ListType (DataType 'Uint16)))
+(let src (AsList (Int32 '1) (Int32 '-2) (Int32 '3)))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# List<Int32?> -> List<Uint16> (less)
+(let targetType (ListType (DataType 'Uint16)))
+(let src (AsList (Just (Int32 '1)) (Null) (Just (Int32 '3))))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
+
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverNull.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverNull.yql
new file mode 100644
index 0000000000..6044a39e4e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverNull.yql
@@ -0,0 +1,38 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Null -> Uint16
+(let cast (SafeCast (Null) (DataType 'Uint16)))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Null -> Uint16?
+(let cast (SafeCast (Null) (OptionalType (DataType 'Uint16))))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Just(Null) -> Null
+(let cast (SafeCast (Just (Null)) (NullType)))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Nothing(Null?) -> Null
+(let cast (SafeCast (Nothing (OptionalType (NullType))) (NullType)))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Uint16 -> Null
+(let cast (SafeCast (Uint16 '0) (NullType)))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Nothing(Uint16?) -> Null
+(let cast (SafeCast (Nothing (OptionalType (DataType 'Uint16))) (NullType)))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Null -> Null?
+(let cast (SafeCast (Null) (OptionalType (NullType))))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverOptional.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverOptional.yql
new file mode 100644
index 0000000000..c10d1243e9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverOptional.yql
@@ -0,0 +1,76 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Int32? -> Uint16
+(let targetType (OptionalType (DataType 'Uint16)))
+(let cast (SafeCast (Just (Int32 '1)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Int32 '1000000)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Nothing (OptionalType (DataType 'Int32))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32? -> Uint16?
+(let targetType (OptionalType (DataType 'Uint16)))
+(let cast (SafeCast (Just (Int32 '1)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Int32 '1000000)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Nothing (OptionalType (DataType 'Int32))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32? -> Uint16???
+(let targetType (OptionalType (OptionalType (OptionalType (DataType 'Uint16)))))
+(let cast (SafeCast (Just (Int32 '1)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Int32 '1000000)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Nothing (OptionalType (DataType 'Int32))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32??? -> Uint16?
+(let targetType (OptionalType (DataType 'Uint16)))
+(let cast (SafeCast (Just (Just (Just (Int32 '1)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Just (Just (Int32 '1000000)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Nothing (OptionalType (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Nothing (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Just (Nothing (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32??? -> Uint16??
+(let targetType (OptionalType (OptionalType (DataType 'Uint16))))
+(let cast (SafeCast (Just (Just (Just (Int32 '1)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Just (Just (Int32 '1000000)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Nothing (OptionalType (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Nothing (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Just (Nothing (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32??? -> Uint16????
+(let targetType (OptionalType (OptionalType (OptionalType (OptionalType (DataType 'Uint16))))))
+(let cast (SafeCast (Just (Just (Just (Int32 '1)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Just (Just (Int32 '1000000)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Nothing (OptionalType (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Nothing (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (SafeCast (Just (Just (Nothing (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverResource.cfg b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverResource.cfg
new file mode 100644
index 0000000000..ec2b802773
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverResource.cfg
@@ -0,0 +1,2 @@
+res result.txt
+udf yson2_udf
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverResource.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverResource.yql
new file mode 100644
index 0000000000..11fd9ebc30
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverResource.yql
@@ -0,0 +1,22 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+
+(let yson1 (Apply (Udf '"Yson2.Parse") (String '"#") (Just (NamedApply (Udf 'Yson2.Options) '() (AsStruct '('"AutoConvert" (Just (Bool '"false"))) '('"Strict" (Just (Bool '"false"))))))))
+(let yson2 (Apply (Udf '"Yson2.Parse") (String '"[]") (Just (NamedApply (Udf 'Yson2.Options) '() (AsStruct '('"AutoConvert" (Just (Bool '"false"))) '('"Strict" (Just (Bool '"false"))))))))
+
+
+(let targetType (ListType (ResourceType 'Yson2.Node)))
+(let src (AsList (Just yson1) (Just yson2)))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) (Map cast (lambda '(item) (Apply (Udf '"Yson2.Serialize") item))) '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
+
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverStream.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverStream.yql
new file mode 100644
index 0000000000..1ac4fd613e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverStream.yql
@@ -0,0 +1,30 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Stream<Int32> -> Stream<Uint16> (full)
+(let targetType (StreamType (DataType 'Uint16)))
+(let src (Iterator (AsList (Int32 '1) (Int32 '2) (Int32 '3))))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) (Collect cast) '('('type))))
+
+# Stream<Int32> -> Stream<Uint16> (less)
+(let targetType (StreamType (DataType 'Uint16)))
+(let src (Iterator (AsList (Int32 '1) (Int32 '-2) (Int32 '3))))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) (Collect cast) '('('type))))
+
+# Stream<Int32?> -> Stream<Uint16> (less)
+(let targetType (StreamType (DataType 'Uint16)))
+(let src (Iterator (AsList (Just (Int32 '1)) (Null) (Just (Int32 '3)))))
+(let cast (SafeCast src targetType))
+(let world (Write! world res_sink (Key) (Collect cast) '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
+
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverStruct.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverStruct.yql
new file mode 100644
index 0000000000..94bc8b7842
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverStruct.yql
@@ -0,0 +1,23 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Struct<Int32, String, Utf8> -> Struct<Uint8?, Utf8?>
+(let targetType (StructType '('a (OptionalType (DataType 'Uint8))) '('b (OptionalType (DataType 'Utf8)))))
+(let value (AsStruct '('a (Int32 '1)) '('b (String 'one)) '('c (Utf8 'two))))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Struct<Int32, String> -> Struct<Int8, Utf8, Float?>?
+(let targetType (StructType '('a (DataType 'Int8)) '('b (DataType 'Utf8)) '('c (OptionalType (DataType 'Float)))))
+(let value (AsStruct '('a (Int32 '-1)) '('b (String 'one))))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverTuple.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverTuple.yql
new file mode 100644
index 0000000000..33421380cb
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverTuple.yql
@@ -0,0 +1,39 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+(let targetType (TupleType (DataType 'Uint8) (DataType 'Utf8)))
+
+# (Int32, String) -> (Uint8, Utf8) [good]
+(let value '((Int32 '1) (String 'one)))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# (Int32, String) -> (Uint8, Utf8)? [null]
+(let value '((Int32 '1) (String '"garbage\xff")))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# (Int32?, String???) -> (Uint8??, Utf8?)? [good]
+(let targetType (TupleType (OptionalType (OptionalType (DataType 'Uint8))) (OptionalType (DataType 'Utf8))))
+(let value '((Just (Int32 '1)) (Just (Nothing (OptionalType (DataType 'String))))))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# (Int32?, String???) -> (Uint8??, Utf8?)? [null]
+(let value '((Just (Int32 '1)) (Nothing (OptionalType (OptionalType (DataType 'String))))))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# (Int32?, String???) -> (Uint8??, Utf8?)? [null]
+(let value '((Just (Int32 '-1)) (Just (Nothing (OptionalType (DataType 'String))))))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverVariant.yql b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverVariant.yql
new file mode 100644
index 0000000000..ea34cbd481
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/SafeCastOverVariant.yql
@@ -0,0 +1,39 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+### Tuple
+(let srcType (VariantType (TupleType (DataType 'Int32) (DataType 'String))))
+(let targetType (VariantType (TupleType (DataType 'Uint8) (DataType 'Utf8))))
+
+# Variant<Tuple<Int32, String>> -> Variant<Tuple<Uint8, Utf8>>? (good)
+(let value (Variant (String 'one) '1 srcType))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Variant<Tuple<Int32, String>> -> Variant<Tuple<Uint8, Utf8>>? (null)
+(let value (Variant (String '"garbage\xff") '1 srcType))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+### Struct
+(let srcType (VariantType (StructType '('a (DataType 'Int32)) '('b (DataType 'String)))))
+(let targetType (VariantType (StructType '('a (DataType 'Uint8)) '('b (DataType 'Utf8)))))
+
+# Variant<Struct<Int32, String>> -> Variant<Struct<Uint8, Utf8>>? (good)
+(let value (Variant (Int32 '1) 'a srcType))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Variant<Struct<Int32, String>> -> Variant<Struct<Uint8, Utf8>>? (null)
+(let value (Variant (Int32 '"-1") 'a srcType))
+(let cast (SafeCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverDict.yql b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverDict.yql
new file mode 100644
index 0000000000..ee7aa8e401
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverDict.yql
@@ -0,0 +1,23 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Dict<Int32, String> -> Dict<Uint8, Utf8> (good)
+(let targetType (DictType (DataType 'Uint8) (DataType 'Utf8)))
+(let src (AsDict '((Int32 '1) (String 'one)) '((Int32 '2) (String 'two)) '((Int32 '3) (String 'three))))
+(let cast (StrictCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Dict<Int32, String> -> Dict<Int64, Utf8> (fail)
+(let targetType (DictType (DataType 'Int64) (DataType 'Utf8)))
+(let src (AsDict '((Int32 '1) (String 'one)) '((Int32 '2) (String '"\xff\xfe")) '((Int32 '3) (String 'three))))
+(let cast (StrictCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverList.yql b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverList.yql
new file mode 100644
index 0000000000..146ed0dbe9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverList.yql
@@ -0,0 +1,30 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# List<Int32> -> List<Uint16> (good)
+(let targetType (ListType (DataType 'Uint16)))
+(let src (AsList (Int32 '1) (Int32 '2) (Int32 '3)))
+(let cast (StrictCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# List<Int32> -> List<Uint16> (fail)
+(let targetType (ListType (DataType 'Uint16)))
+(let src (AsList (Int32 '1) (Int32 '-2) (Int32 '3)))
+(let cast (StrictCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# List<Int32?> -> List<Uint16> (fail)
+(let targetType (ListType (DataType 'Uint16)))
+(let src (AsList (Just (Int32 '1)) (Null) (Just (Int32 '3))))
+(let cast (StrictCast src targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
+
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverNull.yql b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverNull.yql
new file mode 100644
index 0000000000..d7c66842b0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverNull.yql
@@ -0,0 +1,30 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Null -> Uint16?
+(let cast (StrictCast (Null) (OptionalType (DataType 'Uint16))))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Just(Null) -> Null? [good]
+(let cast (StrictCast (Just (Null)) (NullType)))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Nothing(Null?) -> Null? [fail]
+(let cast (StrictCast (Nothing (OptionalType (NullType))) (NullType)))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Nothing(Uint16?) -> Null
+(let cast (StrictCast (Nothing (OptionalType (DataType 'Uint16))) (NullType)))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Null -> Null?
+(let cast (StrictCast (Null) (OptionalType (NullType))))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverOptional.yql b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverOptional.yql
new file mode 100644
index 0000000000..28cf793e44
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverOptional.yql
@@ -0,0 +1,76 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Int32? -> Uint16
+(let targetType (OptionalType (DataType 'Uint16)))
+(let cast (StrictCast (Just (Int32 '1)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Int32 '1000000)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Nothing (OptionalType (DataType 'Int32))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32? -> Uint16?
+(let targetType (OptionalType (DataType 'Uint16)))
+(let cast (StrictCast (Just (Int32 '1)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Int32 '1000000)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Nothing (OptionalType (DataType 'Int32))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32? -> Uint16???
+(let targetType (OptionalType (OptionalType (OptionalType (DataType 'Uint16)))))
+(let cast (StrictCast (Just (Int32 '1)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Int32 '1000000)) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Nothing (OptionalType (DataType 'Int32))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32??? -> Uint16?
+(let targetType (OptionalType (DataType 'Uint16)))
+(let cast (StrictCast (Just (Just (Just (Int32 '1)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Just (Just (Int32 '1000000)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Nothing (OptionalType (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Nothing (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Just (Nothing (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32??? -> Uint16??
+(let targetType (OptionalType (OptionalType (DataType 'Uint16))))
+(let cast (StrictCast (Just (Just (Just (Int32 '1)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Just (Just (Int32 '1000000)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Nothing (OptionalType (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Nothing (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Just (Nothing (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Int32??? -> Uint16????
+(let targetType (OptionalType (OptionalType (OptionalType (OptionalType (DataType 'Uint16))))))
+(let cast (StrictCast (Just (Just (Just (Int32 '1)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Just (Just (Int32 '1000000)))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Nothing (OptionalType (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Nothing (OptionalType (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+(let cast (StrictCast (Just (Just (Nothing (OptionalType (DataType 'Int32))))) targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverStruct.yql b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverStruct.yql
new file mode 100644
index 0000000000..afa021dd11
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverStruct.yql
@@ -0,0 +1,23 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+# Struct<Int32, String, Utf8?> -> Struct<Uint8?, Utf8?> (good)
+(let targetType (StructType '('a (OptionalType (DataType 'Uint8))) '('b (OptionalType (DataType 'Utf8)))))
+(let value (AsStruct '('a (Int32 '1)) '('b (String 'one)) '('c (Nothing (OptionalType (DataType 'Utf8))))))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Struct<Int32, String, String?> -> Struct<Int8, Utf8, Float?>? (fail)
+(let targetType (StructType '('a (DataType 'Int8)) '('b (DataType 'Utf8)) '('c (OptionalType (DataType 'Float)))))
+(let value (AsStruct '('a (Int32 '-1)) '('b (String 'one)) '('d (Just (String 'one)))))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverTuple.yql b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverTuple.yql
new file mode 100644
index 0000000000..4f2319f1ea
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverTuple.yql
@@ -0,0 +1,39 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+(let targetType (TupleType (DataType 'Uint8) (DataType 'Utf8)))
+
+# (Int32, String) -> (Uint8, Utf8) [good]
+(let value '((Int32 '1) (String 'one)))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# (Int32, String) -> (Uint8, Utf8)? [null]
+(let value '((Int32 '1) (String '"garbage\xff")))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# (Int32?, String???) -> (Uint8??, Utf8?)? [good]
+(let targetType (TupleType (OptionalType (OptionalType (DataType 'Uint8))) (OptionalType (DataType 'Utf8))))
+(let value '((Just (Int32 '1)) (Just (Nothing (OptionalType (DataType 'String))))))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# (Int32?, String???) -> (Uint8??, Utf8?)? [fail]
+(let value '((Just (Int32 '1)) (Nothing (OptionalType (OptionalType (DataType 'String))))))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# (Int32?, String???) -> (Uint8??, Utf8?)? [fail]
+(let value '((Just (Int32 '-1)) (Just (Nothing (OptionalType (DataType 'String))))))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverVariant.yql b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverVariant.yql
new file mode 100644
index 0000000000..b533e16780
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/StrictCastOverVariant.yql
@@ -0,0 +1,39 @@
+(
+
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+(let res_sink (DataSink 'result))
+
+### Tuple
+(let srcType (VariantType (TupleType (DataType 'Int32) (DataType 'String))))
+(let targetType (VariantType (TupleType (DataType 'Uint8) (DataType 'Utf8))))
+
+# Variant<Tuple<Int32, String>> -> Variant<Tuple<Uint8, Utf8>>? (good)
+(let value (Variant (String 'one) '1 srcType))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Variant<Tuple<Int32, String>> -> Variant<Tuple<Uint8, Utf8>>? (null)
+(let value (Variant (String '"garbage\xff") '1 srcType))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+### Struct
+(let srcType (VariantType (StructType '('a (DataType 'Int32)) '('b (DataType 'String)))))
+(let targetType (VariantType (StructType '('a (DataType 'Uint8)) '('b (DataType 'Utf8)))))
+
+# Variant<Struct<Int32, String>> -> Variant<Struct<Uint8, Utf8>>? (good)
+(let value (Variant (Int32 '1) 'a srcType))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+# Variant<Struct<Int32, String>> -> Variant<Struct<Uint8, Utf8>>? (null)
+(let value (Variant (Int32 '"-1") 'a srcType))
+(let cast (StrictCast value targetType))
+(let world (Write! world res_sink (Key) cast '('('type))))
+
+(let world (Commit! world res_sink))
+
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/TryRemoveAllOptionals.yql b/yql/essentials/tests/s-expressions/suites/Casts/TryRemoveAllOptionals.yql
new file mode 100644
index 0000000000..1bc57c71bf
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/TryRemoveAllOptionals.yql
@@ -0,0 +1,55 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let res_sink (DataSink 'result))
+
+### Tuple
+
+# (Int8?, String?, (Int32, Int64)?) (success)
+(let value '((Just (Int8 '1)) (Just (String 'str)) (Just '((Int32 '2) (Int64 '3)))))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+# (Int8?, String, (Int32, Int64)?) (success)
+(let value '((Just (Int8 '1)) (String 'str) (Just '((Int32 '2) (Int64 '3)))))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+# (Int8?, Nothing(String?), (Int32, Int64)?) (fail)
+(let value '((Just (Int8 '1)) (Nothing (OptionalType (DataType 'String))) (Just '((Int32 '2) (Int64 '3)))))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+# () (success)
+(let value '())
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+
+### Struct
+
+# Struct<Int8?, String?, (Int32, Int64)?> (success)
+(let value (AsStruct '('a (Just (Int8 '1))) '('b (Just (String 'str))) '('c (Just '((Int32 '2) (Int64 '3))))))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+# Struct<Int8?, String, (Int32, Int64)?> (success)
+(let value (AsStruct '('a (Just (Int8 '1))) '('b (String 'str)) '('c (Just '((Int32 '2) (Int64 '3))))))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+# Struct<Int8?, Nothing(String?), (Int32, Int64)?> (fail)
+(let value (AsStruct '('a (Just (Int8 '1))) '('b (Nothing (OptionalType (DataType 'String)))) '('c (Just '((Int32 '2) (Int64 '3))))))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+# Struct<> (success)
+(let value (Struct))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/TryRemoveAllOptionals2.yql b/yql/essentials/tests/s-expressions/suites/Casts/TryRemoveAllOptionals2.yql
new file mode 100644
index 0000000000..0649383205
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/TryRemoveAllOptionals2.yql
@@ -0,0 +1,24 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let res_sink (DataSink 'result))
+
+### Tuple
+
+# (Int8?, String, (Int32, Int64)?, Just(Nothing(String?)) (success)
+(let value '((Just (Int8 '1)) (String 'str) (Just '((Int32 '2) (Int64 '3))) (Just (Nothing (OptionalType (DataType 'String))))))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+### Struct
+
+# Struct<Int8?, String, (Int32, Int64)?> (success)
+(let value (AsStruct '('a (Just (Int8 '1))) '('b (String 'str)) '('c (Just '((Int32 '2) (Int64 '3)))) '('d (Just (Nothing (OptionalType (DataType 'String)))))))
+(let tryRemoveAllOptionalsResult (TryRemoveAllOptionals value))
+(let world (Write! world res_sink (Key) tryRemoveAllOptionalsResult '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/Casts/default.cfg b/yql/essentials/tests/s-expressions/suites/Casts/default.cfg
new file mode 100644
index 0000000000..baa119f7c7
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/Casts/default.cfg
@@ -0,0 +1,2 @@
+res result.txt
+file alterto.yql DoAlterTo.yql.txt