Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
3f14ed6
Added initial extensions for Database, Schema, Table, Column schema c…
oskardudycz Sep 27, 2025
c8634a6
Added a first naive implementation of SchemaComponentMigrator
oskardudycz Sep 27, 2025
9718612
Added drafts of schema components definitions
oskardudycz Oct 16, 2025
1de4a0d
Added DatabaseSchemaComponent factory
oskardudycz Oct 16, 2025
651a623
Added additional options to SchemaComponent to make easier extending it
oskardudycz Oct 16, 2025
acb210c
Added factories for SchemaComponents
oskardudycz Oct 21, 2025
c846b5a
Removed overengineered kind in schema components and schema component…
oskardudycz Oct 26, 2025
b90e422
Refactored Schema Component to use urn key instead of just component …
oskardudycz Oct 28, 2025
06e7d04
Added mapping for the specific schema component nested components to …
oskardudycz Oct 28, 2025
64660af
Moved schema components to dedicated files
oskardudycz Oct 28, 2025
46bbdcf
Refactored the structure to remove cyclic dependency between migratio…
oskardudycz Oct 28, 2025
a15e854
Added first version of dumbo schema
oskardudycz Oct 28, 2025
f87afe4
Added samples for dumbo schema
oskardudycz Oct 28, 2025
20a2d92
Simplified database schema setup
oskardudycz Oct 29, 2025
8ff99b3
Addef dumbo schema functions overloads
oskardudycz Oct 30, 2025
03fb40a
Refactored Schema component to use exclude instead of omit to avoid a…
oskardudycz Oct 30, 2025
16fde91
Added explicit methods for adding nested components
oskardudycz Oct 31, 2025
70aafb1
Added design and implementation plan
oskardudycz Oct 31, 2025
d247020
Added docs for design of feature schema component
oskardudycz Oct 31, 2025
560748b
Refactored column schema component to take all SQLToken parameters li…
oskardudycz Nov 13, 2025
c1fb729
Adjusted column schema definition to include mandatory type
oskardudycz Nov 13, 2025
e48c1dd
Renamed SQLColumnTokens to SQLColumnTypeTokens to make it explict
oskardudycz Nov 13, 2025
bc24ce6
Refactored SQLToken to be flat to make easier integration with Schema
oskardudycz Nov 14, 2025
511a4c8
Made column schema component be also SQLColumnToken
oskardudycz Nov 15, 2025
1b2b28d
Merged SQL helpers with dumbo schema
oskardudycz Nov 15, 2025
59b9f6d
Added strong typing for column type in column schema
oskardudycz Nov 15, 2025
f800f1e
Added first version of stongly typed dumbo schema
oskardudycz Nov 15, 2025
9cbd4dd
Added columntype sql token to support typed query builders
oskardudycz Nov 18, 2025
e9085d6
Added first draft of type interference for column and table types
oskardudycz Nov 18, 2025
a61bd24
Added explicit json type mapping
oskardudycz Nov 19, 2025
305d825
Fixed nullability mapping of table columns
oskardudycz Nov 19, 2025
aaae02f
Adjusted samples for types interference
oskardudycz Nov 19, 2025
d56eef4
Fixed Pongo databases and collections identifiers to be unique urns
oskardudycz Nov 19, 2025
47a5898
Added helper for TableColumnNames
oskardudycz Nov 19, 2025
9ace79b
Added a way to define primary key for table
oskardudycz Nov 19, 2025
727280e
Added foreign key support
oskardudycz Nov 20, 2025
44c0589
Renamed foreign keys into relationships
oskardudycz Nov 25, 2025
ee1fa6f
Added relationship type
oskardudycz Nov 25, 2025
3e35bff
Refactored relationship validation to include type validation and par…
oskardudycz Nov 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/packages/dumbo/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type {
ExtractDumboDatabaseDriverOptions,
InferDriverDatabaseType,
} from './drivers';
import { dumboSchema } from './schema';
import { SQL, SQLColumnTypeTokensFactory } from './sql';

export * from './connections';
export * from './drivers';
Expand All @@ -15,6 +17,7 @@ export * from './query';
export * from './schema';
export * from './serializer';
export * from './sql';
export * from './testing';
export * from './tracing';

export type Dumbo<
Expand All @@ -39,3 +42,16 @@ export type DumboConnectionOptions<
} & Omit<Options, 'driver' | 'driverType' | 'connectionString'>
: never
: never;

