create-cloesce 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,36 +1,45 @@
|
|
|
1
1
|
// Here, we import the generated backend code, which includes all the types
|
|
2
2
|
// defined in the `schema.clo` file
|
|
3
|
-
import * as
|
|
3
|
+
import * as clo from "@cloesce/backend.js";
|
|
4
4
|
import { CfReadableStream } from "@cloesce/backend.js";
|
|
5
5
|
|
|
6
6
|
// The "cloesce" library provides basic types and utilities for building a Cloesce backend
|
|
7
7
|
import { HttpResult } from "cloesce";
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
//
|
|
9
|
+
|
|
10
|
+
// To implement the API routes of a model or service defined in `schema.clo`,
|
|
11
|
+
// we can use the `impl` method on it's respective generated namespace.
|
|
12
|
+
//
|
|
13
|
+
// In addition to defining the routes, `Weather` will inherit all of the static utility methods
|
|
14
|
+
// from the generated `Orm`, `Key` and `Source`.
|
|
11
15
|
//
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// All models have a `KeyFormat` namespace which provides utilities for generating
|
|
16
|
+
// The only place where generated code should be directly used is in `impl` blocks like this.
|
|
17
|
+
export const Weather = clo.Weather.impl({
|
|
18
|
+
async uploadPhoto(self, e, s: CfReadableStream) {
|
|
19
|
+
// All models have a `Key` namespace which provides utilities for generating
|
|
17
20
|
// KV and R2 keys for that model.
|
|
18
|
-
const key =
|
|
21
|
+
const key = this.Key.photo(self.id);
|
|
19
22
|
await e.bucket.put(key, s);
|
|
20
|
-
}
|
|
23
|
+
},
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
downloadPhoto(self) {
|
|
26
|
+
// Any method can return an HttpResult, which allows you to specify the
|
|
27
|
+
// Response status code, body, and headers.
|
|
25
28
|
if (!self.photo) {
|
|
26
29
|
return HttpResult.fail(404, "Photo not found");
|
|
27
30
|
}
|
|
28
31
|
return HttpResult.ok(200, self.photo.body);
|
|
29
32
|
}
|
|
30
|
-
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// `WeatherReport` has no API routes defined.
|
|
36
|
+
//
|
|
37
|
+
// Instead of using the generated namespace directly, we can still create an implementation with `impl`
|
|
38
|
+
// to avoid passing the generated code around the rest of our application.
|
|
39
|
+
export const WeatherReport = clo.WeatherReport.impl({});
|
|
31
40
|
|
|
32
41
|
export default {
|
|
33
|
-
async fetch(request: Request, env:
|
|
42
|
+
async fetch(request: Request, env: clo.Env): Promise<Response> {
|
|
34
43
|
// preflight
|
|
35
44
|
if (request.method === "OPTIONS") {
|
|
36
45
|
return HttpResult.ok(200, undefined, {
|
|
@@ -41,8 +50,8 @@ export default {
|
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
// Run Cloesce app
|
|
44
|
-
const app = (await
|
|
45
|
-
.register(
|
|
53
|
+
const app = (await clo.cloesce())
|
|
54
|
+
.register(Weather);
|
|
46
55
|
|
|
47
56
|
const result = await app.run(request, env);
|
|
48
57
|
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// It does not replace the wrangler config, but does result in a generated version.
|
|
3
3
|
env {
|
|
4
4
|
// The `d1` block describes all D1 database bindings
|
|
5
|
-
d1 {
|
|
6
|
-
db
|
|
5
|
+
d1 {
|
|
6
|
+
db
|
|
7
7
|
// db2
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
// The `r2` block describes all R2 bucket bindings
|
|
11
|
-
r2 {
|
|
12
|
-
bucket
|
|
11
|
+
r2 {
|
|
12
|
+
bucket
|
|
13
13
|
// bucket2
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -26,7 +26,7 @@ model WeatherReport {
|
|
|
26
26
|
primary {
|
|
27
27
|
id: int
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
// A `nav` block describes a relationship between two models.
|
|
31
31
|
// In this case, it is a one-to-many relationship between WeatherReport and Weather,
|
|
32
32
|
// where WeatherReport has many Weathers.
|
|
@@ -35,11 +35,11 @@ model WeatherReport {
|
|
|
35
35
|
// references the `id` field in the WeatherReport model.
|
|
36
36
|
//
|
|
37
37
|
// This will resolve to a navigation field named `weatherEntries` in the WeatherReport model,
|
|
38
|
-
//which is an array of Weather objects.
|
|
38
|
+
// which is an array of Weather objects.
|
|
39
39
|
nav (Weather::weatherReportId) {
|
|
40
40
|
weatherEntries
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
// All fields that are not apart of a block are just regular fields in the table.
|
|
44
44
|
title: string
|
|
45
45
|
description: string
|
|
@@ -51,21 +51,24 @@ model Weather {
|
|
|
51
51
|
primary {
|
|
52
52
|
id: int
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
// A `foreign` block describes a one to one relationship between two models.
|
|
56
56
|
// It translates directly to a foreign key constraint in the database (`weatherReportId` references `id` in WeatherReport).
|
|
57
57
|
foreign (WeatherReport::id) {
|
|
58
58
|
weatherReportId
|
|
59
|
-
|
|
59
|
+
|
|
60
|
+
|
|
60
61
|
// A `nav` block inside a `foreign` block generates a navigation field,
|
|
61
62
|
// meaning the backend and client will have a WeatherReport object named `weatherReport` nested inside the Weather model.
|
|
62
|
-
nav {
|
|
63
|
+
nav {
|
|
64
|
+
weatherReport
|
|
65
|
+
}
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
r2 (bucket, "weather/photos/{id}.jpg") {
|
|
66
69
|
photo
|
|
67
70
|
}
|
|
68
|
-
|
|
71
|
+
|
|
69
72
|
dateTime: date
|
|
70
73
|
location: string
|
|
71
74
|
temperature: int
|
|
@@ -83,7 +86,7 @@ api Weather {
|
|
|
83
86
|
// In this case, `uploadPhoto` accepts the Wrangler environment (dependency injected),
|
|
84
87
|
// and a stream (the photo to be uploaded).
|
|
85
88
|
post uploadPhoto(self, e: env, s: stream) -> void
|
|
86
|
-
|
|
89
|
+
|
|
87
90
|
// By default, Cloesce will hydrate a `self` instance with all 1:1, KV, R2,
|
|
88
91
|
// and the near side of 1:M/M:M relationships.
|
|
89
92
|
//
|
|
@@ -98,5 +101,7 @@ api Weather {
|
|
|
98
101
|
//
|
|
99
102
|
// In this case, the include tree has only the `photo` field of `Weather`.
|
|
100
103
|
source R2Only for Weather {
|
|
101
|
-
include {
|
|
104
|
+
include {
|
|
105
|
+
photo
|
|
106
|
+
}
|
|
102
107
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Miniflare } from "miniflare";
|
|
2
2
|
import { describe, test, expect, beforeAll } from "vitest";
|
|
3
|
-
import
|
|
4
|
-
import { Weather } from "@api/main.js"
|
|
3
|
+
import { Weather, WeatherReport } from "@api/main.js"
|
|
5
4
|
import { cloesce } from "@cloesce/backend.js";
|
|
6
5
|
|
|
7
6
|
async function createTestEnv() {
|
|
@@ -56,7 +55,7 @@ describe("Miniflare Integration Tests", () => {
|
|
|
56
55
|
const env = await createTestEnv();
|
|
57
56
|
const testData = "test-data";
|
|
58
57
|
|
|
59
|
-
const report = (await
|
|
58
|
+
const report = (await WeatherReport.Orm.save(env, {
|
|
60
59
|
title: "Test Report",
|
|
61
60
|
description: "This is a test weather report.",
|
|
62
61
|
weatherEntries: [{
|
|
@@ -67,11 +66,11 @@ describe("Miniflare Integration Tests", () => {
|
|
|
67
66
|
}]
|
|
68
67
|
}))!;
|
|
69
68
|
|
|
70
|
-
await
|
|
69
|
+
await Weather.uploadPhoto(report.weatherEntries[0], env, testData as any);
|
|
71
70
|
|
|
72
71
|
// Act
|
|
73
|
-
const weatherEntries = (await
|
|
74
|
-
const photo =
|
|
72
|
+
const weatherEntries = (await Weather.Default.list(env, 0, 100))!;
|
|
73
|
+
const photo = Weather.downloadPhoto(weatherEntries[0]);
|
|
75
74
|
|
|
76
75
|
// Assert
|
|
77
76
|
expect(photo.ok).toBe(true);
|