Skip to content

Commit dc1c5fc

Browse files
committed
feat: add Promise.try functionality
1 parent a4759d5 commit dc1c5fc

File tree

3 files changed

+231
-0
lines changed

3 files changed

+231
-0
lines changed

examples_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,78 @@ func ExamplePromisify() {
358358
fmt.Println(result)
359359
// Output: data from database
360360
}
361+
362+
// ExampleTry demonstrates basic usage of Try
363+
func ExampleTry() {
364+
// Basic usage
365+
promise := Try(func() string {
366+
return "Hello, World!"
367+
})
368+
369+
result, err := promise.Await()
370+
if err != nil {
371+
fmt.Printf("Error: %v\n", err)
372+
return
373+
}
374+
fmt.Println(result)
375+
// Output: Hello, World!
376+
}
377+
378+
// ExampleTryWithError demonstrates usage of TryWithError
379+
func ExampleTryWithError() {
380+
// With Go's standard error pattern
381+
promise := TryWithError(func() (int, error) {
382+
// Simulate some operation that might fail
383+
if time.Now().Second()%2 == 0 {
384+
return 42, nil
385+
}
386+
return 0, errors.New("operation failed")
387+
})
388+
389+
result, err := promise.Await()
390+
if err != nil {
391+
fmt.Printf("Error: %v\n", err)
392+
return
393+
}
394+
fmt.Printf("Result: %d\n", result)
395+
}
396+
397+
// ExampleTryWithMgr demonstrates usage of TryWithMgr with custom manager
398+
func ExampleTryWithMgr() {
399+
// Create a custom manager
400+
manager := NewPromiseMgr(2)
401+
defer manager.Close()
402+
403+
// Use TryWithMgr with custom manager
404+
promise := TryWithMgr(manager, func() string {
405+
return "Hello from custom manager!"
406+
})
407+
408+
result, err := promise.Await()
409+
if err != nil {
410+
fmt.Printf("Error: %v\n", err)
411+
return
412+
}
413+
fmt.Println(result)
414+
// Output: Hello from custom manager!
415+
}
416+
417+
// ExampleTryWithErrorAndMgr demonstrates usage of TryWithErrorAndMgr
418+
func ExampleTryWithErrorAndMgr() {
419+
// Create a custom manager
420+
manager := NewPromiseMgr(2)
421+
defer manager.Close()
422+
423+
// Use TryWithErrorAndMgr with custom manager
424+
promise := TryWithErrorAndMgr(manager, func() (string, error) {
425+
return "Success with custom manager!", nil
426+
})
427+
428+
result, err := promise.Await()
429+
if err != nil {
430+
fmt.Printf("Error: %v\n", err)
431+
return
432+
}
433+
fmt.Println(result)
434+
// Output: Success with custom manager!
435+
}

promise_static.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,48 @@ func Reduce[T any, R any](items []T, fn func(R, T) *Promise[R], initial R) *Prom
187187

188188
return Resolve(result)
189189
}
190+
191+
// Try executes a function and returns a Promise that resolves with the result
192+
// or rejects with any error/panic that occurs during execution
193+
// This is similar to Node.js's Promise.try()
194+
func Try[T any](fn func() T) *Promise[T] {
195+
return New(func(resolve func(T), reject func(error)) {
196+
result := fn()
197+
resolve(result)
198+
})
199+
}
200+
201+
// TryWithMgr executes a function using the specified manager and returns a Promise
202+
// that resolves with the result or rejects with any error/panic that occurs during execution
203+
func TryWithMgr[T any](manager *PromiseMgr, fn func() T) *Promise[T] {
204+
return NewWithMgr(manager, func(resolve func(T), reject func(error)) {
205+
result := fn()
206+
resolve(result)
207+
})
208+
}
209+
210+
// TryWithError executes a function that returns (T, error) and returns a Promise
211+
// This is useful for Go functions that follow the standard (value, error) return pattern
212+
func TryWithError[T any](fn func() (T, error)) *Promise[T] {
213+
return New(func(resolve func(T), reject func(error)) {
214+
result, err := fn()
215+
if err != nil {
216+
reject(err)
217+
} else {
218+
resolve(result)
219+
}
220+
})
221+
}
222+
223+
// TryWithErrorAndMgr executes a function that returns (T, error) using the specified manager
224+
// and returns a Promise. This is useful for Go functions that follow the standard (value, error) return pattern
225+
func TryWithErrorAndMgr[T any](manager *PromiseMgr, fn func() (T, error)) *Promise[T] {
226+
return NewWithMgr(manager, func(resolve func(T), reject func(error)) {
227+
result, err := fn()
228+
if err != nil {
229+
reject(err)
230+
} else {
231+
resolve(result)
232+
}
233+
})
234+
}

