Skip to content

Commit

Permalink
feat(tools-storm-plugins-drizzle): Added support for Postgresql and t…
Browse files Browse the repository at this point in the history
…able relations
  • Loading branch information
sullivanpj committed Aug 26, 2023
1 parent f050deb commit bf6387b
Show file tree
Hide file tree
Showing 11 changed files with 419 additions and 169 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CI=true
CI=false
TYPESENSE_API_KEY=xyz
NODE_OPTIONS="--trace-warnings --require helios-opentelemetry-sdk --heapsnapshot-near-heap-limit=3 --heapsnapshot-signal=SIGTERM"

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ jobs:
# - run: npx nx affected -t test --parallel=3 --configuration=ci --base=${{ github.event.before }}

- name: Build repository packages
run: pnpm nx affected -t build --parallel=3 --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }}
run: pnpm nx affected -t build --parallel=3
# run: pnpm nx affected -t build --parallel=3 --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }}

#- name: Run Tests
# uses: nick-fields/[email protected]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ model Contact {

/// @@allow('create,update,delete,read', true)
model ContactAttachment {
id String @id() @default(cuid())
id String @id() @default(uuid())
createdAt DateTime @default(now())
createdBy String
updatedAt DateTime? @updatedAt()
Expand Down
2 changes: 1 addition & 1 deletion libs/contact/typescript/server/attachment/schema.storm
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ model Contact {
// A file attachment included by a Contact
model ContactAttachment {
// The unique identifier for the ContactAttachment
id String @id @default(cuid())
id String @id @default(uuid())

// A timestamp of when the ContactAttachment was created
createdAt DateTime @default(now())
Expand Down
8 changes: 8 additions & 0 deletions libs/core/typescript/shared/utilities/src/common/date-time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@ export class DateTime extends Temporal.Instant implements IDateTime {
return DateTime.getDuration(this, dateTimeTo);
}

/**
* It returns the current `DateTime` object as a JavaScript `Date` object
* @returns A JavaScript `Date` object.
*/
public asJsDate(): Date {
return new Date(this.epochMilliseconds);
}

/**
* Internal identifier field used by architecture to identify the specific object
*/
Expand Down
21 changes: 20 additions & 1 deletion libs/core/typescript/shared/utilities/src/common/string-fns.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
import { dash } from "radash";
import { dash, snake } from "radash";

/**
* Upper case the first character of an input string.
* @example ThisIsAnExample
*/
export const upperCaseFirst = (input?: string): string | undefined => {
return input ? input.charAt(0).toUpperCase() + input.substr(1) : input;
};

/**
* Lower case the first character of an input string.
* @example thisIsAnExample
*/
export const lowerCaseFirst = (input?: string): string | undefined => {
return input ? input.charAt(0).toLowerCase() + input.substr(1) : input;
};

/**
* Convert the input string to kebab case.
* @example this-is-an-example
*/
export const kebabCase = (input?: string): string | undefined => {
return dash(input);
};

/**
* Convert the input string to snake case.
* @example this_is_an_example
*/
export const snakeCase = (input?: string): string | undefined => {
return snake(input);
};

/**
* Convert the input string to constant case.
* @example THIS_IS_AN_EXAMPLE
*/
export const constantCase = (input?: string): string | undefined => {
return snake(input).toUpperCase();
};
127 changes: 54 additions & 73 deletions tools/storm/plugins/drizzle/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import {
upperCaseFirst
} from "@open-system/core-shared-utilities/common/string-fns";
import {
ArrayExpr,
DataModel,
DataSource,
Enum,
MemberAccessExpr,
Model,
isDataModel,
isDataSource,
isEnum
} from "@open-system/tools-storm-language/ast";
import { getDefaultOutputFolder } from "@open-system/tools-storm-schema/plugins/plugin-utils";
Expand All @@ -22,17 +22,19 @@ import {
emitProject,
getDataModels,
getFileHeader,
isForeignKeyField,
getLiteral,
resolvePath,
saveProject
} from "@open-system/tools-storm-schema/sdk";
import { DMMF } from "@prisma/generator-helper";
import { ConnectorType, DMMF } from "@prisma/generator-helper";
import { promises as fs } from "fs";
import { join } from "path";
import { Project } from "ts-morph";
import Transformer from "./transformer";
import { PostgresqlSchemaGenerator } from "./utils/postgresql.schema-gen";
import removeDir from "./utils/removeDir";
import { makeFieldSchema } from "./utils/schema-gen";
import { SchemaGenerator } from "./utils/schema-gen";
import { SqliteSchemaGenerator } from "./utils/sqlite.schema-gen";

export async function generate(
model: Model,
Expand Down Expand Up @@ -71,46 +73,22 @@ export async function generate(
model
);

/*const dataSource = model.declarations.find((d): d is DataSource =>
const dataSource = model.declarations.find((d): d is DataSource =>
isDataSource(d)
);

const dataSourceProvider = getLiteral<string>(
dataSource?.fields.find(f => f.name === "provider")?.value
) as ConnectorType;*/
) as ConnectorType;

await generateModelSchemas(project, model, output);

/*if (options.modelOnly !== true) {
// detailed object schemas referenced from input schemas
Transformer.provider = dataSourceProvider;
addMissingInputObjectTypes(inputObjectTypes, outputObjectTypes, models);
const aggregateOperationSupport =
resolveAggregateOperationSupport(inputObjectTypes);
//await generateObjectSchemas(inputObjectTypes, project, output, model);
// input schemas
const transformer = new Transformer({
models,
modelOperations,
aggregateOperationSupport,
project,
storm: model
});
await transformer.generateInputSchemas();
}*/
await generateModelSchemas(project, model, output, dataSourceProvider);

// create barrel file
const exports = [
`export * as schemas from './schemas'`,
`export * as enums from './enums'`
];
/*if (options.modelOnly !== true) {
exports.push(
`export * as input from './input'`,
`export * as objects from './objects'`
);
}*/

project.createSourceFile(join(output, "index.ts"), exports.join(";\n"), {
overwrite: true
});
Expand Down Expand Up @@ -173,11 +151,14 @@ async function generateEnumSchemas(
async function generateModelSchemas(
project: Project,
storm: Model,
output: string
output: string,
dataSourceProvider: ConnectorType
) {
const schemaNames: string[] = [];
for (const dm of getDataModels(storm)) {
schemaNames.push(await generateModelSchema(dm, project, output));
schemaNames.push(
await generateModelSchema(dm, project, output, dataSourceProvider)
);
}

project.createSourceFile(
Expand All @@ -190,8 +171,23 @@ async function generateModelSchemas(
async function generateModelSchema(
model: DataModel,
project: Project,
output: string
output: string,
dataSourceProvider: ConnectorType
) {
let generator: SchemaGenerator;
switch (dataSourceProvider) {
case "sqlite":
generator = new SqliteSchemaGenerator();
break;
case "postgresql":
generator = new PostgresqlSchemaGenerator();
break;
default:
throw new Error(
`Unsupported data source provider: ${dataSourceProvider}`
);
}

const schemaName = `${kebabCase(model.name)}.schema`;
const sf = project.createSourceFile(
join(output, "schemas", `${schemaName}.ts`),
Expand All @@ -204,15 +200,12 @@ async function generateModelSchema(
const fields = model.fields.filter(
field =>
!AUXILIARY_FIELDS.includes(field.name) &&
// scalar fields only
!isDataModel(field.type.reference?.ref)
);

writer.writeLine("/* eslint-disable */");
writer.writeLine(getFileHeader("Drizzle ORM"));
writer.writeLine(
`import { blob, integer, real, text, sqliteTable } from "drizzle-orm/sqlite-core";`
);
writer.writeLine(generator.importStatement);
writer.writeLine(
`import { UniqueIdGenerator } from "@open-system/core-shared-utilities/common/unique-id-generator";`
);
Expand All @@ -231,45 +224,33 @@ async function generateModelSchema(
}
}

model.fields
.filter(modelField => isDataModel(modelField.type.reference?.ref))
.forEach(modelField => {
writer.writeLine(
`import { ${lowerCaseFirst(
modelField.type.reference.ref.name
)} } from "./${kebabCase(
modelField.type.reference.ref.name
)}.schema";`
);
});

// create base schema
writer.write(
`
export const ${lowerCaseFirst(model.name)} = sqliteTable("${lowerCaseFirst(
model.name
)}", `
);
writer.writeLine("");
writer.write(generator.getTableSchema(model.name));
writer.inlineBlock(() => {
fields.forEach(field => {
let fieldLine = `${field.name}: ${makeFieldSchema(field)}`;

if (isForeignKeyField(field)) {
// field.attributes.find(a => a.name === "relation")
const attribute = field.attributes.find(
attr => attr.decl.ref?.name === "@relation"
);
if (attribute) {
//const foreignKeyFields = attr.args.find(a => a.name === "fields");
const referencesFields = attribute.args.find(
a => a.name === "references"
)?.value as ArrayExpr;
referencesFields.items.forEach(item => {
const reference = item as MemberAccessExpr;

/*const modelFields = model.fields.filter(field =>
isDataModel(field.type.reference?.ref)
);*/

fieldLine += `.references(() => ${lowerCaseFirst(
field.type.reference?.ref.name
)}.${reference?.member?.ref?.name})`;
});
}
}

writer.writeLine(`${fieldLine},`);
writer.writeLine(
`${field.name}: ${generator.getFieldSchema(model, field)},`
);
});
});
writer.writeLine(");");
writer.writeLine("");

writer.writeLine("");
});

return schemaName;
}
7 changes: 5 additions & 2 deletions tools/storm/plugins/drizzle/src/transformer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { kebabCase } from "@open-system/core-shared-utilities/common/string-fns";
import {
constantCase,
kebabCase
} from "@open-system/core-shared-utilities/common/string-fns";
import { Model } from "@open-system/tools-storm-language/ast";
import {
AUXILIARY_FIELDS,
Expand Down Expand Up @@ -61,7 +64,7 @@ export default class Transformer {
)}\n${this.generateExportStatement(
`${name}`,
` {
${filteredValues.map(v => `${v}: "${v}"`).join(", \n")}
${filteredValues.map(v => `${constantCase(v)}: "${v}"`).join(", \n")}
}`
)}`;
this.project.createSourceFile(filePath, content, { overwrite: true });
Expand Down
Loading

0 comments on commit bf6387b

Please sign in to comment.