Skip to content

Commit f8fddd6

Browse files
committed
Merge branch 'main' into sdk-long-running-discovery
2 parents 7721c70 + bbf0b95 commit f8fddd6

File tree

28 files changed

+461
-53
lines changed

28 files changed

+461
-53
lines changed

libs/common/src/typegraph/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ pub struct TypeMeta {
9898
pub auths: Vec<Auth>,
9999
pub rate: Option<Rate>,
100100
pub version: String,
101+
pub random_seed: Option<u32>,
101102
}
102103

103104
#[cfg_attr(feature = "codegen", derive(JsonSchema))]

libs/common/src/typegraph/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub enum Injection {
5050
Secret(InjectionData<String>),
5151
Parent(InjectionData<u32>),
5252
Dynamic(InjectionData<String>),
53+
Random(InjectionData<String>),
5354
}
5455

5556
#[cfg_attr(feature = "codegen", derive(JsonSchema))]
@@ -116,7 +117,6 @@ pub enum StringFormat {
116117
Ean,
117118
Date,
118119
DateTime,
119-
// Path,
120120
Phone,
121121
}
122122

typegate/deno.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

typegate/src/engine/planner/args.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ class ArgumentCollector {
245245
private collectArgImpl(node: CollectNode): ComputeArg {
246246
const { astNode, typeIdx } = node;
247247

248-
const typ = this.tg.type(typeIdx);
248+
const typ: TypeNode = this.tg.type(typeIdx);
249249

250250
this.addPoliciesFrom(typeIdx);
251251

@@ -695,6 +695,10 @@ class ArgumentCollector {
695695
}
696696
return generator;
697697
}
698+
699+
case "random": {
700+
return () => this.tg.getRandom(typ);
701+
}
698702
}
699703
}
700704

typegate/src/runtimes/random.ts

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -78,48 +78,106 @@ export class RandomRuntime extends Runtime {
7878

7979
execute(typ: TypeNode): Resolver {
8080
return () => {
81-
return this.randomizeRecursively(typ);
81+
return randomizeRecursively(typ, this.chance, this._tgTypes);
8282
};
8383
}
84+
}
8485

