Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sdk)!: support Map.tryGet() #4523

Merged
merged 3 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions docs/docs/04-standard-library/03-std/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,7 @@ Immutable Map.
| <code><a href="#@winglang/sdk.std.Map.has">has</a></code> | Returns a boolean indicating whether an element with the specified key exists or not. |
| <code><a href="#@winglang/sdk.std.Map.keys">keys</a></code> | Returns the keys of this map. |
| <code><a href="#@winglang/sdk.std.Map.size">size</a></code> | Returns the number of elements in the map. |
| <code><a href="#@winglang/sdk.std.Map.tryGet">tryGet</a></code> | Optionally returns a specified element from the map. |
| <code><a href="#@winglang/sdk.std.Map.values">values</a></code> | Returns the values of this map. |

---
Expand Down Expand Up @@ -1158,6 +1159,22 @@ Returns the number of elements in the map.

TODO: For now this has to be a method rather than a getter as macros only work on methods https://github.com/winglang/wing/issues/1658

##### `tryGet` <a name="tryGet" id="@winglang/sdk.std.Map.tryGet"></a>

```wing
tryGet(key: str): <T>
```

Optionally returns a specified element from the map.

###### `key`<sup>Required</sup> <a name="key" id="@winglang/sdk.std.Map.tryGet.parameter.key"></a>

- *Type:* str

The key of the element to return.

---

##### `values` <a name="values" id="@winglang/sdk.std.Map.values"></a>