declare module './sql' {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace SQL {
export const columnN: typeof dumboSchema.column & {
type: typeof SQLColumnTypeTokensFactory;
};
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
(SQL as any).columnN = Object.assign(dumboSchema.column, {
type: SQLColumnTypeTokensFactory,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { AnyColumnTypeToken, SQLColumnToken } from '../../sql';
import {
schemaComponent,
type SchemaComponent,
type SchemaComponentOptions,
} from '../schemaComponent';

export type ColumnURNType = 'sc:dumbo:column';
export type ColumnURN<ColumnName extends string = string> =
`${ColumnURNType}:${ColumnName}`;

export const ColumnURNType: ColumnURNType = 'sc:dumbo:column';
export const ColumnURN = <ColumnName extends string = string>({
name,
}: {
name: ColumnName;
}): ColumnURN<ColumnName> => `${ColumnURNType}:${name}`;

export type ColumnSchemaComponent<
ColumnType extends AnyColumnTypeToken | string = AnyColumnTypeToken | string,
ColumnName extends string = string,
> = SchemaComponent<
ColumnURN<ColumnName>,
Readonly<{
columnName: ColumnName;
}>
> &
SQLColumnToken<ColumnType>;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AnyColumnSchemaComponent = ColumnSchemaComponent<any>;

export type ColumnSchemaComponentOptions<
ColumnType extends AnyColumnTypeToken | string = AnyColumnTypeToken | string,
> = Omit<SQLColumnToken<ColumnType>, 'name' | 'sqlTokenType'> &
SchemaComponentOptions;

export const columnSchemaComponent = <
const ColumnType extends AnyColumnTypeToken | string =
| AnyColumnTypeToken
| string,
const TOptions extends
ColumnSchemaComponentOptions<ColumnType> = ColumnSchemaComponentOptions<ColumnType>,
const ColumnName extends string = string,
>(
params: {
columnName: ColumnName;
} & TOptions,
): ColumnSchemaComponent<ColumnType, ColumnName> &
(TOptions extends { notNull: true } | { primaryKey: true }
? { notNull: true }
: { notNull?: false }) => {
const {
columnName,
type,
notNull,
unique,
primaryKey,
default: defaultValue,
...schemaOptions
} = params;

const sc = schemaComponent(ColumnURN({ name: columnName }), schemaOptions);

const result: Record<string, unknown> = {
...sc,
columnName,
notNull,
unique,
primaryKey,
defaultValue,
sqlTokenType: 'SQL_COLUMN',
name: columnName,
type,
};

return result as ColumnSchemaComponent<ColumnType, ColumnName> &
(TOptions extends { notNull: true } | { primaryKey: true }
? { notNull: true }
: { notNull?: false });
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
mapSchemaComponentsOfType,
schemaComponent,
type SchemaComponent,
type SchemaComponentOptions,
} from '../schemaComponent';
import {
DatabaseSchemaURNType,
databaseSchemaSchemaComponent,
type AnyDatabaseSchemaSchemaComponent,
type DatabaseSchemaSchemaComponent,
} from './databaseSchemaSchemaComponent';

export type DatabaseURNType = 'sc:dumbo:database';
export type DatabaseURN = `${DatabaseURNType}:${string}`;

export const DatabaseURNType: DatabaseURNType = 'sc:dumbo:database';
export const DatabaseURN = ({ name }: { name: string }): DatabaseURN =>
`${DatabaseURNType}:${name}`;

export type DatabaseSchemas<
Schemas extends
AnyDatabaseSchemaSchemaComponent = AnyDatabaseSchemaSchemaComponent,
> = Record<string, Schemas>;

export type DatabaseSchemaComponent<
Schemas extends DatabaseSchemas = DatabaseSchemas,
> = SchemaComponent<
DatabaseURN,
Readonly<{
databaseName: string;
schemas: ReadonlyMap<string, DatabaseSchemaSchemaComponent> & Schemas;
addSchema: (
schema: string | DatabaseSchemaSchemaComponent,
) => DatabaseSchemaSchemaComponent;
}>
>;

export type AnyDatabaseSchemaComponent =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
DatabaseSchemaComponent<any>;

export const databaseSchemaComponent = <
Schemas extends DatabaseSchemas = DatabaseSchemas,
>({
databaseName,
schemas,
...migrationsOrComponents
}: {
databaseName: string;
schemas?: Schemas;
} & SchemaComponentOptions): DatabaseSchemaComponent<Schemas> => {
schemas ??= {} as Schemas;

const base = schemaComponent(DatabaseURN({ name: databaseName }), {
migrations: migrationsOrComponents.migrations ?? [],
components: [
...(migrationsOrComponents.components ?? []),
...Object.values(schemas),
],
});

return {
...base,
databaseName,
get schemas() {
const schemasMap =
mapSchemaComponentsOfType<DatabaseSchemaSchemaComponent>(
base.components,
DatabaseSchemaURNType,
(c) => c.schemaName,
);

return Object.assign(schemasMap, schemas);
},
addSchema: (schema: string | DatabaseSchemaSchemaComponent) =>
base.addComponent(
typeof schema === 'string'
? databaseSchemaSchemaComponent({ schemaName: schema })
: schema,
),
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {
mapSchemaComponentsOfType,
schemaComponent,
type SchemaComponent,
type SchemaComponentOptions,
} from '../schemaComponent';
import {
TableURNType,
tableSchemaComponent,
type AnyTableSchemaComponent,
type TableSchemaComponent,
} from './tableSchemaComponent';

export type DatabaseSchemaURNType = 'sc:dumbo:database_schema';
export type DatabaseSchemaURN<SchemaName extends string = string> =
`${DatabaseSchemaURNType}:${SchemaName}`;

export const DatabaseSchemaURNType: DatabaseSchemaURNType =
'sc:dumbo:database_schema';
export const DatabaseSchemaURN = <SchemaName extends string = string>({
name,
}: {
name: SchemaName;
}): DatabaseSchemaURN<SchemaName> => `${DatabaseSchemaURNType}:${name}`;

export type DatabaseSchemaTables<
Tables extends AnyTableSchemaComponent = AnyTableSchemaComponent,
> = Record<string, Tables>;

export type DatabaseSchemaSchemaComponent<
Tables extends DatabaseSchemaTables = DatabaseSchemaTables,
SchemaName extends string = string,
> = SchemaComponent<
DatabaseSchemaURN<SchemaName>,
Readonly<{
schemaName: SchemaName;
tables: ReadonlyMap<string, TableSchemaComponent> & Tables;
addTable: (table: string | TableSchemaComponent) => TableSchemaComponent;
}>
>;

export type AnyDatabaseSchemaSchemaComponent =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
DatabaseSchemaSchemaComponent<any, any>;

export const databaseSchemaSchemaComponent = <
const Tables extends DatabaseSchemaTables = DatabaseSchemaTables,
const SchemaName extends string = string,
>({
schemaName,
tables,
...migrationsOrComponents
}: {
schemaName: SchemaName;
tables?: Tables;
} & SchemaComponentOptions): DatabaseSchemaSchemaComponent<
Tables,
SchemaName
> => {
const base = schemaComponent(DatabaseSchemaURN({ name: schemaName }), {
migrations: migrationsOrComponents.migrations ?? [],
components: [
...(migrationsOrComponents.components ?? []),
...Object.values(tables ?? {}),
],
});

return {
...base,
schemaName,
get tables() {
const tablesMap = mapSchemaComponentsOfType<TableSchemaComponent>(
base.components,
TableURNType,
(c) => c.tableName,
);

return Object.assign(tablesMap, tables);
},
addTable: (table: string | TableSchemaComponent) =>
base.addComponent(
typeof table === 'string'
? tableSchemaComponent({ tableName: table })
: table,
),
};
};
25 changes: 25 additions & 0 deletions src/packages/dumbo/src/core/schema/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ColumnURN } from './columnSchemaComponent';
import { DatabaseURN } from './databaseSchemaComponent';
import { DatabaseSchemaURN } from './databaseSchemaSchemaComponent';
import { IndexURN } from './indexSchemaComponent';
import { TableURN } from './tableSchemaComponent';

export * from './columnSchemaComponent';
export * from './databaseSchemaComponent';
export * from './databaseSchemaSchemaComponent';
export * from './indexSchemaComponent';
export * from './relationships';
export * from './tableSchemaComponent';
export * from './tableTypesInference';

export const schemaComponentURN = {
database: DatabaseURN,
schema: DatabaseSchemaURN,
table: TableURN,
column: ColumnURN,
index: IndexURN,
extractName: (urn: string): string => {
const parts = urn.split(':');
return parts[parts.length - 1] || '';
},
} as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
schemaComponent,
type SchemaComponent,
type SchemaComponentOptions,
} from '../schemaComponent';
import { type ColumnSchemaComponent } from './columnSchemaComponent';

export type IndexURNType = 'sc:dumbo:index';
export type IndexURN = `${IndexURNType}:${string}`;

export type IndexSchemaComponent = SchemaComponent<
IndexURN,
Readonly<{
indexName: string;
columnNames: ReadonlyArray<string>;
isUnique: boolean;
addColumn: (column: string | ColumnSchemaComponent) => void;
}>
>;

export const IndexURNType: IndexURNType = 'sc:dumbo:index';
export const IndexURN = ({ name }: { name: string }): IndexURN =>
`${IndexURNType}:${name}`;

export const indexSchemaComponent = ({
indexName,
columnNames,
isUnique,
...migrationsOrComponents
}: {
indexName: string;
columnNames: string[];
isUnique: boolean;
} & SchemaComponentOptions): IndexSchemaComponent => {
const sc = schemaComponent(IndexURN({ name: indexName }), {
migrations: migrationsOrComponents.migrations ?? [],
components: [...(migrationsOrComponents.components ?? [])],
});

return {
...sc,
indexName,
get columnNames() {
return columnNames;
},
addColumn: (column: string | ColumnSchemaComponent) =>
columnNames.push(typeof column === 'string' ? column : column.columnName),
isUnique,
};
};
Loading