alepha 0.20.2 → 0.20.3
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/README.md +0 -1
- package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/assets/swagger-ui/swagger-ui.css +1 -1
- package/dist/api/audits/index.browser.js +49 -0
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +49 -0
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +16 -75
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.js.map +1 -1
- package/dist/api/notifications/index.d.ts +1 -10
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/organizations/index.d.ts.map +1 -1
- package/dist/api/parameters/index.browser.js +37 -0
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +4 -65
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +37 -0
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/payments/index.d.ts.map +1 -1
- package/dist/api/payments/index.js.map +1 -1
- package/dist/api/users/index.d.ts +207 -5184
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +2 -4
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +2 -1
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/bucket/index.js +5 -1
- package/dist/bucket/index.js.map +1 -1
- package/dist/bucket/index.workerd.js +5 -1
- package/dist/bucket/index.workerd.js.map +1 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/captcha/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +217 -11647
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +706 -42
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.js +7 -1
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +41 -64
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +47 -0
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.js +15 -0
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/command/index.js +1 -1
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +2 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.js.map +1 -1
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/smtp/index.js +2 -10522
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +4 -8085
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +3 -33554
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.js.map +1 -1
- package/dist/logger/index.js +32 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.js +5 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +1 -361
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +14 -406
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +96 -5117
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +23 -419
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js +17 -20
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +2 -613
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js +17 -20
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/intro/index.js +22 -17
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +78 -2
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +22 -1
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +102 -4
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/testing/index.d.ts +1 -411
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +13 -12293
- package/dist/react/testing/index.js.map +1 -1
- package/dist/react/ui/index.js +3 -0
- package/dist/react/ui/index.js.map +1 -1
- package/dist/react/websocket/index.js.map +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +1 -83
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +2 -391
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js +2 -391
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +2 -325
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +3 -1362
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +1 -1054
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +16 -1224
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +1 -4
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +19 -4
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +1 -514
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +4 -4356
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.js +1 -1
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js.map +1 -1
- package/dist/system/index.js.map +1 -1
- package/dist/system/index.workerd.js.map +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/dist/websocket/index.browser.js +21 -0
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.js +21 -0
- package/dist/websocket/index.js.map +1 -1
- package/package.json +18 -15
- package/src/api/files/__tests__/FileController.spec.ts +1 -1
- package/src/api/jobs/__tests__/$job.spec.ts +5 -1
- package/src/api/users/schemas/userQuerySchema.ts +0 -1
- package/src/api/users/services/UserService.ts +1 -5
- package/src/api/verifications/__tests__/CodeVerification.spec.ts +14 -0
- package/src/api/verifications/__tests__/LinkVerification.spec.ts +14 -0
- package/src/api/verifications/services/VerificationService.ts +1 -0
- package/src/cli/core/__tests__/init.spec.ts +208 -0
- package/src/cli/core/commands/init.ts +12 -0
- package/src/cli/core/services/PackageManagerUtils.ts +23 -6
- package/src/cli/core/services/ProjectScaffolder.ts +298 -20
- package/src/cli/core/tasks/BuildDockerTask.ts +9 -10
- package/src/cli/core/tasks/BuildServerTask.ts +8 -0
- package/src/cli/core/templates/apiIndexTs.ts +23 -1
- package/src/cli/core/templates/componentsJsonTs.ts +39 -0
- package/src/cli/core/templates/mainCss.ts +1 -0
- package/src/cli/core/templates/saasAdminLayoutTsx.ts +77 -0
- package/src/cli/core/templates/saasAdminPagesTsx.ts +26 -0
- package/src/cli/core/templates/saasAuthLayoutTsx.ts +20 -0
- package/src/cli/core/templates/saasAuthPagesTsx.ts +62 -0
- package/src/cli/core/templates/saasRealmProviderTs.ts +46 -0
- package/src/cli/core/templates/webAppRouterTs.ts +104 -1
- package/src/cli/core/templates/webIndexTs.ts +23 -1
- package/src/cli/platform/__tests__/SecretsCommand.spec.ts +2 -0
- package/src/command/providers/CliProvider.ts +1 -1
- package/src/core/interfaces/Service.ts +3 -1
- package/src/core/providers/TypeProvider.ts +1 -1
- package/src/logger/services/Logger.ts +1 -1
- package/src/mcp/__tests__/$resource.spec.ts +1 -1
- package/src/mcp/__tests__/$tool.spec.ts +1 -1
- package/src/mcp/__tests__/McpServerProvider.spec.ts +1 -1
- package/src/orm/__tests__/$repository-tests.ts +1 -0
- package/src/orm/__tests__/orm-next-tests.ts +2 -67
- package/src/orm/__tests__/orm-next.spec.ts +0 -21
- package/src/orm/core/index.shared.ts +0 -2
- package/src/orm/core/index.ts +1 -2
- package/src/orm/core/primitives/$repository.ts +3 -6
- package/src/orm/core/providers/drivers/DatabaseProvider.ts +0 -5
- package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +11 -13
- package/src/orm/core/services/ModelBuilder.ts +1 -13
- package/src/orm/core/services/Repository.ts +1 -42
- package/src/orm/core/services/SqliteModelBuilder.ts +2 -33
- package/src/orm/postgres/services/PostgresModelBuilder.ts +10 -45
- package/src/react/intro/components/GettingStartedAuthSlide.tsx +11 -4
- package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +213 -2
- package/src/react/router/providers/ReactBrowserProvider.ts +73 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +1 -1
- package/src/react/router/providers/ReactPreloadProvider.ts +1 -1
- package/src/react/router/providers/ReactServerProvider.ts +1 -0
- package/src/scheduler/providers/CronProvider.ts +1 -1
- package/src/security/primitives/$basicAuth.ts +1 -1
- package/src/server/auth/providers/ServerAuthProvider.ts +5 -1
- package/src/server/core/interfaces/ServerRequest.ts +1 -0
- package/src/server/core/providers/ServerProvider.ts +1 -1
- package/src/server/core/providers/ServerRouterProvider.ts +2 -2
- package/src/server/core/services/HttpClient.ts +1 -1
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
- package/dist/react/testing/chunk-DBEY4PJZ.js +0 -16
- package/src/orm/core/__tests__/parseQueryString.spec.ts +0 -196
- package/src/orm/core/helpers/parseQueryString.ts +0 -502
- package/src/orm/core/primitives/$view.ts +0 -88
|
@@ -9,7 +9,7 @@ import { alias, customType } from "drizzle-orm/pg-core";
|
|
|
9
9
|
import { dirname } from "node:path";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import * as pg from "drizzle-orm/sqlite-core";
|
|
12
|
-
import { check, foreignKey, index, sqliteTable,
|
|
12
|
+
import { check, foreignKey, index, sqliteTable, unique, uniqueIndex } from "drizzle-orm/sqlite-core";
|
|
13
13
|
import { currentUserAtom } from "alepha/security";
|
|
14
14
|
import { isSQLWrapper as isSQLWrapper$1 } from "drizzle-orm/sql/sql";
|
|
15
15
|
export * from "drizzle-orm/pg-core";
|
|
@@ -136,6 +136,13 @@ var DbError = class extends AlephaError {
|
|
|
136
136
|
*/
|
|
137
137
|
const databaseEnvSchema = t.object({
|
|
138
138
|
DATABASE_URL: t.optional(t.text()),
|
|
139
|
+
/**
|
|
140
|
+
* Enable or disable push-based schema synchronization (drizzle-kit push).
|
|
141
|
+
*
|
|
142
|
+
* Defaults to `true` in development and test, `false` in production.
|
|
143
|
+
* Set to `false` in development to skip automatic schema sync
|
|
144
|
+
* (e.g. when managing migrations manually).
|
|
145
|
+
*/
|
|
139
146
|
DATABASE_SYNC: t.optional(t.boolean())
|
|
140
147
|
});
|
|
141
148
|
//#endregion
|
|
@@ -451,9 +458,6 @@ var DatabaseProvider = class {
|
|
|
451
458
|
this.entityPrimitives.push(entity);
|
|
452
459
|
this.builder.buildTable(entity, this);
|
|
453
460
|
}
|
|
454
|
-
registerView(view) {
|
|
455
|
-
this.builder.buildView(view, this);
|
|
456
|
-
}
|
|
457
461
|
registerSequence(sequence) {
|
|
458
462
|
this.sequencePrimitives.push(sequence);
|
|
459
463
|
this.builder.buildSequence(sequence, this);
|
|
@@ -651,7 +655,7 @@ var ModelBuilder = class {
|
|
|
651
655
|
const fkName = fkDef.name || `${entity.name}_${columnNames.join("_")}_fk`;
|
|
652
656
|
const foreignColumns = fkDef.foreignColumns.map((colRef) => {
|
|
653
657
|
const entityCol = colRef();
|
|
654
|
-
if (!entityCol
|
|
658
|
+
if (!entityCol?.entity || !entityCol.name) throw new AlephaError(`Invalid foreign column reference in ${entity.name}`);
|
|
655
659
|
if (tableResolver) {
|
|
656
660
|
const foreignTable = tableResolver(entityCol.entity.name);
|
|
657
661
|
if (!foreignTable) throw new AlephaError(`Foreign table ${entityCol.entity.name} not found for ${entity.name}`);
|
|
@@ -698,13 +702,6 @@ var SqliteModelBuilder = class extends ModelBuilder {
|
|
|
698
702
|
const table = sqliteTable(tableName, this.schemaToSqliteColumns(tableName, entity.schema, options.enums, options.tables), this.getTableConfig(entity, options.tables));
|
|
699
703
|
options.tables.set(tableName, table);
|
|
700
704
|
}
|
|
701
|
-
buildView(view, options) {
|
|
702
|
-
const viewName = view.name;
|
|
703
|
-
if (options.tables.has(viewName)) return;
|
|
704
|
-
if (view.materialized) throw new AlephaError("SQLite does not support materialized views");
|
|
705
|
-
const drizzleView = sqliteView(viewName, this.schemaToSqliteColumns(viewName, view.schema, /* @__PURE__ */ new Map(), options.tables)).existing();
|
|
706
|
-
options.tables.set(viewName, drizzleView);
|
|
707
|
-
}
|
|
708
705
|
buildSequence(sequence, options) {
|
|
709
706
|
throw new AlephaError("SQLite does not support sequences");
|
|
710
707
|
}
|
|
@@ -748,10 +745,8 @@ var SqliteModelBuilder = class extends ModelBuilder {
|
|
|
748
745
|
col = col.generatedAlwaysAs(gen.expression, { mode: gen.mode ?? "virtual" });
|
|
749
746
|
}
|
|
750
747
|
if (schema.required?.includes(key)) col = col.notNull();
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
[key]: col
|
|
754
|
-
};
|
|
748
|
+
columns[key] = col;
|
|
749
|
+
return columns;
|
|
755
750
|
}, {});
|
|
756
751
|
};
|
|
757
752
|
mapFieldToSqliteColumn = (tableName, fieldName, value, enums) => {
|
|
@@ -1663,8 +1658,7 @@ var Repository = class Repository {
|
|
|
1663
1658
|
constructor(entity, provider = DatabaseProvider) {
|
|
1664
1659
|
this.entity = entity;
|
|
1665
1660
|
this.provider = this.alepha.inject(provider);
|
|
1666
|
-
|
|
1667
|
-
else this.provider.registerEntity(entity);
|
|
1661
|
+
this.provider.registerEntity(entity);
|
|
1668
1662
|
}
|
|
1669
1663
|
/**
|
|
1670
1664
|
* Represents the primary key of the table.
|
|
@@ -1689,12 +1683,6 @@ var Repository = class Repository {
|
|
|
1689
1683
|
return this.entity.name;
|
|
1690
1684
|
}
|
|
1691
1685
|
/**
|
|
1692
|
-
* Whether this repository is backed by a view (read-only).
|
|
1693
|
-
*/
|
|
1694
|
-
get isReadOnly() {
|
|
1695
|
-
return this.entity.isView === true;
|
|
1696
|
-
}
|
|
1697
|
-
/**
|
|
1698
1686
|
* Getter for the database connection from the database provider.
|
|
1699
1687
|
*
|
|
1700
1688
|
* Automatically picks up a transaction from `alepha.store` if one was set
|
|
@@ -1970,7 +1958,6 @@ var Repository = class Repository {
|
|
|
1970
1958
|
* @returns The ID of the created entity.
|
|
1971
1959
|
*/
|
|
1972
1960
|
async create(data, opts = {}) {
|
|
1973
|
-
this.assertWritable();
|
|
1974
1961
|
this.stampOrganization(data);
|
|
1975
1962
|
await this.alepha.events.emit("repository:create:before", {
|
|
1976
1963
|
tableName: this.tableName,
|
|
@@ -1999,7 +1986,6 @@ var Repository = class Repository {
|
|
|
1999
1986
|
* @returns The created entities.
|
|
2000
1987
|
*/
|
|
2001
1988
|
async createMany(values, opts = {}) {
|
|
2002
|
-
this.assertWritable();
|
|
2003
1989
|
if (values.length === 0) return [];
|
|
2004
1990
|
for (const value of values) this.stampOrganization(value);
|
|
2005
1991
|
await this.alepha.events.emit("repository:create:before", {
|
|
@@ -2055,7 +2041,6 @@ var Repository = class Repository {
|
|
|
2055
2041
|
* ```
|
|
2056
2042
|
*/
|
|
2057
2043
|
async upsert(data, opts = {}) {
|
|
2058
|
-
this.assertWritable();
|
|
2059
2044
|
this.stampOrganization(data);
|
|
2060
2045
|
await this.alepha.events.emit("repository:create:before", {
|
|
2061
2046
|
tableName: this.tableName,
|
|
@@ -2092,7 +2077,6 @@ var Repository = class Repository {
|
|
|
2092
2077
|
* Find an entity and update it.
|
|
2093
2078
|
*/
|
|
2094
2079
|
async updateOne(where, data, opts = {}) {
|
|
2095
|
-
this.assertWritable();
|
|
2096
2080
|
await this.alepha.events.emit("repository:update:before", {
|
|
2097
2081
|
tableName: this.tableName,
|
|
2098
2082
|
where,
|
|
@@ -2143,7 +2127,6 @@ var Repository = class Repository {
|
|
|
2143
2127
|
* @see {@link DbVersionMismatchError}
|
|
2144
2128
|
*/
|
|
2145
2129
|
async save(entity, opts = {}) {
|
|
2146
|
-
this.assertWritable();
|
|
2147
2130
|
const row = entity;
|
|
2148
2131
|
const id = row[this.id.key];
|
|
2149
2132
|
if (id == null) throw new AlephaError("Cannot save entity without ID - missing primary key in value");
|
|
@@ -2181,7 +2164,6 @@ var Repository = class Repository {
|
|
|
2181
2164
|
* Find many entities and update all of them.
|
|
2182
2165
|
*/
|
|
2183
2166
|
async updateMany(where, data, opts = {}) {
|
|
2184
|
-
this.assertWritable();
|
|
2185
2167
|
await this.alepha.events.emit("repository:update:before", {
|
|
2186
2168
|
tableName: this.tableName,
|
|
2187
2169
|
where,
|
|
@@ -2210,7 +2192,6 @@ var Repository = class Repository {
|
|
|
2210
2192
|
* @returns Array of deleted entity IDs
|
|
2211
2193
|
*/
|
|
2212
2194
|
async deleteMany(where = {}, opts = {}) {
|
|
2213
|
-
this.assertWritable();
|
|
2214
2195
|
const deletedAt = this.deletedAt();
|
|
2215
2196
|
if (deletedAt && !opts.force) return await this.updateMany(where, { [deletedAt.key]: opts.now ?? this.dateTimeProvider.nowISOString() }, opts);
|
|
2216
2197
|
where = this.withOrganization(where);
|
|
@@ -2464,19 +2445,6 @@ var Repository = class Repository {
|
|
|
2464
2445
|
return entity;
|
|
2465
2446
|
}
|
|
2466
2447
|
/**
|
|
2467
|
-
* Throw if this repository is read-only (backed by a view).
|
|
2468
|
-
*/
|
|
2469
|
-
assertWritable() {
|
|
2470
|
-
if (this.isReadOnly) throw new AlephaError(`Cannot write to view '${this.tableName}'. Views are read-only.`);
|
|
2471
|
-
}
|
|
2472
|
-
/**
|
|
2473
|
-
* Refresh a materialized view. PostgreSQL only.
|
|
2474
|
-
*/
|
|
2475
|
-
async refresh() {
|
|
2476
|
-
if (!this.entity.materialized) throw new AlephaError(`Cannot refresh '${this.tableName}'. Only materialized views support refresh.`);
|
|
2477
|
-
await this.provider.execute(`REFRESH MATERIALIZED VIEW ${this.tableName}`);
|
|
2478
|
-
}
|
|
2479
|
-
/**
|
|
2480
2448
|
* Build a cache key from method name and query parameters.
|
|
2481
2449
|
*/
|
|
2482
2450
|
buildCacheKey(method, query) {
|
|
@@ -2617,366 +2585,6 @@ var DbConnectionError = class DbConnectionError extends DbError {
|
|
|
2617
2585
|
}
|
|
2618
2586
|
};
|
|
2619
2587
|
//#endregion
|
|
2620
|
-
//#region ../../src/orm/core/helpers/parseQueryString.ts
|
|
2621
|
-
/**
|
|
2622
|
-
* Parse a string query into a PgQueryWhere object.
|
|
2623
|
-
*
|
|
2624
|
-
* Supported syntax:
|
|
2625
|
-
* - Simple equality: "name=John"
|
|
2626
|
-
* - Wildcard patterns: "name=John*" (startsWith), "name=*John" (endsWith), "name=*John*" (contains)
|
|
2627
|
-
* - Operators: "age>18", "age>=18", "age<65", "age<=65", "status!=active"
|
|
2628
|
-
* - NULL checks: "deletedAt=null", "email!=null"
|
|
2629
|
-
* - IN arrays: "status=[pending,active]"
|
|
2630
|
-
* - AND conditions: "name=John&age>18"
|
|
2631
|
-
* - OR conditions: "name=John|email=john@example.com"
|
|
2632
|
-
* - Nested AND/OR: "(name=John|name=Jane)&age>18"
|
|
2633
|
-
* - JSONB nested: "profile.city=Paris"
|
|
2634
|
-
*
|
|
2635
|
-
* @example
|
|
2636
|
-
* ```ts
|
|
2637
|
-
* // Simple equality
|
|
2638
|
-
* parseQueryString("name=John")
|
|
2639
|
-
* // => { name: { eq: "John" } }
|
|
2640
|
-
*
|
|
2641
|
-
* // Wildcard patterns
|
|
2642
|
-
* parseQueryString("name=John*") // startsWith
|
|
2643
|
-
* // => { name: { startsWith: "John" } }
|
|
2644
|
-
* parseQueryString("name=*Smith") // endsWith
|
|
2645
|
-
* // => { name: { endsWith: "Smith" } }
|
|
2646
|
-
* parseQueryString("name=*oh*") // contains
|
|
2647
|
-
* // => { name: { contains: "oh" } }
|
|
2648
|
-
*
|
|
2649
|
-
* // Multiple conditions
|
|
2650
|
-
* parseQueryString("name=John&age>18")
|
|
2651
|
-
* // => { and: [{ name: { eq: "John" } }, { age: { gt: 18 } }] }
|
|
2652
|
-
*
|
|
2653
|
-
* // OR conditions
|
|
2654
|
-
* parseQueryString("status=active|status=pending")
|
|
2655
|
-
* // => { or: [{ status: { eq: "active" } }, { status: { eq: "pending" } }] }
|
|
2656
|
-
*
|
|
2657
|
-
* // Complex nested
|
|
2658
|
-
* parseQueryString("(name=John|name=Jane)&age>18&status!=archived")
|
|
2659
|
-
* // => { and: [
|
|
2660
|
-
* // { or: [{ name: { eq: "John" } }, { name: { eq: "Jane" } }] },
|
|
2661
|
-
* // { age: { gt: 18 } },
|
|
2662
|
-
* // { status: { ne: "archived" } }
|
|
2663
|
-
* // ] }
|
|
2664
|
-
*
|
|
2665
|
-
* // JSONB nested query
|
|
2666
|
-
* parseQueryString("profile.city=Paris&profile.age>25")
|
|
2667
|
-
* // => { profile: { city: { eq: "Paris" }, age: { gt: 25 } } }
|
|
2668
|
-
* ```
|
|
2669
|
-
*/
|
|
2670
|
-
function parseQueryString(query) {
|
|
2671
|
-
if (!query || query.trim() === "") return {};
|
|
2672
|
-
return new QueryStringParser(query).parse();
|
|
2673
|
-
}
|
|
2674
|
-
var QueryStringParser = class {
|
|
2675
|
-
pos = 0;
|
|
2676
|
-
query;
|
|
2677
|
-
constructor(query) {
|
|
2678
|
-
this.query = query.trim();
|
|
2679
|
-
}
|
|
2680
|
-
parse() {
|
|
2681
|
-
return this.parseExpression();
|
|
2682
|
-
}
|
|
2683
|
-
parseExpression() {
|
|
2684
|
-
return this.parseOr();
|
|
2685
|
-
}
|
|
2686
|
-
parseOr() {
|
|
2687
|
-
const left = this.parseAnd();
|
|
2688
|
-
if (this.peek() === "|") {
|
|
2689
|
-
const conditions = [left];
|
|
2690
|
-
while (this.peek() === "|") {
|
|
2691
|
-
this.consume("|");
|
|
2692
|
-
conditions.push(this.parseAnd());
|
|
2693
|
-
}
|
|
2694
|
-
return { or: conditions };
|
|
2695
|
-
}
|
|
2696
|
-
return left;
|
|
2697
|
-
}
|
|
2698
|
-
parseAnd() {
|
|
2699
|
-
const left = this.parsePrimary();
|
|
2700
|
-
if (this.peek() === "&") {
|
|
2701
|
-
const conditions = [left];
|
|
2702
|
-
while (this.peek() === "&") {
|
|
2703
|
-
this.consume("&");
|
|
2704
|
-
conditions.push(this.parsePrimary());
|
|
2705
|
-
}
|
|
2706
|
-
return { and: conditions };
|
|
2707
|
-
}
|
|
2708
|
-
return left;
|
|
2709
|
-
}
|
|
2710
|
-
parsePrimary() {
|
|
2711
|
-
this.skipWhitespace();
|
|
2712
|
-
if (this.peek() === "(") {
|
|
2713
|
-
this.consume("(");
|
|
2714
|
-
const expr = this.parseExpression();
|
|
2715
|
-
this.consume(")");
|
|
2716
|
-
return expr;
|
|
2717
|
-
}
|
|
2718
|
-
return this.parseCondition();
|
|
2719
|
-
}
|
|
2720
|
-
parseCondition() {
|
|
2721
|
-
const field = this.parseFieldPath();
|
|
2722
|
-
this.skipWhitespace();
|
|
2723
|
-
const operator = this.parseOperator();
|
|
2724
|
-
this.skipWhitespace();
|
|
2725
|
-
const value = this.parseValue();
|
|
2726
|
-
if (value === "") throw new AlephaError(`Expected value for field '${field.join(".")}'`);
|
|
2727
|
-
return this.buildCondition(field, operator, value);
|
|
2728
|
-
}
|
|
2729
|
-
parseFieldPath() {
|
|
2730
|
-
const path = [];
|
|
2731
|
-
let current = "";
|
|
2732
|
-
while (this.pos < this.query.length) {
|
|
2733
|
-
const ch = this.query[this.pos];
|
|
2734
|
-
if (ch === "." && current) {
|
|
2735
|
-
path.push(current);
|
|
2736
|
-
current = "";
|
|
2737
|
-
this.pos++;
|
|
2738
|
-
continue;
|
|
2739
|
-
}
|
|
2740
|
-
if (ch === "=" || ch === "!" || ch === ">" || ch === "<" || ch === " ") break;
|
|
2741
|
-
current += ch;
|
|
2742
|
-
this.pos++;
|
|
2743
|
-
}
|
|
2744
|
-
if (current) path.push(current);
|
|
2745
|
-
return path;
|
|
2746
|
-
}
|
|
2747
|
-
parseOperator() {
|
|
2748
|
-
this.skipWhitespace();
|
|
2749
|
-
const remaining = this.query.slice(this.pos);
|
|
2750
|
-
if (remaining.startsWith(">=")) {
|
|
2751
|
-
this.pos += 2;
|
|
2752
|
-
return ">=";
|
|
2753
|
-
}
|
|
2754
|
-
if (remaining.startsWith("<=")) {
|
|
2755
|
-
this.pos += 2;
|
|
2756
|
-
return "<=";
|
|
2757
|
-
}
|
|
2758
|
-
if (remaining.startsWith("!=")) {
|
|
2759
|
-
this.pos += 2;
|
|
2760
|
-
return "!=";
|
|
2761
|
-
}
|
|
2762
|
-
const ch = this.query[this.pos];
|
|
2763
|
-
if (ch === "=" || ch === ">" || ch === "<") {
|
|
2764
|
-
this.pos++;
|
|
2765
|
-
return ch;
|
|
2766
|
-
}
|
|
2767
|
-
throw new AlephaError(`Expected operator at position ${this.pos}`);
|
|
2768
|
-
}
|
|
2769
|
-
parseValue() {
|
|
2770
|
-
this.skipWhitespace();
|
|
2771
|
-
if (this.query.slice(this.pos, this.pos + 4).toLowerCase() === "null") {
|
|
2772
|
-
this.pos += 4;
|
|
2773
|
-
return null;
|
|
2774
|
-
}
|
|
2775
|
-
if (this.query[this.pos] === "[") return this.parseArray();
|
|
2776
|
-
if (this.query[this.pos] === "\"" || this.query[this.pos] === "'") return this.parseQuotedString();
|
|
2777
|
-
let value = "";
|
|
2778
|
-
while (this.pos < this.query.length) {
|
|
2779
|
-
const ch = this.query[this.pos];
|
|
2780
|
-
if (ch === "&" || ch === "|" || ch === ")") break;
|
|
2781
|
-
value += ch;
|
|
2782
|
-
this.pos++;
|
|
2783
|
-
}
|
|
2784
|
-
return this.coerceValue(value.trim());
|
|
2785
|
-
}
|
|
2786
|
-
parseArray() {
|
|
2787
|
-
this.consume("[");
|
|
2788
|
-
const values = [];
|
|
2789
|
-
while (this.pos < this.query.length && this.query[this.pos] !== "]") {
|
|
2790
|
-
this.skipWhitespace();
|
|
2791
|
-
if (this.query[this.pos] === "\"" || this.query[this.pos] === "'") values.push(this.parseQuotedString());
|
|
2792
|
-
else {
|
|
2793
|
-
let value = "";
|
|
2794
|
-
while (this.pos < this.query.length && this.query[this.pos] !== "," && this.query[this.pos] !== "]") {
|
|
2795
|
-
value += this.query[this.pos];
|
|
2796
|
-
this.pos++;
|
|
2797
|
-
}
|
|
2798
|
-
values.push(this.coerceValue(value.trim()));
|
|
2799
|
-
}
|
|
2800
|
-
this.skipWhitespace();
|
|
2801
|
-
if (this.query[this.pos] === ",") this.pos++;
|
|
2802
|
-
}
|
|
2803
|
-
this.consume("]");
|
|
2804
|
-
return values;
|
|
2805
|
-
}
|
|
2806
|
-
parseQuotedString() {
|
|
2807
|
-
const quote = this.query[this.pos];
|
|
2808
|
-
this.pos++;
|
|
2809
|
-
let value = "";
|
|
2810
|
-
let escaped = false;
|
|
2811
|
-
while (this.pos < this.query.length) {
|
|
2812
|
-
const ch = this.query[this.pos];
|
|
2813
|
-
if (escaped) {
|
|
2814
|
-
value += ch;
|
|
2815
|
-
escaped = false;
|
|
2816
|
-
this.pos++;
|
|
2817
|
-
continue;
|
|
2818
|
-
}
|
|
2819
|
-
if (ch === "\\") {
|
|
2820
|
-
escaped = true;
|
|
2821
|
-
this.pos++;
|
|
2822
|
-
continue;
|
|
2823
|
-
}
|
|
2824
|
-
if (ch === quote) {
|
|
2825
|
-
this.pos++;
|
|
2826
|
-
break;
|
|
2827
|
-
}
|
|
2828
|
-
value += ch;
|
|
2829
|
-
this.pos++;
|
|
2830
|
-
}
|
|
2831
|
-
return value;
|
|
2832
|
-
}
|
|
2833
|
-
coerceValue(value) {
|
|
2834
|
-
if (/^-?\d+$/.test(value)) return parseInt(value, 10);
|
|
2835
|
-
if (/^-?\d+\.\d+$/.test(value)) return parseFloat(value);
|
|
2836
|
-
if (value.toLowerCase() === "true") return true;
|
|
2837
|
-
if (value.toLowerCase() === "false") return false;
|
|
2838
|
-
return value;
|
|
2839
|
-
}
|
|
2840
|
-
buildCondition(path, operator, value) {
|
|
2841
|
-
let filterOp;
|
|
2842
|
-
if (operator === "=") if (value === null) filterOp = { isNull: true };
|
|
2843
|
-
else if (Array.isArray(value)) filterOp = { inArray: value };
|
|
2844
|
-
else if (typeof value === "string" && value.includes("*")) {
|
|
2845
|
-
const startsWithAsterisk = value.startsWith("*");
|
|
2846
|
-
const endsWithAsterisk = value.endsWith("*");
|
|
2847
|
-
const cleanValue = value.replace(/^\*|\*$/g, "");
|
|
2848
|
-
if (startsWithAsterisk && endsWithAsterisk) filterOp = { contains: cleanValue };
|
|
2849
|
-
else if (startsWithAsterisk) filterOp = { endsWith: cleanValue };
|
|
2850
|
-
else if (endsWithAsterisk) filterOp = { startsWith: cleanValue };
|
|
2851
|
-
else filterOp = { eq: value };
|
|
2852
|
-
} else filterOp = { eq: value };
|
|
2853
|
-
else if (operator === "!=") if (value === null) filterOp = { isNotNull: true };
|
|
2854
|
-
else filterOp = { ne: value };
|
|
2855
|
-
else if (operator === ">") filterOp = { gt: value };
|
|
2856
|
-
else if (operator === ">=") filterOp = { gte: value };
|
|
2857
|
-
else if (operator === "<") filterOp = { lt: value };
|
|
2858
|
-
else if (operator === "<=") filterOp = { lte: value };
|
|
2859
|
-
else throw new AlephaError(`Unsupported operator: ${operator}`);
|
|
2860
|
-
if (path.length === 1) return { [path[0]]: filterOp };
|
|
2861
|
-
let result = filterOp;
|
|
2862
|
-
for (let i = path.length - 1; i >= 0; i--) result = { [path[i]]: result };
|
|
2863
|
-
return result;
|
|
2864
|
-
}
|
|
2865
|
-
peek() {
|
|
2866
|
-
this.skipWhitespace();
|
|
2867
|
-
return this.query[this.pos] || "";
|
|
2868
|
-
}
|
|
2869
|
-
consume(expected) {
|
|
2870
|
-
this.skipWhitespace();
|
|
2871
|
-
if (this.query[this.pos] !== expected) throw new AlephaError(`Expected '${expected}' at position ${this.pos}, got '${this.query[this.pos]}'`);
|
|
2872
|
-
this.pos++;
|
|
2873
|
-
}
|
|
2874
|
-
skipWhitespace() {
|
|
2875
|
-
while (this.pos < this.query.length && /\s/.test(this.query[this.pos])) this.pos++;
|
|
2876
|
-
}
|
|
2877
|
-
};
|
|
2878
|
-
/**
|
|
2879
|
-
* Helper function to build query strings programmatically
|
|
2880
|
-
*
|
|
2881
|
-
* @example
|
|
2882
|
-
* ```ts
|
|
2883
|
-
* buildQueryString({
|
|
2884
|
-
* and: [
|
|
2885
|
-
* { name: "eq:John" },
|
|
2886
|
-
* { age: "gt:18" }
|
|
2887
|
-
* ]
|
|
2888
|
-
* })
|
|
2889
|
-
* // => "name=John&age>18"
|
|
2890
|
-
* ```
|
|
2891
|
-
*/
|
|
2892
|
-
function buildQueryString(where) {
|
|
2893
|
-
if (!where || typeof where !== "object") return "";
|
|
2894
|
-
if ("and" in where && Array.isArray(where.and)) return where.and.map((w) => buildQueryString(w)).join("&");
|
|
2895
|
-
if ("or" in where && Array.isArray(where.or)) {
|
|
2896
|
-
const parts = where.or.map((w) => buildQueryString(w));
|
|
2897
|
-
return parts.length > 1 ? `(${parts.join("|")})` : parts[0];
|
|
2898
|
-
}
|
|
2899
|
-
if ("not" in where) return "";
|
|
2900
|
-
const parts = [];
|
|
2901
|
-
for (const [field, condition] of Object.entries(where)) {
|
|
2902
|
-
if (typeof condition !== "object" || condition === null) {
|
|
2903
|
-
parts.push(`${field}=${condition}`);
|
|
2904
|
-
continue;
|
|
2905
|
-
}
|
|
2906
|
-
if ("eq" in condition) parts.push(`${field}=${condition.eq}`);
|
|
2907
|
-
else if ("ne" in condition) parts.push(`${field}!=${condition.ne}`);
|
|
2908
|
-
else if ("gt" in condition) parts.push(`${field}>${condition.gt}`);
|
|
2909
|
-
else if ("gte" in condition) parts.push(`${field}>=${condition.gte}`);
|
|
2910
|
-
else if ("lt" in condition) parts.push(`${field}<${condition.lt}`);
|
|
2911
|
-
else if ("lte" in condition) parts.push(`${field}<=${condition.lte}`);
|
|
2912
|
-
else if ("contains" in condition) parts.push(`${field}=*${condition.contains}*`);
|
|
2913
|
-
else if ("startsWith" in condition) parts.push(`${field}=${condition.startsWith}*`);
|
|
2914
|
-
else if ("endsWith" in condition) parts.push(`${field}=*${condition.endsWith}`);
|
|
2915
|
-
else if ("isNull" in condition && condition.isNull) parts.push(`${field}=null`);
|
|
2916
|
-
else if ("isNotNull" in condition && condition.isNotNull) parts.push(`${field}!=null`);
|
|
2917
|
-
else if ("inArray" in condition && Array.isArray(condition.inArray)) {
|
|
2918
|
-
const values = condition.inArray.map((v) => typeof v === "string" ? `"${v}"` : v);
|
|
2919
|
-
parts.push(`${field}=[${values.join(",")}]`);
|
|
2920
|
-
} else {
|
|
2921
|
-
const nested = buildQueryString(condition);
|
|
2922
|
-
if (nested) parts.push(`${field}.${nested}`);
|
|
2923
|
-
}
|
|
2924
|
-
}
|
|
2925
|
-
return parts.join("&");
|
|
2926
|
-
}
|
|
2927
|
-
//#endregion
|
|
2928
|
-
//#region ../../src/orm/core/primitives/$view.ts
|
|
2929
|
-
/**
|
|
2930
|
-
* Creates a database view primitive from a TypeBox schema and SQL query.
|
|
2931
|
-
*
|
|
2932
|
-
* Views are read-only: Repository blocks all write operations.
|
|
2933
|
-
*
|
|
2934
|
-
* @example
|
|
2935
|
-
* ```ts
|
|
2936
|
-
* import { t } from "alepha";
|
|
2937
|
-
* import { $view } from "alepha/orm";
|
|
2938
|
-
* import { sql } from "drizzle-orm";
|
|
2939
|
-
*
|
|
2940
|
-
* const userSummary = $view({
|
|
2941
|
-
* name: "user_summary",
|
|
2942
|
-
* schema: t.object({
|
|
2943
|
-
* id: t.uuid(),
|
|
2944
|
-
* fullName: t.text(),
|
|
2945
|
-
* orderCount: t.integer(),
|
|
2946
|
-
* }),
|
|
2947
|
-
* query: sql`SELECT u.id, u.first_name || ' ' || u.last_name AS full_name, COUNT(o.id) AS order_count FROM users u LEFT JOIN orders o ON o.user_id = u.id GROUP BY u.id`,
|
|
2948
|
-
* });
|
|
2949
|
-
*
|
|
2950
|
-
* // Materialized view (PostgreSQL only)
|
|
2951
|
-
* const monthlyStats = $view({
|
|
2952
|
-
* name: "monthly_stats",
|
|
2953
|
-
* schema: t.object({ ... }),
|
|
2954
|
-
* query: sql`...`,
|
|
2955
|
-
* materialized: true,
|
|
2956
|
-
* });
|
|
2957
|
-
* ```
|
|
2958
|
-
*/
|
|
2959
|
-
const $view = (options) => {
|
|
2960
|
-
return new ViewPrimitive(options);
|
|
2961
|
-
};
|
|
2962
|
-
var ViewPrimitive = class {
|
|
2963
|
-
options;
|
|
2964
|
-
isView = true;
|
|
2965
|
-
constructor(options) {
|
|
2966
|
-
this.options = options;
|
|
2967
|
-
}
|
|
2968
|
-
get name() {
|
|
2969
|
-
return this.options.name;
|
|
2970
|
-
}
|
|
2971
|
-
get schema() {
|
|
2972
|
-
return this.options.schema;
|
|
2973
|
-
}
|
|
2974
|
-
get materialized() {
|
|
2975
|
-
return this.options.materialized ?? false;
|
|
2976
|
-
}
|
|
2977
|
-
};
|
|
2978
|
-
$view[KIND] = ViewPrimitive;
|
|
2979
|
-
//#endregion
|
|
2980
2588
|
//#region ../../src/orm/core/providers/DatabaseTypeProvider.ts
|
|
2981
2589
|
var DatabaseTypeProvider = class {
|
|
2982
2590
|
attr = pgAttr;
|
|
@@ -3085,7 +2693,7 @@ const legacyIdSchema = pgAttr(pgAttr(pgAttr(t.integer(), PG_PRIMARY_KEY), PG_SER
|
|
|
3085
2693
|
//#endregion
|
|
3086
2694
|
//#region ../../src/orm/core/primitives/$repository.ts
|
|
3087
2695
|
/**
|
|
3088
|
-
* Get the repository for the given entity
|
|
2696
|
+
* Get the repository for the given entity.
|
|
3089
2697
|
*/
|
|
3090
2698
|
const $repository = (entity) => {
|
|
3091
2699
|
const { alepha } = $context();
|
|
@@ -3222,6 +2830,6 @@ const AlephaOrm = $module({
|
|
|
3222
2830
|
}
|
|
3223
2831
|
});
|
|
3224
2832
|
//#endregion
|
|
3225
|
-
export { $entity, $repository, $seed, $sequence, $transactional,
|
|
2833
|
+
export { $entity, $repository, $seed, $sequence, $transactional, AlephaOrm, BunSqliteProvider, CloudflareD1Provider, DatabaseProvider, DatabaseTypeProvider, DbCacheProvider, DbColumnNotFoundError, DbConflictError, DbConnectionError, DbDeadlockError, DbEntityNotFoundError, DbError, DbForeignKeyError, DbMigrationError, DbNotNullError, DbTableNotFoundError, DbVersionMismatchError, DrizzleKitProvider, EntityPrimitive, ModelBuilder, PG_CREATED_AT, PG_DEFAULT, PG_DELETED_AT, PG_ENUM, PG_GENERATED, PG_IDENTITY, PG_ORGANIZATION, PG_PRIMARY_KEY, PG_REF, PG_SERIAL, PG_UPDATED_AT, PG_VERSION, Repository, RepositoryProvider, SequencePrimitive, SqliteProvider, bunSqliteOptions, databaseEnvSchema, db, drizzle, getAttrFields, insertSchema, legacyIdSchema, pageQuerySchema, pageSchema, pgAttr, schema, sql, updateSchema };
|
|
3226
2834
|
|
|
3227
2835
|
//# sourceMappingURL=index.bun.js.map
|