```wing
Expand Down Expand Up @@ -1624,6 +1641,7 @@ Mutable Map.
| <code><a href="#@winglang/sdk.std.MutMap.keys">keys</a></code> | Returns the keys of this map. |
| <code><a href="#@winglang/sdk.std.MutMap.set">set</a></code> | Adds or updates an entry in a Map object with a specified key and a value. |
| <code><a href="#@winglang/sdk.std.MutMap.size">size</a></code> | Returns the number of elements in the map. |
| <code><a href="#@winglang/sdk.std.MutMap.tryGet">tryGet</a></code> | Optionally returns a specified element from the map. |
| <code><a href="#@winglang/sdk.std.MutMap.values">values</a></code> | Returns the values of this map. |

---
Expand Down Expand Up @@ -1739,6 +1757,22 @@ Returns the number of elements in the map.

TODO: For now this has to be a method rather than a getter as macros only work on methods https://github.com/winglang/wing/issues/1658

##### `tryGet` <a name="tryGet" id="@winglang/sdk.std.MutMap.tryGet"></a>

```wing
tryGet(key: str): <T>
```

Optionally returns a specified element from the map.

###### `key`<sup>Required</sup> <a name="key" id="@winglang/sdk.std.MutMap.tryGet.parameter.key"></a>

- *Type:* str

The key of the element to return.

---

##### `values` <a name="values" id="@winglang/sdk.std.MutMap.values"></a>

```wing
Expand Down
26 changes: 22 additions & 4 deletions examples/tests/sdk_tests/std/map.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -70,27 +70,38 @@ test "size()" {

let greeting = { "hello" => "there!" };
assert(greeting.get("hello") == "there!");
try {
greeting.get("bye");
} catch err {
assert(err.contains("does not contain key: \"bye\""));
}


let general: str? = greeting.get("grievous");
let general: str? = greeting.tryGet("grievous");
hasanaburayyan marked this conversation as resolved.
Show resolved Hide resolved
assert(general == nil);

let mutGreeting = MutMap<str>{ "general" => "kenobi" };
assert(mutGreeting.get("general") == "kenobi");

let Viceroy: str? = mutGreeting.get("gunray");
let Viceroy: str? = mutGreeting.tryGet("gunray");
assert(Viceroy == nil);

test "get()" {
let greeting = { "hello" => "there!" };
assert(greeting.get("hello") == "there!");
try {
greeting.get("bye");
} catch err {
assert(err.contains("does not contain key: \"bye\""));
}

let general: str? = greeting.get("grievous");
let general: str? = greeting.tryGet("grievous");
assert(general == nil);

let mutGreeting = MutMap<str>{ "general" => "kenobi" };
assert(mutGreeting.get("general") == "kenobi");

let Viceroy: str? = mutGreeting.get("gunray");
let Viceroy: str? = mutGreeting.tryGet("gunray");
assert(Viceroy == nil);
}

Expand Down Expand Up @@ -254,3 +265,10 @@ test "delete()" {
sithTriumvirate.delete("sion");
assert(sithTriumvirate == MutMap<str> { "traya" => "lord of betrayal" });
}


// testing optionals
let mapOfOptionalString = MutMap<str?>{ };
mapOfOptionalString.set("a", nil);
let b = mapOfOptionalString.get("a");
assert(b == nil);
8 changes: 4 additions & 4 deletions examples/tests/valid/api_cors_custom.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ test "GET /users has cors headers" {
t.Assert.equalStr(headers.get("access-control-expose-headers"), "Content-Type");

// OPTIONS cors headers are not set
t.Assert.isNil(headers.get("access-control-allow-headers"));
t.Assert.isNil(headers.get("access-control-allow-methods"));
t.Assert.isNil(headers.tryGet("access-control-allow-headers"));
t.Assert.isNil(headers.tryGet("access-control-allow-methods"));
}

test "OPTIONS /users has cors headers" {
Expand All @@ -52,8 +52,8 @@ test "OPTIONS /users has cors headers" {
t.Assert.equalStr(headers.get("access-control-allow-origin"), "winglang.io");

// Other cors headers are not set
t.Assert.isNil(headers.get("access-control-expose-headers"));
t.Assert.isNil(headers.get("access-control-allow-credentials"));
t.Assert.isNil(headers.tryGet("access-control-expose-headers"));
t.Assert.isNil(headers.tryGet("access-control-allow-credentials"));
}

test "OPTIONS /users responds with proper headers for requested" {
Expand Down
8 changes: 4 additions & 4 deletions examples/tests/valid/api_cors_default.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ test "GET /users has default cors headers" {
t.Assert.equalStr(headers.get("access-control-expose-headers"), "");

// OPTIONS headers are not set
t.Assert.isNil(headers.get("access-control-allow-headers"));
t.Assert.isNil(headers.get("access-control-allow-methods"));
t.Assert.isNil(headers.tryGet("access-control-allow-headers"));
t.Assert.isNil(headers.tryGet("access-control-allow-methods"));
}

test "OPTIONS /users has default cors headers" {
Expand All @@ -44,7 +44,7 @@ test "OPTIONS /users has default cors headers" {
t.Assert.equalStr(headers.get("access-control-allow-origin"), "*");

// Other headers are not set
t.Assert.isNil(headers.get("access-control-allow-credentials"));
t.Assert.isNil(headers.get("access-control-expose-headers"));
t.Assert.isNil(headers.tryGet("access-control-allow-credentials"));
t.Assert.isNil(headers.tryGet("access-control-expose-headers"));
}

20 changes: 20 additions & 0 deletions examples/tests/valid/container_types.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,32 @@ assert(m9.values().at(0) == "a1");
assert(m9.values().at(1) == "b1");
assert(m9.values().at(2) == "c1");
for val in m9.keys() {

assert(!val.endsWith("1"));
}
for val in m9.values() {
assert(val.endsWith("1"));
}

// try get something exists
if let k = m9.tryGet("a") {
assert(k == "a1");
} else {
assert(false); // should never happen
}

// try get something doesnt exist
if let k = m9.tryGet("def-fake") {
assert(false); // should never happen
}

// get something that doesnt exist
try {
m9.get("def-fake");
} catch err {
assert(err.contains("does not contain key: \"def-fake\""));
}

//Set tests
let emptySet = Set<num>{};
assert(emptySet.size == 0);
Expand Down
6 changes: 3 additions & 3 deletions examples/tests/valid/website_with_api.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ test "GET /users" {

let headers = response.headers;
t.Assert.equalNum(response.status, 200);

t.Assert.equalStr(headers.get("access-control-allow-origin"), "*");

t.Assert.equalStr(headers.get("access-control-expose-headers"), "Content-Type");
t.Assert.equalStr(headers.get("access-control-allow-credentials"), "false");

t.Assert.isNil(headers.get("access-control-allow-headers"));
t.Assert.isNil(headers.get("access-control-allow-methods"));
t.Assert.isNil(headers.tryGet("access-control-allow-headers"));
t.Assert.isNil(headers.tryGet("access-control-allow-methods"));
}

test "OPTIONS /users" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ source: libs/wingc/src/jsify/tests.rs

```js
"use strict";
module.exports = function({ $_s___hello___length }) {
module.exports = function({ $__obj__key_______if____key_in_obj___throw_new_Error__Map_does_not_contain_key_____key______return_obj_key______s___hello___length }) {
class $Closure1 {
constructor({ }) {
const $obj = (...args) => this.handle(...args);
Object.setPrototypeOf($obj, this);
return $obj;
}
async handle() {
{((cond) => {if (!cond) throw new Error("assertion failed: s.get(\"hello\").length == 3")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })($_s___hello___length,3)))};
{((cond) => {if (!cond) throw new Error("assertion failed: s.get(\"hello\").length == 3")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })($__obj__key_______if____key_in_obj___throw_new_Error__Map_does_not_contain_key_____key______return_obj_key______s___hello___length,3)))};
}
}
return $Closure1;
Expand All @@ -52,7 +52,7 @@ class $Root extends $stdlib.std.Resource {
static _toInflightType(context) {
return `
require("./inflight.$Closure1-1.js")({
$_s___hello___length: ${context._lift((s)["hello"].length)},
$__obj__key_______if____key_in_obj___throw_new_Error__Map_does_not_contain_key_____key______return_obj_key______s___hello___length: ${context._lift(((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(s, "hello").length)},
})
`;
}
Expand All @@ -72,7 +72,7 @@ class $Root extends $stdlib.std.Resource {
}
_registerBind(host, ops) {
if (ops.includes("handle")) {
$Closure1._registerBindObject((s)["hello"].length, host, []);
$Closure1._registerBindObject(((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(s, "hello").length, host, []);
}
super._registerBind(host, ops);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ source: libs/wingc/src/lsp/completions.rs
value: "```wing\nsize: (): num\n```\n---\nReturns the number of elements in the map.\n\n\n### Returns\nThe number of elements in map\n\n### Remarks\nTODO: For now this has to be a method rather than a getter as macros only work on methods https://github.com/winglang/wing/issues/1658"
sortText: ff|size
insertText: size()
- label: tryGet
kind: 2
detail: "(key: str): T1?"
documentation:
kind: markdown
value: "```wing\ntryGet: (key: str): T1?\n```\n---\nOptionally returns a specified element from the map.\n\n\n### Returns\nThe element associated with the specified key, or undefined if the key can't be found"
sortText: ff|tryGet
insertText: tryGet($0)
insertTextFormat: 2
command:
title: triggerParameterHints
command: editor.action.triggerParameterHints
- label: values
kind: 2
detail: "(): Array"
Expand Down
30 changes: 28 additions & 2 deletions libs/wingsdk/src/std/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class Map {
* If the value that is associated to the provided key is an object, then you will get a reference
* to that object and any change made to that object will effectively modify it inside the map.
*
* @macro ($self$)[$args$]
* @macro ((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })($self$, $args$)
*
* @param key The key of the element to return.
* @returns The element associated with the specified key, or undefined if the key can't be found
Expand All @@ -49,6 +49,19 @@ export class Map {
throw new Error("Macro");
}

/**
* Optionally returns a specified element from the map.
*
* @macro ($self$)[$args$]
*
* @param key The key of the element to return.
* @returns The element associated with the specified key, or undefined if the key can't be found
*/
public tryGet(key: string): T1 | undefined {
key;
throw new Error("Macro");
}

/**
* Returns a boolean indicating whether an element with the specified key exists or not.
*
Expand Down Expand Up @@ -162,7 +175,7 @@ export class MutMap {
* If the value that is associated to the provided key is an object, then you will get a reference
* to that object and any change made to that object will effectively modify it inside the map.
*
* @macro ($self$)[$args$]
* @macro ((obj, key) => { if (!(key in obj)) throw new Error(`MutMap does not contain key: "${key}"`); return obj[key]; })($self$, $args$)
*
* @param key The key of the element to return.
* @returns The element associated with the specified key, or undefined if the key can't be found
Expand All @@ -172,6 +185,19 @@ export class MutMap {
throw new Error("Macro");
}

/**
* Optionally returns a specified element from the map.
*
* @macro ($self$)[$args$]
*
* @param key The key of the element to return.
* @returns The element associated with the specified key, or undefined if the key can't be found
*/
public tryGet(key: string): T1 | undefined {
key;
throw new Error("Macro");
}

/**
* Returns a boolean indicating whether an element with the specified key exists or not.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module.exports = function({ $api_url, $http_Util }) {
async handle() {
const url = ($api_url + "/path");
const response = (await $http_Util.get(url));
{((cond) => {if (!cond) throw new Error("assertion failed: response.headers.get(\"access-control-allow-origin\") == \"*\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((response.headers)["access-control-allow-origin"],"*")))};
{((cond) => {if (!cond) throw new Error("assertion failed: response.headers.get(\"access-control-allow-origin\") == \"*\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(response.headers, "access-control-allow-origin"),"*")))};
}
}
return $Closure2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ module.exports = function({ $cloud_HttpMethod }) {
}
async handle(req) {
{((cond) => {if (!cond) throw new Error("assertion failed: req.method == cloud.HttpMethod.DELETE")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(req.method,$cloud_HttpMethod.DELETE)))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.query?.get(\"all\") == \"true\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((req.query)["all"],"true")))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.query?.get(\"page\") == \"6\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((req.query)["page"],"6")))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.query?.get(\"all\") == \"true\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(req.query, "all"),"true")))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.query?.get(\"page\") == \"6\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(req.query, "page"),"6")))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.path == \"/path\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(req.path,"/path")))};
return ({"status": 200,"body": (req.query)["page"]});
return ({"status": 200,"body": ((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(req.query, "page")});
}
}
return $Closure1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module.exports = function({ $body, $cloud_HttpMethod }) {
{((cond) => {if (!cond) throw new Error("assertion failed: req.method == cloud.HttpMethod.GET")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(req.method,$cloud_HttpMethod.GET)))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.path == \"/path\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(req.path,"/path")))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.body?.length == 0")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(req.body?.length,0)))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.headers?.get(\"content-type\") == \"application/json\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((req.headers)["content-type"],"application/json")))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.headers?.get(\"content-type\") == \"application/json\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(req.headers, "content-type"),"application/json")))};
return ({"status": 200,"body": $body});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ module.exports = function({ $_id, $body, $cloud_HttpMethod, $std_Json }) {
}
async handle(req) {
{((cond) => {if (!cond) throw new Error("assertion failed: req.method == cloud.HttpMethod.PATCH")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(req.method,$cloud_HttpMethod.PATCH)))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.vars?.get(\"id\") == _id")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((req.vars)["id"],$_id)))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.vars?.get(\"id\") == _id")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(req.vars, "id"),$_id)))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.path == \"/path/\"+ _id")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(req.path,("/path/" + $_id))))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.body == Json.stringify(body)")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(req.body,((args) => { return JSON.stringify(args[0], null, args[1]?.indent) })([$body]))))};
{((cond) => {if (!cond) throw new Error("assertion failed: req.headers?.get(\"content-type\") == \"application/json\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((req.headers)["content-type"],"application/json")))};
return ({"status": 200,"body": (req.vars)["id"]});
{((cond) => {if (!cond) throw new Error("assertion failed: req.headers?.get(\"content-type\") == \"application/json\"")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(req.headers, "content-type"),"application/json")))};
return ({"status": 200,"body": ((obj, key) => { if (!(key in obj)) throw new Error(`Map does not contain key: "${key}"`); return obj[key]; })(req.vars, "id")});
}
}
return $Closure1;
Expand Down
Loading