85-
randomizeRecursively(typ: TypeNode): any {
86-
const config = typ.config ?? {};
87-
if (Object.prototype.hasOwnProperty.call(config, "gen")) {
88-
const { gen, ...arg } = config;
89-
return this.chance[gen as string](arg);
86+
export default function randomizeRecursively(
87+
typ: TypeNode,
88+
chance: typeof Chance,
89+
tgTypes: TypeNode[],
90+
): any {
91+
const config = typ.config ?? {};
92+
if (Object.prototype.hasOwnProperty.call(config, "gen")) {
93+
const { gen, ...arg } = config;
94+
return chance[gen as string](arg);
95+
}
96+
switch (typ.type) {
97+
case "object":
98+
return {};
99+
case "optional": {
100+
const childNodeName = tgTypes[typ.item];
101+
return chance.bool()
102+
? randomizeRecursively(childNodeName, chance, tgTypes)
103+
: null;
90104
}
91-
switch (typ.type) {
92-
case "object":
93-
return {};
94-
case "optional": {
95-
const childNodeName = this.getTgTypeNameByIndex(typ.item);
96-
return this.chance.bool()
97-
? this.randomizeRecursively(childNodeName)
98-
: null;
105+
case "integer":
106+
return chance.integer();
107+
case "string":
108+
if (typ.format === "uuid") {
109+
return chance.guid();
110+
}
111+
if (typ.format === "email") {
112+
return chance.email();
113+
}
114+
if (typ.format === "uri") {
115+
return chance.url();
116+
}
117+
if (typ.format === "hostname") {
118+
return chance.domain();
119+
}
120+
if (typ.format === "date-time") {
121+
const randomDate = chance.date();
122+
123+
// Get the timestamp of the random date
124+
const timestamp = randomDate.getTime();
125+
console.log(randomDate);
126+
127+
// Create a new Date object with the timestamp adjusted for the local timezone offset
128+
const dateInUtc = new Date(
129+
timestamp - randomDate.getTimezoneOffset() * 60000,
130+
);
131+
return dateInUtc.toISOString();
132+
}
133+
if (typ.format === "phone") {
134+
return chance.phone();
99135
}
100-
case "integer":
101-
return this.chance.integer();
102-
case "string":
103-
if (typ.format === "uuid") {
104-
return this.chance.guid();
105-
}
106-
if (typ.format === "email") {
107-
return this.chance.email();
108-
}
109-
return this.chance.string();
110-
case "boolean":
111-
return this.chance.bool();
112-
case "list": {
113-
const res = [];
114-
let size = this.chance.integer({ min: 1, max: 10 });
115-
const childNodeName = this.getTgTypeNameByIndex(typ.items);
116-
while (size--) {
117-
res.push(this.randomizeRecursively(childNodeName));
118-
}
119-
return res;
136+
if (typ.format == "ean") {
137+
return generateEAN(chance);
120138
}
121-
default:
122-
throw new Error(`type not supported "${typ.type}"`);
139+
return chance.string();
140+
case "boolean":
141+
return chance.bool();
142+
case "list": {
143+
const res = [];
144+
let size = chance.integer({ min: 1, max: 10 });
145+
const childNodeName = tgTypes[typ.items];
146+
while (size--) {
147+
res.push(
148+
randomizeRecursively(childNodeName, chance, tgTypes),
149+
);
150+
}
151+
return res;
123152
}
153+
154+
default:
155+
throw new Error(`type not supported "${typ.type}"`);
124156
}
125157
}
158+
159+
function generateEAN(chance: typeof Chance) {
160+
let ean = "0";
161+
162+
for (let i = 1; i <= 11; i++) {
163+
ean += chance.integer({ min: 0, max: 9 }).toString();
164+
}
165+
166+
const checkDigit = calculateCheckDigit(ean);
167+
ean += checkDigit;
168+
169+
return ean;
170+
}
171+
172+
function calculateCheckDigit(ean: string) {
173+
const digits = ean.split("").map(Number);
174+
175+
let sum = 0;
176+
for (let i = 0; i < digits.length; i++) {
177+
sum += (i % 2 === 0) ? digits[i] : digits[i] * 3;
178+
}
179+
180+
const checkDigit = (10 - (sum % 10)) % 10;
181+
182+
return checkDigit.toString();
183+
}

typegate/src/typegraph/mod.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { DenoRuntime } from "../runtimes/deno/deno.ts";
77
import { Runtime } from "../runtimes/Runtime.ts";
88
import { ensure, ensureNonNullable } from "../utils.ts";
99
import { typegraph_validate } from "native";
10+
import Chance from "chance";
1011

1112
import {
1213
initAuth,
@@ -41,6 +42,7 @@ import type {
4142
import { InternalAuth } from "../services/auth/protocols/internal.ts";
4243
import { Protocol } from "../services/auth/protocols/protocol.ts";
4344
import { initRuntime } from "../runtimes/mod.ts";
45+
import randomizeRecursively from "../runtimes/random.ts";
4446

4547
export { Cors, Rate, TypeGraphDS, TypeMaterializer, TypePolicy, TypeRuntime };
4648

@@ -349,6 +351,30 @@ export class TypeGraph {
349351
);
350352
}
351353

354+
getRandom(
355+
schema: TypeNode,
356+
): number | string | null {
357+
const tgTypes: TypeNode[] = this.tg.types;
358+
let seed = 12; // default seed
359+
if (
360+
this.tg.meta.random_seed !== undefined &&
361+
this.tg.meta.random_seed !== null
362+
) {
363+
seed = this.tg.meta.random_seed;
364+
}
365+
const chance: typeof Chance = new Chance(seed);
366+
367+
try {
368+
const result = randomizeRecursively(schema, chance, tgTypes);
369+
370+
return result;
371+
} catch (_) {
372+
throw new Error(
373+
`invalid type for random injection: ${schema.type}`,
374+
);
375+
}
376+
}
377+
352378
nextBatcher = (
353379
type: TypeNode,
354380
): Batcher => {

typegate/src/typegraph/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ export type Injection = {
223223
} | {
224224
source: "dynamic";
225225
data: InjectionDataFor_String;
226+
} | {
227+
source: "random";
228+
data: InjectionDataFor_String;
226229
};
227230
export type InjectionDataFor_String = SingleValueFor_String | {
228231
[k: string]: string;
@@ -503,6 +506,7 @@ export interface TypeMeta {
503506
auths: Auth[];
504507
rate?: Rate | null;
505508
version: string;
509+
random_seed: number | undefined;
506510
}
507511
export interface Queries {
508512
dynamic: boolean;

typegate/tests/e2e/typegraph/__snapshots__/typegraph_test.ts.snap

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,8 @@ snapshot[`typegraphs creation 1`] = `
326326
"context_identifier": "user",
327327
"local_excess": 5
328328
},
329-
"version": "0.0.3"
329+
"version": "0.0.3",
330+
"random_seed": null
330331
}
331332
}
332333
]'
@@ -533,7 +534,8 @@ snapshot[`typegraphs creation 2`] = `
533534
},
534535
"auths": [],
535536
"rate": null,
536-
"version": "0.0.3"
537+
"version": "0.0.3",
538+
"random_seed": null
537539
}
538540
}
539541
]\`
@@ -815,7 +817,8 @@ snapshot[`typegraphs creation 3`] = `
815817
},
816818
"auths": [],
817819
"rate": null,
818-
"version": "0.0.3"
820+
"version": "0.0.3",
821+
"random_seed": null
819822
}
820823
}
821824
]\`
@@ -1147,7 +1150,8 @@ snapshot[`typegraphs creation 4`] = `
11471150
"context_identifier": "user",
11481151
"local_excess": 5
11491152
},
1150-
"version": "0.0.3"
1153+
"version": "0.0.3",
1154+
"random_seed": null
11511155
}
11521156
}
11531157
]'
@@ -1354,7 +1358,8 @@ snapshot[`typegraphs creation 5`] = `
13541358
},
13551359
"auths": [],
13561360
"rate": null,
1357-
"version": "0.0.3"
1361+
"version": "0.0.3",
1362+
"random_seed": null
13581363
}
13591364
}
13601365
]\`
@@ -1636,7 +1641,8 @@ snapshot[`typegraphs creation 6`] = `
16361641
},
16371642
"auths": [],
16381643
"rate": null,
1639-
"version": "0.0.3"
1644+
"version": "0.0.3",
1645+
"random_seed": null
16401646
}
16411647
}
16421648
]\`
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from typegraph.policy import Policy
2+
from typegraph.runtimes.deno import DenoRuntime
3+
4+
from typegraph import Graph, t, typegraph
5+
6+
7+
@typegraph()
8+
def random_injection(g: Graph):
9+
pub = Policy.public()
10+
deno = DenoRuntime()
11+
12+
user = t.struct(
13+
{
14+
"id": t.uuid().from_random(),
15+
"ean": t.ean().from_random(),
16+
"name": t.string(config={"gen": "name"}).from_random(),
17+
"age": t.integer(config={"gen": "age", "type": "adult"}).from_random(),
18+
"married": t.boolean().from_random(),
19+
"birthday": t.datetime().from_random(),
20+
"friends": t.list(t.string(config={"gen": "first"})).from_random(),
21+
"phone": t.string(config={"gen": "phone"}).from_random(),
22+
"gender": t.string(config={"gen": "gender"}).from_random(),
23+
"firstname": t.string(config={"gen": "first"}).from_random(),
24+
"lastname": t.string(config={"gen": "last"}).from_random(),
25+
"occupation": t.string(config={"gen": "profession"}).from_random(),
26+
"street": t.string(config={"gen": "address"}).from_random(),
27+
"city": t.string(config={"gen": "city"}).from_random(),
28+
"postcode": t.string(config={"gen": "postcode"}).from_random(),
29+
"country": t.string(
30+
config={"gen": "country", "full": "true"}
31+
).from_random(),
32+
"uri": t.uri().from_random(),
33+
"hostname": t.string(format="hostname").from_random(),
34+
}
35+
)
36+
37+
random_list = t.struct(
38+
{
39+
"names": t.list(t.string(config={"gen": "name"})).from_random(),
40+
}
41+
)
42+
# Configure random injection seed value or the default will be used
43+
g.configure_random_injection(seed=1)
44+
g.expose(
45+
pub,
46+
randomUser=deno.identity(user),
47+
randomList=deno.identity(random_list),
48+
)

0 commit comments

Comments
 (0)