@embracesql/postgres
Advanced tools
Comparing version 0.0.8 to 0.0.9
{ | ||
"name": "@embracesql/postgres", | ||
"version": "0.0.8", | ||
"version": "0.0.9", | ||
"description": "EmbraceSQL shared library for talking to postgres. Used in Node.", | ||
@@ -13,3 +13,3 @@ "type": "module", | ||
"dependencies": { | ||
"@embracesql/shared": "^0.0.8", | ||
"@embracesql/shared": "^0.0.9", | ||
"glob": "^10.3.10", | ||
@@ -23,3 +23,3 @@ "object-hash": "^3.0.0", | ||
}, | ||
"gitHead": "92c10ccba1bac0a6e94cd89576f0c73d16cf5bcf" | ||
"gitHead": "149e4adeacf43a8b41c906a492e5ddeb4ed0114b" | ||
} |
@@ -1,2 +0,2 @@ | ||
import { Context, TypeFactoryContext } from "../../context"; | ||
import { TypeFactoryContext } from "../../context"; | ||
import { groupBy } from "../../util"; | ||
@@ -7,3 +7,2 @@ import { PGAttribute, PGAttributes } from "./pgattribute"; | ||
import { GenerationContext, IndexNode, TableNode } from "@embracesql/shared"; | ||
import { pascalCase } from "change-case"; | ||
import path from "path"; | ||
@@ -44,3 +43,3 @@ import { Sql } from "postgres"; | ||
this.indexesByTableTypeOid[catalogType.oid]?.sort((l, r) => | ||
l.typescriptName.localeCompare(r.typescriptName), | ||
l.name.localeCompare(r.name), | ||
) ?? [] | ||
@@ -88,6 +87,2 @@ ); | ||
get unique() { | ||
return this.index.indisunique; | ||
} | ||
get primaryKey() { | ||
@@ -111,23 +106,2 @@ return this.index.indisprimary; | ||
} | ||
get typescriptName() { | ||
return `By${pascalCase( | ||
this.attributes.map((a) => a.typescriptName).join("_"), | ||
)}`; | ||
} | ||
/** | ||
* Code generation builder for an exact index match. | ||
*/ | ||
sqlPredicate(context: Context, parameterHolder = "parameters") { | ||
return this.attributes | ||
.map( | ||
(a) => | ||
`${a.postgresName} = ${a.postgresValueExpression( | ||
context, | ||
parameterHolder, | ||
)}`, | ||
) | ||
.join(" AND "); | ||
} | ||
} |
@@ -18,21 +18,6 @@ import { postgresResultRecordToTypescript, sqlPredicate } from "./shared"; | ||
async before(context: GenerationContext, node: DeleteOperationNode) { | ||
const generationBuffer = [""]; | ||
const parameters = `${PARAMETERS}: ${node.index.typescriptNamespacedName}`; | ||
const returns = node.index.unique | ||
? `Promise<${node.index.table.typescriptNamespacedName}.Record>` | ||
: `Promise<${node.index.table.typescriptNamespacedName}.Record[]>`; | ||
const sqlColumnNames = node.index.table.type.attributes | ||
.map((a) => a.name) | ||
.join(","); | ||
generationBuffer.push( | ||
`async ${node.typescriptPropertyName}(${parameters}) : ${returns}{`, | ||
); | ||
generationBuffer.push( | ||
` | ||
console.assert(parameters); | ||
const sql = this.database.context.sql; | ||
const typed = sql.typed as unknown as PostgresTypecasts; | ||
`, | ||
); | ||
// query using postgres driver bindings to the index | ||
@@ -47,15 +32,15 @@ const sql = ` | ||
generationBuffer.push(`const response = await sql\`${sql}\``); | ||
generationBuffer.push( | ||
`return ${postgresResultRecordToTypescript( | ||
return [ | ||
`async ${node.typescriptPropertyName}(${parameters}) {`, | ||
` console.assert(parameters);`, | ||
` const sql = this.database.context.sql;`, | ||
` const typed = sql.typed as unknown as PostgresTypecasts;`, | ||
` const response = await sql\`${sql}\``, | ||
` return ${postgresResultRecordToTypescript( | ||
context, | ||
node.index.table.type, | ||
)}${node.index.unique ? "[0]" : ""}`, | ||
); | ||
generationBuffer.push(`}`); | ||
return generationBuffer.join("\n"); | ||
`}`, | ||
].join("\n"); | ||
}, | ||
}; |
/** | ||
* Generate a right hand side expression that converts a postgres | ||
* driver result record to a type checked record. | ||
* driver result row to a type checked object. | ||
*/ | ||
@@ -19,2 +19,5 @@ import { | ||
/** | ||
* Generate code to map a postgres row object names to typescript style names. | ||
*/ | ||
export function postgresResultRecordToTypescript( | ||
@@ -29,7 +32,7 @@ context: GenerationContext, | ||
// snippet will pick resultset fields to type map | ||
const recordPieceBuilders = node.attributes.map( | ||
const attributes = node.attributes.map( | ||
(c) => `${c.typescriptPropertyName}: undefinedIsNull(record.${c.name})`, | ||
); | ||
// all the fields in the resultset mapped out to an inferred type array | ||
return `response.map(record => ({ ${recordPieceBuilders.join(",")} }))`; | ||
return `response.map(record => ({ ${attributes.join(",")} }))`; | ||
} | ||
@@ -39,3 +42,27 @@ | ||
} | ||
/** | ||
* Generate code for an empty typescript row object constant. | ||
*/ | ||
export function emptyTypescriptRow( | ||
context: GenerationContext, | ||
node: AbstractTypeNode, | ||
): string { | ||
console.assert(context); | ||
console.assert(node); | ||
if (isNodeType(node, ASTKind.CompositeType)) { | ||
// snippet will pick resultset fields to type map | ||
const attributes = node.attributes.map( | ||
(c) => | ||
`${c.typescriptPropertyName}: ${emptyTypescriptRow(context, c.type)}`, | ||
); | ||
// all the fields in the resultset mapped out to an inferred type array | ||
return `{ ${attributes.join(",")} }`; | ||
} | ||
return "undefined"; | ||
} | ||
/** | ||
* Render a code generation string that will create a postgres 'right hand side' | ||
@@ -42,0 +69,0 @@ * of an equals value expression for this attribute. |
@@ -0,1 +1,2 @@ | ||
import { AllOperation } from "./autocrud/all"; | ||
import { CreateOperation } from "./autocrud/create"; | ||
@@ -8,2 +9,3 @@ import { DeleteOperation } from "./autocrud/delete"; | ||
ASTKind, | ||
BY_PRIMARY_KEY, | ||
CompositeTypeNode, | ||
@@ -55,3 +57,2 @@ GenerationContext, | ||
` | ||
// BEGIN - Node side database connectivity layer | ||
import { Context, initializeContext, PostgresDatabase } from "@embracesql/postgres"; | ||
@@ -201,3 +202,13 @@ import postgres from "postgres"; | ||
[ASTKind.Table]: NestedNamedClassVisitor, | ||
[ASTKind.Index]: NestedNamedClassVisitor, | ||
[ASTKind.Index]: { | ||
before: NestedNamedClassVisitor.before, | ||
after: async (context, node) => { | ||
return [ | ||
await NestedNamedClassVisitor.after(context, node), | ||
node.primaryKey | ||
? `public get ${BY_PRIMARY_KEY}(){ return this.${node.typescriptName} };` | ||
: ``, | ||
].join("\n"); | ||
}, | ||
}, | ||
@@ -207,2 +218,3 @@ // C R U D - AutoCRUD! | ||
[ASTKind.ReadOperation]: ReadOperation, | ||
[ASTKind.AllOperation]: AllOperation, | ||
[ASTKind.UpdateOperation]: UpdateOperation, | ||
@@ -209,0 +221,0 @@ [ASTKind.DeleteOperation]: DeleteOperation, |
@@ -9,2 +9,3 @@ import { | ||
DeleteOperationNode, | ||
AllOperationNode, | ||
} from "@embracesql/shared"; | ||
@@ -82,2 +83,12 @@ | ||
}, | ||
[ASTKind.AllOperation]: { | ||
before: async (_: GenerationContext, node: AllOperationNode) => { | ||
return [ | ||
` | ||
"${node.typescriptNamespacedPropertyName}": async (request: EmbraceSQLRequest<object, object>) => | ||
database.${node.typescriptNamespacedPropertyName}(), | ||
`, | ||
].join("\n"); | ||
}, | ||
}, | ||
[ASTKind.ReadOperation]: { | ||
@@ -84,0 +95,0 @@ before: async (_: GenerationContext, node: ReadOperationNode) => { |
import { GenerationContext } from ".."; | ||
import { asDocComment } from "../../util"; | ||
import { emptyTypescriptRow } from "./autocrud/shared"; | ||
import { generatePrimaryKeyPickers } from "./generatePrimaryKeyPickers"; | ||
@@ -20,7 +21,2 @@ import { generateTypeGuards } from "./generateTypeGuards"; | ||
* types for each available stored function. | ||
* | ||
* | ||
* | ||
* @param context | ||
* @param namespaces | ||
*/ | ||
@@ -35,4 +31,2 @@ export const generateSchemaDefinitions = async (context: GenerationContext) => { | ||
/** | ||
* BEGIN - shared types generated from schema. | ||
* | ||
* These types are node/browser isomorphic and are used by all other | ||
@@ -48,3 +42,3 @@ * EmbraceSQL generated code. | ||
/* @typescript-eslint/no-redundant-type-constituents */ | ||
import {UUID, JsDate, JSONValue, JSONObject, Empty, Nullable, NullableMembers, undefinedIsNull, nullIsUndefined} from "@embracesql/shared"; | ||
import {UUID, JsDate, JSONValue, JSONObject, Empty, Nullable, NullableMembers, undefinedIsNull, nullIsUndefined, NEVER} from "@embracesql/shared"; | ||
import type { PartiallyOptional } from "@embracesql/shared"; | ||
@@ -94,3 +88,3 @@ | ||
[ASTKind.Tables]: NamespaceVisitor, | ||
// tables are defined by types -- but actual rows/records | ||
// tables are defined by types -- but actual rows | ||
// coming back from queries need a required so we get | ||
@@ -114,2 +108,6 @@ // DBMS style value | null semantics -- no undefinded in SQL | ||
`};`, | ||
// empty placeholder rows used in UI adding | ||
`export function emptyRow() {`, | ||
` return ${emptyTypescriptRow(context, node.type)};`, | ||
`}`, | ||
].join("\n"); | ||
@@ -120,3 +118,3 @@ }, | ||
// exhaustive -- if there is no primary key, say so explicitly | ||
node.primaryKey ? "" : `export type PrimaryKey = never;`, | ||
node.primaryKey ? "" : `export type ByPrimaryKey = never;`, | ||
// optional columns -- won't always need to pass these | ||
@@ -132,3 +130,3 @@ // ex: database has a default | ||
VALUES, | ||
)} = PartiallyOptional<Record, Optional & PrimaryKey>`, | ||
)} = PartiallyOptional<Record, Optional & ByPrimaryKey>`, | ||
await NamespaceVisitor.after(context, node), | ||
@@ -145,3 +143,3 @@ ].join("\n"); | ||
node.primaryKey | ||
? `export type PrimaryKey = ${node.typescriptName};` | ||
? `export type ByPrimaryKey = ${node.typescriptName};` | ||
: "", | ||
@@ -148,0 +146,0 @@ ].join("\n"), |
113913
56
3342
+ Added@embracesql/shared@0.0.9(transitive)
- Removed@embracesql/shared@0.0.8(transitive)
Updated@embracesql/shared@^0.0.9