@rebasepro/server-postgresql 0.2.5 → 0.4.0
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/dist/common/src/data/query_builder.d.ts +6 -2
- package/dist/index.es.js +93 -213
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +92 -212
- package/dist/index.umd.js.map +1 -1
- package/dist/server-postgresql/src/auth/ensure-tables.d.ts +7 -4
- package/dist/server-postgresql/src/services/EntityFetchService.d.ts +2 -1
- package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +5 -1
- package/dist/types/src/controllers/data.d.ts +17 -3
- package/dist/types/src/controllers/email.d.ts +2 -0
- package/dist/types/src/types/collections.d.ts +9 -5
- package/dist/types/src/types/entity_views.d.ts +19 -28
- package/dist/types/src/types/properties.d.ts +2 -2
- package/package.json +6 -6
- package/src/PostgresBootstrapper.ts +22 -9
- package/src/auth/ensure-tables.ts +30 -28
- package/src/schema/generate-drizzle-schema.ts +2 -6
- package/src/services/EntityFetchService.ts +13 -1
- package/src/utils/drizzle-conditions.ts +40 -5
- package/src/websocket.ts +1 -3
- package/test/relation-pipeline-gaps.test.ts +315 -0
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator } from "@rebasepro/types";
|
|
1
|
+
import { FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator, LogicalCondition, WhereValue, FilterCondition } from "@rebasepro/types";
|
|
2
|
+
export declare function or(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition;
|
|
3
|
+
export declare function and(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition;
|
|
4
|
+
export declare function cond(column: string, operator: FilterOperator, value: unknown): FilterCondition;
|
|
2
5
|
export declare class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements QueryBuilderInterface<M> {
|
|
3
6
|
private collection;
|
|
4
7
|
private params;
|
|
@@ -8,7 +11,8 @@ export declare class QueryBuilder<M extends Record<string, unknown> = Record<str
|
|
|
8
11
|
* @example
|
|
9
12
|
* client.collection('users').where('age', '>=', 18).find()
|
|
10
13
|
*/
|
|
11
|
-
where
|
|
14
|
+
where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): this;
|
|
15
|
+
where(logicalCondition: LogicalCondition): this;
|
|
12
16
|
/**
|
|
13
17
|
* Order the results by a specific column.
|
|
14
18
|
* @example
|
package/dist/index.es.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Pool, Client } from "pg";
|
|
2
2
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
3
|
-
import {
|
|
3
|
+
import { or, and, sql, inArray, eq, ilike, asc, desc, gt, lt, getTableName as getTableName$1, count, relations, isTable } from "drizzle-orm";
|
|
4
4
|
import { PgVarchar, PgText, PgChar, pgSchema, pgTable, timestamp, jsonb, text, boolean, varchar, uuid, unique, getTableConfig } from "drizzle-orm/pg-core";
|
|
5
5
|
import { createHash, randomUUID } from "crypto";
|
|
6
6
|
import * as fs from "fs";
|
|
@@ -2711,166 +2711,6 @@ class CollectionRegistry {
|
|
|
2711
2711
|
};
|
|
2712
2712
|
}
|
|
2713
2713
|
}
|
|
2714
|
-
const defaultUsersCollection = {
|
|
2715
|
-
name: "Users",
|
|
2716
|
-
singularName: "User",
|
|
2717
|
-
slug: "users",
|
|
2718
|
-
table: "users",
|
|
2719
|
-
schema: "rebase",
|
|
2720
|
-
icon: "Users",
|
|
2721
|
-
group: "Settings",
|
|
2722
|
-
openEntityMode: "dialog",
|
|
2723
|
-
disableDefaultActions: ["copy"],
|
|
2724
|
-
sort: ["createdAt", "desc"],
|
|
2725
|
-
properties: {
|
|
2726
|
-
id: {
|
|
2727
|
-
name: "ID",
|
|
2728
|
-
type: "string",
|
|
2729
|
-
isId: "uuid",
|
|
2730
|
-
ui: {
|
|
2731
|
-
readOnly: true
|
|
2732
|
-
}
|
|
2733
|
-
},
|
|
2734
|
-
email: {
|
|
2735
|
-
name: "Email",
|
|
2736
|
-
type: "string",
|
|
2737
|
-
validation: {
|
|
2738
|
-
required: true,
|
|
2739
|
-
unique: true
|
|
2740
|
-
}
|
|
2741
|
-
},
|
|
2742
|
-
displayName: {
|
|
2743
|
-
name: "Name",
|
|
2744
|
-
type: "string",
|
|
2745
|
-
columnName: "display_name",
|
|
2746
|
-
validation: {
|
|
2747
|
-
required: true
|
|
2748
|
-
}
|
|
2749
|
-
},
|
|
2750
|
-
photoURL: {
|
|
2751
|
-
name: "Photo URL",
|
|
2752
|
-
type: "string",
|
|
2753
|
-
columnName: "photo_url",
|
|
2754
|
-
url: "image"
|
|
2755
|
-
},
|
|
2756
|
-
roles: {
|
|
2757
|
-
name: "Roles",
|
|
2758
|
-
type: "array",
|
|
2759
|
-
columnType: "text[]",
|
|
2760
|
-
of: {
|
|
2761
|
-
name: "Role",
|
|
2762
|
-
type: "string",
|
|
2763
|
-
enum: {
|
|
2764
|
-
admin: "Admin",
|
|
2765
|
-
editor: "Editor",
|
|
2766
|
-
viewer: "Viewer"
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
},
|
|
2770
|
-
passwordHash: {
|
|
2771
|
-
name: "Password Hash",
|
|
2772
|
-
type: "string",
|
|
2773
|
-
columnName: "password_hash",
|
|
2774
|
-
ui: {
|
|
2775
|
-
hideFromCollection: true,
|
|
2776
|
-
disabled: {
|
|
2777
|
-
hidden: true
|
|
2778
|
-
}
|
|
2779
|
-
}
|
|
2780
|
-
},
|
|
2781
|
-
emailVerified: {
|
|
2782
|
-
name: "Email Verified",
|
|
2783
|
-
type: "boolean",
|
|
2784
|
-
columnName: "email_verified",
|
|
2785
|
-
defaultValue: false,
|
|
2786
|
-
ui: {
|
|
2787
|
-
hideFromCollection: true,
|
|
2788
|
-
disabled: {
|
|
2789
|
-
hidden: true
|
|
2790
|
-
}
|
|
2791
|
-
}
|
|
2792
|
-
},
|
|
2793
|
-
emailVerificationToken: {
|
|
2794
|
-
name: "Email Verification Token",
|
|
2795
|
-
type: "string",
|
|
2796
|
-
columnName: "email_verification_token",
|
|
2797
|
-
ui: {
|
|
2798
|
-
hideFromCollection: true,
|
|
2799
|
-
disabled: {
|
|
2800
|
-
hidden: true
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
},
|
|
2804
|
-
emailVerificationSentAt: {
|
|
2805
|
-
name: "Email Verification Sent At",
|
|
2806
|
-
type: "date",
|
|
2807
|
-
columnName: "email_verification_sent_at",
|
|
2808
|
-
ui: {
|
|
2809
|
-
hideFromCollection: true,
|
|
2810
|
-
disabled: {
|
|
2811
|
-
hidden: true
|
|
2812
|
-
}
|
|
2813
|
-
}
|
|
2814
|
-
},
|
|
2815
|
-
metadata: {
|
|
2816
|
-
name: "Metadata",
|
|
2817
|
-
type: "map",
|
|
2818
|
-
defaultValue: {},
|
|
2819
|
-
ui: {
|
|
2820
|
-
hideFromCollection: true,
|
|
2821
|
-
disabled: {
|
|
2822
|
-
hidden: true
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
2825
|
-
},
|
|
2826
|
-
createdAt: {
|
|
2827
|
-
name: "Created At",
|
|
2828
|
-
type: "date",
|
|
2829
|
-
columnName: "created_at",
|
|
2830
|
-
ui: {
|
|
2831
|
-
readOnly: true
|
|
2832
|
-
}
|
|
2833
|
-
},
|
|
2834
|
-
updatedAt: {
|
|
2835
|
-
name: "Updated At",
|
|
2836
|
-
type: "date",
|
|
2837
|
-
columnName: "updated_at",
|
|
2838
|
-
autoValue: "on_update",
|
|
2839
|
-
ui: {
|
|
2840
|
-
hideFromCollection: true,
|
|
2841
|
-
disabled: {
|
|
2842
|
-
hidden: true
|
|
2843
|
-
}
|
|
2844
|
-
}
|
|
2845
|
-
}
|
|
2846
|
-
},
|
|
2847
|
-
listProperties: ["displayName", "email", "roles", "createdAt"],
|
|
2848
|
-
propertiesOrder: ["id", "email", "displayName", "roles", "createdAt"]
|
|
2849
|
-
};
|
|
2850
|
-
function mapOperator(op) {
|
|
2851
|
-
switch (op) {
|
|
2852
|
-
case "==":
|
|
2853
|
-
return "eq";
|
|
2854
|
-
case "!=":
|
|
2855
|
-
return "neq";
|
|
2856
|
-
case ">":
|
|
2857
|
-
return "gt";
|
|
2858
|
-
case ">=":
|
|
2859
|
-
return "gte";
|
|
2860
|
-
case "<":
|
|
2861
|
-
return "lt";
|
|
2862
|
-
case "<=":
|
|
2863
|
-
return "lte";
|
|
2864
|
-
case "array-contains":
|
|
2865
|
-
return "cs";
|
|
2866
|
-
case "array-contains-any":
|
|
2867
|
-
return "csa";
|
|
2868
|
-
case "not-in":
|
|
2869
|
-
return "nin";
|
|
2870
|
-
default:
|
|
2871
|
-
return op;
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
2714
|
class QueryBuilder {
|
|
2875
2715
|
constructor(collection) {
|
|
2876
2716
|
this.collection = collection;
|
|
@@ -2878,23 +2718,30 @@ class QueryBuilder {
|
|
|
2878
2718
|
params = {
|
|
2879
2719
|
where: {}
|
|
2880
2720
|
};
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
where(column, operator, value) {
|
|
2721
|
+
where(columnOrCondition, operator, value) {
|
|
2722
|
+
if (typeof columnOrCondition === "object" && columnOrCondition !== null && "type" in columnOrCondition) {
|
|
2723
|
+
this.params.logical = columnOrCondition;
|
|
2724
|
+
return this;
|
|
2725
|
+
}
|
|
2887
2726
|
if (!this.params.where) {
|
|
2888
2727
|
this.params.where = {};
|
|
2889
2728
|
}
|
|
2890
|
-
const
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2729
|
+
const column = columnOrCondition;
|
|
2730
|
+
const condition = [operator, value];
|
|
2731
|
+
const existing = this.params.where[column];
|
|
2732
|
+
if (existing === void 0) {
|
|
2733
|
+
this.params.where[column] = condition;
|
|
2734
|
+
} else if (Array.isArray(existing) && existing.length > 0 && Array.isArray(existing[0])) {
|
|
2735
|
+
this.params.where[column].push(condition);
|
|
2736
|
+
} else {
|
|
2737
|
+
let firstCondition;
|
|
2738
|
+
if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === "string") {
|
|
2739
|
+
firstCondition = existing;
|
|
2740
|
+
} else {
|
|
2741
|
+
firstCondition = ["==", existing];
|
|
2742
|
+
}
|
|
2743
|
+
this.params.where[column] = [firstCondition, condition];
|
|
2896
2744
|
}
|
|
2897
|
-
this.params.where[column] = mappedOp === "eq" ? String(formattedValue) : `${mappedOp}.${formattedValue}`;
|
|
2898
2745
|
return this;
|
|
2899
2746
|
}
|
|
2900
2747
|
/**
|
|
@@ -2996,10 +2843,13 @@ function convertWhereToFilter(where) {
|
|
|
2996
2843
|
filter[field] = ["==", rawValue];
|
|
2997
2844
|
continue;
|
|
2998
2845
|
}
|
|
2999
|
-
if (Array.isArray(rawValue)
|
|
3000
|
-
const [
|
|
3001
|
-
const
|
|
3002
|
-
|
|
2846
|
+
if (Array.isArray(rawValue)) {
|
|
2847
|
+
const conditions = Array.isArray(rawValue[0]) ? rawValue : [rawValue];
|
|
2848
|
+
const mappedConditions = conditions.map(([rawOp, val]) => {
|
|
2849
|
+
const mappedOp = operatorMap[rawOp] ?? "==";
|
|
2850
|
+
return [mappedOp, val];
|
|
2851
|
+
});
|
|
2852
|
+
filter[field] = Array.isArray(rawValue[0]) ? mappedConditions : mappedConditions[0];
|
|
3003
2853
|
continue;
|
|
3004
2854
|
}
|
|
3005
2855
|
if (typeof rawValue === "string") {
|
|
@@ -3137,8 +2987,12 @@ function createDriverAccessor(driver, slug) {
|
|
|
3137
2987
|
});
|
|
3138
2988
|
} : void 0,
|
|
3139
2989
|
// Fluent Query Builder
|
|
3140
|
-
where(
|
|
3141
|
-
|
|
2990
|
+
where(columnOrCondition, operator, value) {
|
|
2991
|
+
const builder = new QueryBuilder(accessor);
|
|
2992
|
+
if (typeof columnOrCondition === "object") {
|
|
2993
|
+
return builder.where(columnOrCondition);
|
|
2994
|
+
}
|
|
2995
|
+
return builder.where(columnOrCondition, operator, value);
|
|
3142
2996
|
},
|
|
3143
2997
|
orderBy(column, ascending) {
|
|
3144
2998
|
return new QueryBuilder(accessor).orderBy(column, ascending);
|
|
@@ -3189,7 +3043,6 @@ class DrizzleConditionBuilder {
|
|
|
3189
3043
|
const conditions = [];
|
|
3190
3044
|
for (const [field, filterParam] of Object.entries(filter)) {
|
|
3191
3045
|
if (!filterParam) continue;
|
|
3192
|
-
const [op, value] = filterParam;
|
|
3193
3046
|
let fieldColumn = table[field];
|
|
3194
3047
|
if (!fieldColumn) {
|
|
3195
3048
|
const relationKey = `${field}_id`;
|
|
@@ -3201,13 +3054,39 @@ class DrizzleConditionBuilder {
|
|
|
3201
3054
|
console.warn(`Filtering by field '${field}', but it does not exist in table for collection '${collectionPath}'`);
|
|
3202
3055
|
continue;
|
|
3203
3056
|
}
|
|
3204
|
-
const
|
|
3205
|
-
|
|
3206
|
-
|
|
3057
|
+
const paramsList = Array.isArray(filterParam) && filterParam.length > 0 && Array.isArray(filterParam[0]) ? filterParam : [filterParam];
|
|
3058
|
+
for (const [op, value] of paramsList) {
|
|
3059
|
+
const condition = this.buildSingleFilterCondition(fieldColumn, op, value);
|
|
3060
|
+
if (condition) {
|
|
3061
|
+
conditions.push(condition);
|
|
3062
|
+
}
|
|
3207
3063
|
}
|
|
3208
3064
|
}
|
|
3209
3065
|
return conditions;
|
|
3210
3066
|
}
|
|
3067
|
+
/**
|
|
3068
|
+
* Build logical conditions recursively from LogicalCondition or FilterCondition
|
|
3069
|
+
*/
|
|
3070
|
+
static buildLogicalConditions(cond, table, collectionPath) {
|
|
3071
|
+
if ("type" in cond) {
|
|
3072
|
+
const subSQLs = cond.conditions.map((c) => this.buildLogicalConditions(c, table, collectionPath)).filter((sql2) => sql2 !== null);
|
|
3073
|
+
if (subSQLs.length === 0) return null;
|
|
3074
|
+
return (cond.type === "or" ? or(...subSQLs) : and(...subSQLs)) ?? null;
|
|
3075
|
+
} else {
|
|
3076
|
+
let fieldColumn = table[cond.column];
|
|
3077
|
+
if (!fieldColumn) {
|
|
3078
|
+
const relationKey = `${cond.column}_id`;
|
|
3079
|
+
if (relationKey in table) {
|
|
3080
|
+
fieldColumn = table[relationKey];
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
if (!fieldColumn) {
|
|
3084
|
+
console.warn(`Filtering by field '${cond.column}', but it does not exist in table for collection '${collectionPath}'`);
|
|
3085
|
+
return null;
|
|
3086
|
+
}
|
|
3087
|
+
return this.buildSingleFilterCondition(fieldColumn, cond.operator, cond.value);
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3211
3090
|
/**
|
|
3212
3091
|
* Build a single filter condition for a specific operator and value
|
|
3213
3092
|
*/
|
|
@@ -5604,6 +5483,10 @@ class EntityFetchService {
|
|
|
5604
5483
|
const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);
|
|
5605
5484
|
if (filterConditions.length > 0) allConditions.push(...filterConditions);
|
|
5606
5485
|
}
|
|
5486
|
+
if (options.logical) {
|
|
5487
|
+
const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);
|
|
5488
|
+
if (logicalCondition) allConditions.push(logicalCondition);
|
|
5489
|
+
}
|
|
5607
5490
|
if (options.startAfter) {
|
|
5608
5491
|
const cursorConditions = this.buildCursorConditions(table, idField, idInfo, options, collectionPath);
|
|
5609
5492
|
if (cursorConditions.length > 0) allConditions.push(...cursorConditions);
|
|
@@ -5775,6 +5658,10 @@ class EntityFetchService {
|
|
|
5775
5658
|
const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);
|
|
5776
5659
|
if (filterConditions.length > 0) allConditions.push(...filterConditions);
|
|
5777
5660
|
}
|
|
5661
|
+
if (options.logical) {
|
|
5662
|
+
const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);
|
|
5663
|
+
if (logicalCondition) allConditions.push(logicalCondition);
|
|
5664
|
+
}
|
|
5778
5665
|
if (vectorMeta?.filter) {
|
|
5779
5666
|
allConditions.push(vectorMeta.filter);
|
|
5780
5667
|
}
|
|
@@ -8733,7 +8620,6 @@ const runGeneration = async (collectionsFilePath, outputPath) => {
|
|
|
8733
8620
|
if (!collections || !Array.isArray(collections)) {
|
|
8734
8621
|
collections = [];
|
|
8735
8622
|
}
|
|
8736
|
-
collections = Array.from(new Map([defaultUsersCollection, ...collections].map((c) => [c.slug, c])).values());
|
|
8737
8623
|
collections.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
8738
8624
|
const schemaContent = await generateSchema(collections);
|
|
8739
8625
|
if (outputPath) {
|
|
@@ -10341,31 +10227,23 @@ class PostgresCollectionRegistry extends CollectionRegistry {
|
|
|
10341
10227
|
return collection.relations.map((r) => r.relationName || r.localKey || "").filter(Boolean);
|
|
10342
10228
|
}
|
|
10343
10229
|
}
|
|
10344
|
-
async function ensureAuthTablesExist(db,
|
|
10230
|
+
async function ensureAuthTablesExist(db, collection) {
|
|
10345
10231
|
logger.info("🔍 Checking auth tables...");
|
|
10346
10232
|
try {
|
|
10347
|
-
let usersTableName = '"users"';
|
|
10233
|
+
let usersTableName = '"rebase"."users"';
|
|
10348
10234
|
let userIdType = "TEXT";
|
|
10349
|
-
let usersSchema2 = "
|
|
10350
|
-
if (
|
|
10351
|
-
const
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
|
|
10361
|
-
const columnType = meta.columnType;
|
|
10362
|
-
if (columnType === "PgUUID") {
|
|
10363
|
-
userIdType = "UUID";
|
|
10364
|
-
} else if (columnType === "PgSerial" || columnType === "PgInteger") {
|
|
10365
|
-
userIdType = "INTEGER";
|
|
10366
|
-
} else if (columnType === "PgBigInt" || columnType === "PgBigSerial") {
|
|
10367
|
-
userIdType = "BIGINT";
|
|
10368
|
-
}
|
|
10235
|
+
let usersSchema2 = "rebase";
|
|
10236
|
+
if (collection) {
|
|
10237
|
+
const rawTable = "table" in collection && typeof collection.table === "string" ? collection.table : collection.slug;
|
|
10238
|
+
usersSchema2 = "schema" in collection && typeof collection.schema === "string" ? collection.schema : "public";
|
|
10239
|
+
usersTableName = usersSchema2 === "public" ? `"${rawTable}"` : `"${usersSchema2}"."${rawTable}"`;
|
|
10240
|
+
const idProp = collection.properties?.id;
|
|
10241
|
+
if (idProp) {
|
|
10242
|
+
const isId = "isId" in idProp ? idProp.isId : void 0;
|
|
10243
|
+
if (isId === "uuid") {
|
|
10244
|
+
userIdType = "UUID";
|
|
10245
|
+
} else if (isId === "autoincrement") {
|
|
10246
|
+
userIdType = "INTEGER";
|
|
10369
10247
|
}
|
|
10370
10248
|
}
|
|
10371
10249
|
}
|
|
@@ -11758,19 +11636,21 @@ function createPostgresBootstrapper(pgConfig) {
|
|
|
11758
11636
|
const internals = driverResult.internals;
|
|
11759
11637
|
const db = internals.db;
|
|
11760
11638
|
const registry = internals.registry;
|
|
11761
|
-
|
|
11639
|
+
const authCollection = authConfig.collection;
|
|
11640
|
+
await ensureAuthTablesExist(db, authCollection);
|
|
11762
11641
|
let emailService;
|
|
11763
11642
|
if (authConfig.email) {
|
|
11764
11643
|
emailService = createEmailService(authConfig.email);
|
|
11765
11644
|
}
|
|
11766
|
-
const
|
|
11645
|
+
const tableName = authCollection ? "table" in authCollection && typeof authCollection.table === "string" ? authCollection.table : authCollection.slug : void 0;
|
|
11646
|
+
const usersTable = tableName ? registry.getTable(tableName) : void 0;
|
|
11767
11647
|
let usersSchemaName = "rebase";
|
|
11768
|
-
if (
|
|
11769
|
-
usersSchemaName =
|
|
11648
|
+
if (authCollection && "schema" in authCollection && typeof authCollection.schema === "string") {
|
|
11649
|
+
usersSchemaName = authCollection.schema;
|
|
11770
11650
|
}
|
|
11771
11651
|
const authTables = createAuthSchema(usersSchemaName);
|
|
11772
|
-
if (
|
|
11773
|
-
authTables.users =
|
|
11652
|
+
if (usersTable) {
|
|
11653
|
+
authTables.users = usersTable;
|
|
11774
11654
|
}
|
|
11775
11655
|
const userService = new UserService(db, authTables);
|
|
11776
11656
|
const authRepository = new PostgresAuthRepository(db, authTables);
|