promise_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,3 +1223,114 @@ func TestErrorHandlingOptimization(t *testing.T) {
12231223
t.Errorf("Expected cause to be original error, but got: %v", promiseErr2.Cause)
12241224
}
12251225
}
1226+
1227+
// TestTry tests the Try function
1228+
func TestTry(t *testing.T) {
1229+
t.Run("Try with successful function", func(t *testing.T) {
1230+
promise := Try(func() string {
1231+
return "success"
1232+
})
1233+
1234+
result, err := promise.Await()
1235+
if err != nil {
1236+
t.Errorf("Expected no error, got %v", err)
1237+
}
1238+
if result != "success" {
1239+
t.Errorf("Expected 'success', got %s", result)
1240+
}
1241+
})
1242+
1243+
t.Run("Try with panic", func(t *testing.T) {
1244+
promise := Try(func() string {
1245+
panic("test panic")
1246+
})
1247+
1248+
_, err := promise.Await()
1249+
if err == nil {
1250+
t.Error("Expected error for panic, got nil")
1251+
}
1252+
1253+
var promiseErr *PromiseError
1254+
if !errors.As(err, &promiseErr) {
1255+
t.Error("Expected PromiseError type")
1256+
}
1257+
if promiseErr.Type != PanicError {
1258+
t.Errorf("Expected PanicError type, got %v", promiseErr.Type)
1259+
}
1260+
})
1261+
1262+
t.Run("Try with error panic", func(t *testing.T) {
1263+
testErr := errors.New("test error")
1264+
promise := Try(func() string {
1265+
panic(testErr)
1266+
})
1267+
1268+
_, err := promise.Await()
1269+
if err == nil {
1270+
t.Error("Expected error for panic, got nil")
1271+
}
1272+
1273+
var promiseErr *PromiseError
1274+
if !errors.As(err, &promiseErr) {
1275+
t.Error("Expected PromiseError type")
1276+
}
1277+
if promiseErr.Type != PanicError {
1278+
t.Errorf("Expected PanicError type, got %v", promiseErr.Type)
1279+
}
1280+
if promiseErr.Cause != testErr {
1281+
t.Errorf("Expected cause to be testErr, got %v", promiseErr.Cause)
1282+
}
1283+
})
1284+
}
1285+
1286+
// TestTryWithError tests the TryWithError function
1287+
func TestTryWithError(t *testing.T) {
1288+
t.Run("TryWithError with successful function", func(t *testing.T) {
1289+
promise := TryWithError(func() (string, error) {
1290+
return "success", nil
1291+
})
1292+
1293+
result, err := promise.Await()
1294+
if err != nil {
1295+
t.Errorf("Expected no error, got %v", err)
1296+
}
1297+
if result != "success" {
1298+
t.Errorf("Expected 'success', got %s", result)
1299+
}
1300+
})
1301+
1302+
t.Run("TryWithError with error return", func(t *testing.T) {
1303+
testErr := errors.New("test error")
1304+
promise := TryWithError(func() (string, error) {
1305+
return "", testErr
1306+
})
1307+
1308+
_, err := promise.Await()
1309+
if err == nil {
1310+
t.Error("Expected error, got nil")
1311+
}
1312+
// The error might be wrapped, so check if it contains the original error
1313+
if !errors.Is(err, testErr) && !strings.Contains(err.Error(), testErr.Error()) {
1314+
t.Errorf("Expected error to contain testErr, got %v", err)
1315+
}
1316+
})
1317+
1318+
t.Run("TryWithError with panic", func(t *testing.T) {
1319+
promise := TryWithError(func() (string, error) {
1320+
panic("test panic")
1321+
})
1322+
1323+
_, err := promise.Await()
1324+
if err == nil {
1325+
t.Error("Expected error for panic, got nil")
1326+
}
1327+
1328+
var promiseErr *PromiseError
1329+
if !errors.As(err, &promiseErr) {
1330+
t.Error("Expected PromiseError type")
1331+
}
1332+
if promiseErr.Type != PanicError {
1333+
t.Errorf("Expected PanicError type, got %v", promiseErr.Type)
1334+
}
1335+
})
1336+
}

0 commit comments

Comments
 (0)