|
2 | 2 | import type * as schema from '../out/schema';
|
3 | 3 | import type { Document } from 'bson';
|
4 | 4 |
|
5 |
| -interface GenericCollectionSchema { |
6 |
| - schema: Document; |
7 |
| -} |
| 5 | +type StringKey<T> = keyof T & string; |
8 | 6 | interface GenericDatabaseSchema {
|
9 | 7 | [key: string]: GenericCollectionSchema;
|
10 | 8 | }
|
11 |
| -interface GenericServerSideSchema { |
12 |
| - [key: string]: GenericDatabaseSchema; |
13 |
| -} |
14 |
| -type StringKey<T> = keyof T & string; |
15 | 9 |
|
16 |
| -class Mongo<M extends GenericServerSideSchema = GenericServerSideSchema> {} |
17 |
| - |
18 |
| -type CollectionWithSchema< |
19 |
| - M extends GenericServerSideSchema = GenericServerSideSchema, |
20 |
| - D extends GenericDatabaseSchema = M[keyof M], |
21 |
| - C extends GenericCollectionSchema = D[keyof D], |
22 |
| - N extends StringKey<D> = StringKey<D>, |
23 |
| -> = Collection<M, D, C, N> & { |
24 |
| - [k in StringKey<D> as k extends `${N}.${infer S}` ? S : never]: Collection< |
25 |
| - M, |
26 |
| - D, |
27 |
| - D[k], |
28 |
| - k |
29 |
| - >; |
30 |
| -}; |
31 |
| - |
32 |
| -class Collection< |
33 |
| - M extends GenericServerSideSchema = GenericServerSideSchema, |
34 |
| - D extends GenericDatabaseSchema = M[keyof M], |
35 |
| - C extends GenericCollectionSchema = D[keyof D], |
36 |
| - N extends StringKey<D> = StringKey<D>, |
37 |
| -> { |
38 |
| - _mongo: Mongo<M>; |
39 |
| - _database: DatabaseWithSchema<M, D>; |
40 |
| - _name: N; |
41 |
| - constructor( |
42 |
| - mongo: Mongo<M>, |
43 |
| - database: DatabaseWithSchema<M, D> | Database<M, D>, |
44 |
| - name: N, |
45 |
| - ) { |
46 |
| - this._mongo = mongo; |
47 |
| - this._database = database as DatabaseWithSchema<M, D>; |
48 |
| - this._name = name; |
49 |
| - } |
50 |
| - getName(): N { |
51 |
| - return this._name; |
52 |
| - } |
53 |
| - async find( |
54 |
| - query?: schema.Query<C['schema']>, |
55 |
| - projection?: Document, |
56 |
| - options: Document = {}, |
57 |
| - ): Promise<schema.Query<C['schema']> | undefined> { |
58 |
| - return Promise.resolve(query); |
59 |
| - } |
60 |
| -} |
61 |
| - |
62 |
| -type DatabaseWithSchema< |
63 |
| - M extends GenericServerSideSchema = GenericServerSideSchema, |
64 |
| - D extends GenericDatabaseSchema = GenericDatabaseSchema, |
65 |
| -> = Database<M, D> & { |
66 |
| - [k in StringKey<D>]: Collection<M, D, D[k], k>; |
67 |
| -}; |
68 |
| - |
69 |
| -function isValidCollectionName(name: string): boolean { |
70 |
| - return !!name && !/[$\0]/.test(name); |
| 10 | +interface GenericCollectionSchema { |
| 11 | + schema: Document; |
71 | 12 | }
|
72 | 13 |
|
73 |
| -export class Database< |
74 |
| - M extends GenericServerSideSchema = GenericServerSideSchema, |
75 |
| - D extends GenericDatabaseSchema = GenericDatabaseSchema, |
76 |
| -> { |
77 |
| - _mongo: Mongo<M>; |
78 |
| - _name: StringKey<M>; |
79 |
| - _collections: Record<StringKey<D>, CollectionWithSchema<M, D>>; |
| 14 | +class Database<D extends GenericDatabaseSchema = GenericDatabaseSchema> { |
| 15 | + _collections: Record<StringKey<D>, CollectionWithSchema<D>>; |
80 | 16 |
|
81 |
| - constructor(mongo: Mongo<M>, name: StringKey<M>) { |
82 |
| - this._mongo = mongo; |
83 |
| - this._name = name; |
84 |
| - const collections: Record< |
85 |
| - string, |
86 |
| - CollectionWithSchema<M, D> |
87 |
| - > = Object.create(null); |
| 17 | + constructor() { |
| 18 | + const collections: Record<string, CollectionWithSchema<D>> = Object.create( |
| 19 | + null, |
| 20 | + ); |
88 | 21 | this._collections = collections;
|
89 |
| - |
90 | 22 | const proxy = new Proxy(this, {
|
91 | 23 | get: (target, prop): any => {
|
92 | 24 | if (prop in target) {
|
93 | 25 | return (target as any)[prop];
|
94 | 26 | }
|
95 | 27 |
|
96 |
| - if ( |
97 |
| - typeof prop !== 'string' || |
98 |
| - prop.startsWith('_') || |
99 |
| - !isValidCollectionName(prop) |
100 |
| - ) { |
| 28 | + if (typeof prop !== 'string' || prop.startsWith('_')) { |
101 | 29 | return;
|
102 | 30 | }
|
103 | 31 |
|
104 | 32 | if (!collections[prop]) {
|
105 |
| - collections[prop] = new Collection<M, D>( |
106 |
| - mongo, |
107 |
| - proxy, |
108 |
| - prop, |
109 |
| - ) as CollectionWithSchema<M, D>; |
| 33 | + collections[prop] = new Collection< |
| 34 | + D, |
| 35 | + D[typeof prop] |
| 36 | + >() as CollectionWithSchema<D, D[typeof prop]>; |
110 | 37 | }
|
111 | 38 |
|
112 | 39 | return collections[prop];
|
113 | 40 | },
|
114 | 41 | });
|
115 | 42 | return proxy;
|
116 | 43 | }
|
| 44 | +} |
117 | 45 |
|
118 |
| - getCollection<K extends StringKey<D>>( |
119 |
| - coll: K, |
120 |
| - ): CollectionWithSchema<M, D, D[K], K> { |
121 |
| - const collection = new Collection<M, D, D['myCollection']>( |
122 |
| - this._mongo, |
123 |
| - this, |
124 |
| - 'myCollection', |
125 |
| - ); |
126 |
| - |
127 |
| - return collection as CollectionWithSchema<M, D, D[K], K>; |
| 46 | +type DatabaseWithSchema< |
| 47 | + D extends GenericDatabaseSchema = GenericDatabaseSchema, |
| 48 | +> = Database<D>; |
| 49 | +class Collection< |
| 50 | + D extends GenericDatabaseSchema = GenericDatabaseSchema, |
| 51 | + C extends GenericCollectionSchema = GenericCollectionSchema, |
| 52 | +> { |
| 53 | + find(query: schema.Query<C['schema']>): Promise<schema.Query<C['schema']>> { |
| 54 | + return Promise.resolve(query); |
128 | 55 | }
|
129 | 56 | }
|
| 57 | +type CollectionWithSchema< |
| 58 | + D extends GenericDatabaseSchema = GenericDatabaseSchema, |
| 59 | + C extends GenericCollectionSchema = D[keyof D], |
| 60 | +> = Collection<D, C>; |
130 | 61 |
|
131 | 62 | async function run() {
|
132 |
| - const serverSchema = { |
133 |
| - myDatabase: { |
134 |
| - myCollection: { |
135 |
| - schema: { |
136 |
| - _id: 'ObjectId', |
137 |
| - name: 'string', |
138 |
| - age: 'number', |
139 |
| - }, |
140 |
| - }, |
141 |
| - }, |
142 |
| - }; |
143 |
| - const mongo = new Mongo<typeof serverSchema>(); |
144 |
| - const db = new Database< |
145 |
| - typeof serverSchema, |
146 |
| - (typeof serverSchema)['myDatabase'] |
147 |
| - >(mongo, 'myDatabase') as DatabaseWithSchema< |
148 |
| - typeof serverSchema, |
149 |
| - (typeof serverSchema)['myDatabase'] |
150 |
| - >; |
151 |
| - const query = await db.myCollection.find({ name: 'foo' }); |
152 |
| - console.log(query); |
| 63 | + const database = new Database<{ |
| 64 | + myCollection: { schema: { name: string } }; |
| 65 | + }>(); |
| 66 | + console.log(await database.myCollection.find({ name: 'foo' })); |
153 | 67 | }
|
154 | 68 |
|
155 | 69 | run().catch(console.error);
|
0 commit comments