Skip to content

Commit f5d5b64

Browse files
authored
Merge pull request #3049 from SeedCompany/edgedb/extended-scalars
2 parents ce3fd53 + f346519 commit f5d5b64

File tree

16 files changed

+169
-112
lines changed

16 files changed

+169
-112
lines changed

.yarn/patches/edgedb-npm-1.4.0-902d833279.patch

Lines changed: 0 additions & 12 deletions
This file was deleted.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"cypher-query-builder": "patch:[email protected]#.yarn/patches/cypher-query-builder.patch",
6262
"dotenv": "^16.3.1",
6363
"dotenv-expand": "^10.0.0",
64-
"edgedb": "patch:edgedb@npm%3A1.4.0#~/.yarn/patches/edgedb-npm-1.4.0-902d833279.patch",
64+
"edgedb": "^1.5.0-canary.20240116T174024",
6565
"execa": "^8.0.1",
6666
"express": "^4.18.2",
6767
"extensionless": "^1.7.0",
@@ -104,7 +104,7 @@
104104
"yaml": "^2.3.3"
105105
},
106106
"devDependencies": {
107-
"@edgedb/generate": "^0.4.1",
107+
"@edgedb/generate": "^0.5.0-canary.20240116T174045",
108108
"@nestjs/cli": "^10.2.1",
109109
"@nestjs/schematics": "^10.0.3",
110110
"@nestjs/testing": "^10.2.7",

src/common/temporal/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { DurationIn } from '@seedcompany/common/temporal/luxon';
1+
export type { DurationIn } from '@seedcompany/common/temporal/luxon';
22

33
export * from './date-time';
44
export * from './interval';

src/core/edgedb/codecs/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { LuxonCalendarDateCodec, LuxonDateTimeCodec } from './temporal.codec';
2+
import { ScalarCodecClass } from './type.util';
3+
import { OurUUIDCodec } from './uuid.codec';
4+
5+
export { registerCustomScalarCodecs } from './register-codecs';
6+
export type { ScalarInfo } from './type.util';
7+
8+
export const codecs: readonly ScalarCodecClass[] = [
9+
OurUUIDCodec,
10+
LuxonDateTimeCodec,
11+
LuxonCalendarDateCodec,
12+
];
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { delay, mapEntries } from '@seedcompany/common';
2+
import { $, Client } from 'edgedb';
3+
import { KNOWN_TYPENAMES } from 'edgedb/dist/codecs/consts.js';
4+
import LRU from 'edgedb/dist/primitives/lru.js';
5+
import { retry } from '~/common/retry';
6+
import { ScalarCodecClass } from './type.util';
7+
8+
export const registerCustomScalarCodecs = async (
9+
client: Client,
10+
codecs: readonly ScalarCodecClass[],
11+
) => {
12+
async function registerWithServerSchema() {
13+
const introspected = await $.introspect.scalars(client);
14+
const scalarIdsByName = mapEntries(introspected, ([_, scalar]) => [
15+
scalar.name,
16+
scalar.id.replaceAll('-', ''),
17+
]).asMap;
18+
register(client, codecs, scalarIdsByName);
19+
}
20+
21+
const connectedFast = await Promise.race([
22+
client.ensureConnected(),
23+
delay({ seconds: 2 }), // don't wait full 30 seconds with retries
24+
]);
25+
// If connection was established fast, register with schema info, and wait for completion
26+
if (connectedFast) {
27+
await registerWithServerSchema();
28+
} else {
29+
// Otherwise, register statically known codecs immediately
30+
register(client, codecs);
31+
// And then keep trying to connect in the background, and register on successful connection.
32+
void retry(
33+
async () => {
34+
if (client.isClosed()) {
35+
return;
36+
}
37+
await client.ensureConnected();
38+
await registerWithServerSchema();
39+
},
40+
{
41+
forever: true,
42+
unref: true,
43+
maxTimeout: { seconds: 10 },
44+
},
45+
);
46+
}
47+
};
48+
49+
const register = (
50+
client: Client,
51+
scalarCodecs: readonly ScalarCodecClass[],
52+
scalarIdsByName?: ReadonlyMap<string, string>,
53+
) => {
54+
const registry = (client as any).pool._codecsRegistry;
55+
const codecs: LRU<string, InstanceType<ScalarCodecClass>> = registry.codecs;
56+
57+
for (const scalarCodec of scalarCodecs) {
58+
const typeName = `${scalarCodec.info.module}::${scalarCodec.info.type}`;
59+
const uuid =
60+
KNOWN_TYPENAMES.get(typeName) ?? scalarIdsByName?.get(typeName);
61+
if (!uuid) {
62+
continue;
63+
}
64+
codecs.set(uuid, new scalarCodec(uuid));
65+
}
66+
};

src/core/edgedb/temporal.codecs.ts renamed to src/core/edgedb/codecs/temporal.codec.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@ import { InvalidArgumentError, LocalDate } from 'edgedb';
22
import { DateTimeCodec, LocalDateCodec } from 'edgedb/dist/codecs/datetime.js';
33
import { ReadBuffer, WriteBuffer } from 'edgedb/dist/primitives/buffer.js';
44
import { DateTime } from 'luxon';
5-
import { CalendarDate } from '~/common';
5+
import { CalendarDate } from '~/common/temporal';
6+
import { ScalarInfo } from './type.util';
67

78
export class LuxonDateTimeCodec extends DateTimeCodec {
8-
static edgedbTypeName = 'std::datetime';
9+
static info: ScalarInfo = {
10+
module: 'std',
11+
type: 'datetime',
12+
ts: 'DateTime',
13+
path: 'luxon',
14+
};
15+
tsType = DateTime.name;
16+
importedType = true;
917

1018
encode(buf: WriteBuffer, object: unknown) {
1119
if (object instanceof Date) {
@@ -20,14 +28,21 @@ export class LuxonDateTimeCodec extends DateTimeCodec {
2028
super.encode(buf, object.toJSDate());
2129
}
2230

23-
decode(buf: ReadBuffer): DateTime {
31+
decode(buf: ReadBuffer) {
2432
const date: Date = super.decode(buf);
25-
return DateTime.fromJSDate(date);
33+
return DateTime.fromJSDate(date) as any;
2634
}
2735
}
2836

2937
export class LuxonCalendarDateCodec extends LocalDateCodec {
30-
static edgedbTypeName = 'cal::local_date';
38+
static info: ScalarInfo = {
39+
module: 'cal',
40+
type: 'local_date',
41+
ts: 'CalendarDate',
42+
path: '~/common',
43+
};
44+
tsType = CalendarDate.name;
45+
importedType = true;
3146

3247
encode(buf: WriteBuffer, object: unknown) {
3348
if (object instanceof LocalDate) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { ICodec, ScalarCodec } from 'edgedb/dist/codecs/ifaces';
2+
import { Class } from 'type-fest';
3+
4+
export type ScalarCodecClass = Class<ScalarCodec & ICodec> & {
5+
info: ScalarInfo;
6+
};
7+
8+
export interface ScalarInfo {
9+
module: string;
10+
type: string;
11+
ts: string;
12+
path: string;
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { UUIDCodec } from 'edgedb/dist/codecs/uuid.js';
2+
import { ScalarInfo } from './type.util';
3+
4+
export class OurUUIDCodec extends UUIDCodec {
5+
static info: ScalarInfo = {
6+
module: 'std',
7+
type: 'uuid',
8+
ts: 'ID',
9+
path: '~/common',
10+
};
11+
tsType = 'ID';
12+
importedType = true;
13+
}

src/core/edgedb/edgedb.module.ts

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import { Module, OnModuleDestroy } from '@nestjs/common';
22
import { APP_INTERCEPTOR } from '@nestjs/core';
33
import { createClient, Duration } from 'edgedb';
4-
import { KNOWN_TYPENAMES } from 'edgedb/dist/codecs/consts.js';
5-
import { ScalarCodec } from 'edgedb/dist/codecs/ifaces.js';
6-
import { Class } from 'type-fest';
4+
import { codecs, registerCustomScalarCodecs } from './codecs';
75
import { EdgeDBTransactionalMutationsInterceptor } from './edgedb-transactional-mutations.interceptor';
86
import { EdgeDB } from './edgedb.service';
97
import { Options } from './options';
108
import { OptionsContext } from './options.context';
119
import { Client } from './reexports';
12-
import { LuxonCalendarDateCodec, LuxonDateTimeCodec } from './temporal.codecs';
1310
import { TransactionContext } from './transaction.context';
1411

1512
@Module({
@@ -30,15 +27,15 @@ import { TransactionContext } from './transaction.context';
3027
{
3128
provide: Client,
3229
inject: [OptionsContext],
33-
useFactory: (options: OptionsContext) => {
34-
const client = createClient();
30+
useFactory: async (options: OptionsContext) => {
31+
const client = createClient({
32+
// Only for connection retry warnings. Skip.
33+
logging: false,
34+
});
3535

3636
Object.assign(client, { options: options.current });
3737

38-
registerCustomScalarCodecs(client, [
39-
LuxonDateTimeCodec,
40-
LuxonCalendarDateCodec,
41-
]);
38+
await registerCustomScalarCodecs(client, codecs);
4239

4340
return client;
4441
},
@@ -59,15 +56,3 @@ export class EdgeDBModule implements OnModuleDestroy {
5956
await this.client.close();
6057
}
6158
}
62-
63-
const registerCustomScalarCodecs = (
64-
client: Client,
65-
scalars: ReadonlyArray<Class<ScalarCodec> & { edgedbTypeName: string }>,
66-
) => {
67-
const map: Map<string, ScalarCodec> = (client as any).pool._codecsRegistry
68-
.customScalarCodecs;
69-
for (const scalar of scalars) {
70-
const uuid = KNOWN_TYPENAMES.get(scalar.edgedbTypeName)!;
71-
map.set(uuid, new scalar(uuid));
72-
}
73-
};

src/core/edgedb/generator/generate-schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function generateSchema({
1616
},
1717
client,
1818
root: root.getPath(),
19+
schemaDir: 'unused',
1920
});
2021
await schemaFile.refreshFromFileSystem();
2122
addCustomScalarImports(schemaFile, customScalars.values());

0 commit comments

Comments
 (0)