@embracesql/postgres
Advanced tools
Comparing version 0.1.0 to 0.1.1
{ | ||
"name": "@embracesql/postgres", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "EmbraceSQL shared library for talking to postgres. Used in Node.", | ||
@@ -13,3 +13,3 @@ "type": "module", | ||
"dependencies": { | ||
"@embracesql/shared": "^0.1.0", | ||
"@embracesql/shared": "^0.1.1", | ||
"glob": "^10.3.10", | ||
@@ -23,3 +23,3 @@ "object-hash": "^3.0.0", | ||
}, | ||
"gitHead": "6f0191319a0be4f5ebddc92fe81fb0b729521e87" | ||
"gitHead": "8ea204346f819dd1a7cae4e0380f211b89eee243" | ||
} |
import { PGIndexes } from "./generator/pgtype/pgindex"; | ||
import { PGNamespace } from "./generator/pgtype/pgnamespace"; | ||
import { PGProcs } from "./generator/pgtype/pgproc/pgproc"; | ||
import { PGSettings } from "./generator/pgtype/pgsettings"; | ||
import { PGTables } from "./generator/pgtype/pgtable"; | ||
@@ -141,2 +142,5 @@ import { PGTypes } from "./generator/pgtype/pgtype"; | ||
}; | ||
// settings from the database | ||
const settings = await PGSettings.factory(sql); | ||
settings.loadAST(generationContext); | ||
@@ -263,2 +267,5 @@ // start off with the types grouped into namespaces, types will be | ||
database, | ||
settings: Object.fromEntries( | ||
database.settings.map((s) => [s.typescriptPropertyName, s.setting]), | ||
), | ||
}; | ||
@@ -265,0 +272,0 @@ |
@@ -22,1 +22,2 @@ const operatorOverrides = new Map<string, string>(); | ||
registerOperatorOverride("gist_trgm_ops", "%"); | ||
registerOperatorOverride("tsvector_ops", "@@"); |
@@ -0,4 +1,5 @@ | ||
import { Context } from "../../../../context"; | ||
import { PGCatalogType } from "../../pgcatalogtype"; | ||
import { registerOverride } from "../_overrides"; | ||
import { GenerationContext } from "@embracesql/shared"; | ||
import { GenerationContext, Geometry } from "@embracesql/shared"; | ||
@@ -8,11 +9,22 @@ class PGTypeBox extends PGCatalogType { | ||
console.assert(context); | ||
return `Geometry.Box`; | ||
} | ||
typescriptTypeParser(context: GenerationContext) { | ||
console.assert(context); | ||
return ` | ||
{ | ||
upperRight: Point; | ||
lowerLeft: Point; | ||
} | ||
return Geometry.parseBox(from); | ||
`; | ||
} | ||
serializeToPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.serializeBox(x); | ||
} | ||
parseFromPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.parseBox(x as string); | ||
} | ||
} | ||
registerOverride("box", PGTypeBox); |
@@ -0,4 +1,5 @@ | ||
import { Context } from "../../../../context"; | ||
import { PGTypeBase } from "../../pgtypebase"; | ||
import { registerOverride } from "../_overrides"; | ||
import { GenerationContext } from "@embracesql/shared"; | ||
import { GenerationContext, Geometry } from "@embracesql/shared"; | ||
@@ -8,11 +9,22 @@ class PGTypeCircle extends PGTypeBase { | ||
console.assert(context); | ||
return `Geometry.Circle`; | ||
} | ||
typescriptTypeParser(context: GenerationContext) { | ||
console.assert(context); | ||
return ` | ||
{ | ||
center: Point; | ||
radius: number; | ||
} | ||
return Geometry.parseCircle(from); | ||
`; | ||
} | ||
serializeToPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.serializeCircle(x); | ||
} | ||
parseFromPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.parseCircle(x as string); | ||
} | ||
} | ||
registerOverride("circle", PGTypeCircle); |
@@ -0,4 +1,5 @@ | ||
import { Context } from "../../../../context"; | ||
import { PGCatalogType } from "../../pgcatalogtype"; | ||
import { registerOverride } from "../_overrides"; | ||
import { GenerationContext } from "@embracesql/shared"; | ||
import { GenerationContext, Geometry } from "@embracesql/shared"; | ||
@@ -8,12 +9,22 @@ class PGLine extends PGCatalogType { | ||
console.assert(context); | ||
return `Geometry.Line`; | ||
} | ||
typescriptTypeParser(context: GenerationContext) { | ||
console.assert(context); | ||
return ` | ||
{ | ||
a: number; | ||
b: number; | ||
c: number; | ||
} | ||
return Geometry.parseLine(from); | ||
`; | ||
} | ||
serializeToPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.serializeLine(x); | ||
} | ||
parseFromPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.parseLine(x as string); | ||
} | ||
} | ||
registerOverride("line", PGLine); |
@@ -0,4 +1,5 @@ | ||
import { Context } from "../../../../context"; | ||
import { PGCatalogType } from "../../pgcatalogtype"; | ||
import { registerOverride } from "../_overrides"; | ||
import { GenerationContext } from "@embracesql/shared"; | ||
import { GenerationContext, Geometry } from "@embracesql/shared"; | ||
@@ -8,11 +9,22 @@ class PGLineSegment extends PGCatalogType { | ||
console.assert(context); | ||
return `Geometry.LineSegment`; | ||
} | ||
typescriptTypeParser(context: GenerationContext) { | ||
console.assert(context); | ||
return ` | ||
{ | ||
from: Point; | ||
to: Point; | ||
} | ||
return Geometry.parseLineSegment(from); | ||
`; | ||
} | ||
serializeToPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.serializeLineSegment(x); | ||
} | ||
parseFromPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.parseLineSegment(x as string); | ||
} | ||
} | ||
registerOverride("lseg", PGLineSegment); |
@@ -0,4 +1,5 @@ | ||
import { Context } from "../../../../context"; | ||
import { PGCatalogType } from "../../pgcatalogtype"; | ||
import { registerOverride } from "../_overrides"; | ||
import { GenerationContext } from "@embracesql/shared"; | ||
import { GenerationContext, Geometry } from "@embracesql/shared"; | ||
@@ -8,20 +9,22 @@ class PGTypePoint extends PGCatalogType { | ||
console.assert(context); | ||
return `Geometry.Point`; | ||
} | ||
typescriptTypeParser(context: GenerationContext) { | ||
console.assert(context); | ||
return ` | ||
{ | ||
x: number; | ||
y: number; | ||
} | ||
return Geometry.parsePoint(from); | ||
`; | ||
} | ||
} | ||
class PGTypePointArray extends PGCatalogType { | ||
typescriptTypeDefinition(context: GenerationContext) { | ||
serializeToPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return `Array<Point>`; | ||
return Geometry.serializePoint(x); | ||
} | ||
parseFromPostgres(context: Context, x: unknown) { | ||
console.assert(context); | ||
return Geometry.parsePoint(x as string); | ||
} | ||
} | ||
registerOverride("point", PGTypePoint); | ||
registerOverride("path", PGTypePointArray); | ||
registerOverride("polygon", PGTypePointArray); |
@@ -6,7 +6,5 @@ import { PGTypeNumber } from "../base/number"; | ||
// yeah -- looks odd -- but registerOverride needs to be defined first | ||
export * from "./uuid"; | ||
// TODO: geometric types need real use cases and parsers to match docs at | ||
// https://www.postgresql.org/docs/current/datatype-geometric.html | ||
export * from "./geometric/point"; | ||
export * from "./geometric/path"; | ||
export * from "./geometric/box"; | ||
@@ -20,3 +18,5 @@ export * from "./geometric/circle"; | ||
export * from "./cube"; | ||
export * from "./postgis"; | ||
export * from "./tsvector"; | ||
registerOverride("interval", PGTypeNumber); |
@@ -1,5 +0,2 @@ | ||
import { Context } from "../../context"; | ||
import { groupBy } from "../../util"; | ||
import { cleanIdentifierForTypescript } from "@embracesql/shared"; | ||
import { camelCase } from "change-case"; | ||
import path from "path"; | ||
@@ -76,33 +73,2 @@ import { Sql } from "postgres"; | ||
} | ||
get typescriptName() { | ||
// camel case -- this is a 'property like' | ||
return `${camelCase(cleanIdentifierForTypescript(this.attribute.attname))}`; | ||
} | ||
get postgresName() { | ||
return this.attribute.attname; | ||
} | ||
/** | ||
* Render a code generation string that will create a postgres 'right hand side' | ||
* of an equals value expression for this attribute. | ||
* | ||
* This will create an expression that will self equal for undefined on the | ||
* parameterHolder in calling typescript -- allows partial updates. | ||
* | ||
*/ | ||
postgresValueExpression( | ||
context: Context, | ||
parameterHolder = "parameters", | ||
selfEqual = true, | ||
) { | ||
const postgresType = context.resolveType(this.attribute.atttypid); | ||
const undefinedExpression = selfEqual | ||
? `sql("${this.postgresName}")` | ||
: "sql`DEFAULT`"; | ||
const valueExpression = `typed[${postgresType.oid}](${parameterHolder}.${this.typescriptName})`; | ||
const combinedExpression = `${parameterHolder}.${this.typescriptName} === undefined ? ${undefinedExpression} : ${valueExpression}`; | ||
return `\${ ${combinedExpression} }`; | ||
} | ||
} |
@@ -69,2 +69,13 @@ import { Context, PostgresTypecast } from "../../context"; | ||
/** | ||
* Wrap a a WHERE predicate right hand side parameter expression | ||
* with additional postgres side function calls. | ||
* | ||
* Really useful for full text search. | ||
*/ | ||
postgresWrapReadParameter(context: GenerationContext, expression: string) { | ||
console.assert(context); | ||
return expression; | ||
} | ||
/** | ||
* Given a value, turn it into postgres protocol serialization format | ||
@@ -91,2 +102,9 @@ * for use with the postgres driver. | ||
/** | ||
* Override this to change the postgres type id of the serialized result. | ||
*/ | ||
get toOID() { | ||
return this.oid; | ||
} | ||
/** | ||
* Build up the postgres type casting capability. This is used by the postgres | ||
@@ -97,3 +115,3 @@ * driver to go to and from the database. | ||
return { | ||
to: this.oid, | ||
to: this.toOID, | ||
from: [this.oid], | ||
@@ -104,2 +122,12 @@ serialize: (x) => this.serializeToPostgres(context, x), | ||
} | ||
/** | ||
* Build up code to provide additional type options. | ||
*/ | ||
typescriptTypeOptions(context: Context): string { | ||
console.assert(context); | ||
return ` | ||
export type Options = never; | ||
`; | ||
} | ||
} |
@@ -146,9 +146,2 @@ import { PGTypeBool } from "./base/bool"; | ||
); | ||
case "tsvector": | ||
return new PGTypeText( | ||
catalog.oid, | ||
catalog.nspname, | ||
catalog.typname, | ||
"", | ||
); | ||
case "gtsvector": | ||
@@ -161,9 +154,2 @@ return new PGTypeTextArray( | ||
); | ||
case "tsquery": | ||
return new PGTypeText( | ||
catalog.oid, | ||
catalog.nspname, | ||
catalog.typname, | ||
"", | ||
); | ||
case "uri": | ||
@@ -170,0 +156,0 @@ return new PGTypeUri(catalog.oid, catalog.nspname, catalog.typname, ""); |
@@ -73,6 +73,2 @@ import { Context } from "../../context"; | ||
get sqlColumns() { | ||
return this.attributes.map((a) => a.postgresName).join(","); | ||
} | ||
get postgresToTypescript() { | ||
@@ -79,0 +75,0 @@ // snippet will pick resultset fields to type map |
import { postgresToTypescript, postgresValueExpression } from "./shared"; | ||
import { | ||
CreateOperationNode, | ||
GenerationContext, | ||
VALUES, | ||
} from "@embracesql/shared"; | ||
import { camelCase } from "change-case"; | ||
import { CreateOperationNode, GenerationContext } from "@embracesql/shared"; | ||
@@ -14,8 +9,8 @@ /** | ||
async before(context: GenerationContext, node: CreateOperationNode) { | ||
const valuesType = `Partial<${node.table.type.typescriptNamespacedName}>`; | ||
const optionType = `${node.table.typescriptNamespacedName}.Options`; | ||
const generationBuffer = [""]; | ||
generationBuffer.push( | ||
`async create(${camelCase(VALUES)}: ${ | ||
node.table.typescriptNamespacedName | ||
}.Values): Promise<${node.table.type.typescriptNamespacedName}>{`, | ||
`async create(values: ${valuesType}, options?: ${optionType}): Promise<${node.table.type.typescriptNamespacedName}>{`, | ||
); | ||
@@ -42,5 +37,3 @@ generationBuffer.push( | ||
generationBuffer.push(` | ||
if (!${ | ||
node.table.typescriptNamespacedName | ||
}.includesPrimaryKey(${camelCase(VALUES)})) { | ||
if (!${node.table.typescriptNamespacedName}.includesPrimaryKey(values)) { | ||
`); | ||
@@ -52,3 +45,3 @@ const sql = ` | ||
VALUES (${node.table.columnsNotInPrimaryKey | ||
.map((a) => postgresValueExpression(context, a, VALUES)) | ||
.map((a) => postgresValueExpression(context, a, "values")) | ||
.join(",")}) | ||
@@ -73,3 +66,3 @@ RETURNING | ||
VALUES (${node.table.type.attributes | ||
.map((a) => postgresValueExpression(context, a, VALUES)) | ||
.map((a) => postgresValueExpression(context, a, "values")) | ||
.join(",")}) | ||
@@ -76,0 +69,0 @@ ON CONFLICT (${node.table.columnsInPrimaryKey |
import { postgresToTypescript, sqlPredicate } from "./shared"; | ||
import { | ||
PARAMETERS, | ||
DeleteOperationNode, | ||
GenerationContext, | ||
} from "@embracesql/shared"; | ||
import { DeleteOperationNode, GenerationContext } from "@embracesql/shared"; | ||
@@ -18,3 +14,5 @@ /** | ||
async before(context: GenerationContext, node: DeleteOperationNode) { | ||
const parameters = `${PARAMETERS}: ${node.index.type.typescriptNamespacedName}`; | ||
const parameters = `parameters: ${node.index.type.typescriptNamespacedName}`; | ||
const optionType = `${node.index.type.typescriptNamespacedName}.Options & ${node.index.table.typescriptNamespacedName}.Options`; | ||
const options = `options?: ${optionType}`; | ||
const sqlColumnNames = node.index.table.type.attributes | ||
@@ -29,7 +27,7 @@ .map((a) => a.name) | ||
WHERE | ||
${sqlPredicate(context, node.index, PARAMETERS)} | ||
${sqlPredicate(context, node.index, "parameters")} | ||
RETURNING ${sqlColumnNames}`; | ||
return [ | ||
`async ${node.typescriptPropertyName}(${parameters}) {`, | ||
`async ${node.typescriptPropertyName}(${parameters}, ${options}) {`, | ||
` console.assert(parameters);`, | ||
@@ -36,0 +34,0 @@ ` const sql = this.database.context.sql;`, |
@@ -17,3 +17,4 @@ import { postgresToTypescript, sqlPredicate } from "./shared"; | ||
const parameters = `${PARAMETERS}: ${node.index.type.typescriptNamespacedName}`; | ||
const options = `options?: ${node.index.table.typescriptNamespacedName}.Options`; | ||
const optionType = `${node.index.type.typescriptNamespacedName}.Options & ${node.index.table.typescriptNamespacedName}.Options`; | ||
const options = `options?: ${optionType}`; | ||
const returns = node.index.unique | ||
@@ -20,0 +21,0 @@ ? `Promise<${node.index.table.type.typescriptNamespacedName}>` |
@@ -104,6 +104,8 @@ /** | ||
(a, i) => | ||
`${a.name} ${node.operators[i]} ${postgresValueExpression( | ||
context, | ||
a, | ||
holder, | ||
`${a.name} ${node.operators[i]} ${a.type.postgresWrapReadParameter( | ||
{ | ||
...context, | ||
currentSymbolName: `options?.${a.typescriptPropertyName}`, | ||
}, | ||
postgresValueExpression(context, a, holder), | ||
)}`, | ||
@@ -110,0 +112,0 @@ ) |
@@ -25,2 +25,4 @@ import { | ||
const parameters = `${PARAMETERS}: ${node.index.type.typescriptNamespacedName}, ${VALUES}: Partial<${node.index.table.typescriptNamespacedName}.Values>`; | ||
const optionType = `${node.index.type.typescriptNamespacedName}.Options & ${node.index.table.typescriptNamespacedName}.Options`; | ||
const options = `options?: ${optionType}`; | ||
const returns = node.index.unique | ||
@@ -34,3 +36,3 @@ ? `Promise<${node.index.table.type.typescriptNamespacedName}>` | ||
generationBuffer.push( | ||
`async ${node.typescriptPropertyName}(${parameters}) : ${returns}{`, | ||
`async ${node.typescriptPropertyName}(${parameters}, ${options}) : ${returns}{`, | ||
); | ||
@@ -37,0 +39,0 @@ generationBuffer.push( |
@@ -71,3 +71,4 @@ import { AllOperation } from "./autocrud/all"; | ||
`export class Database extends PostgresDatabase implements HasDatabase { `, | ||
`get database() { return this};`, | ||
`get database() { return this };`, | ||
`get settings() { return this.context.settings as Settings };`, | ||
` | ||
@@ -74,0 +75,0 @@ /** |
@@ -5,4 +5,6 @@ import { GenerationContext } from ".."; | ||
import { generatePrimaryKeyPickers } from "./generatePrimaryKeyPickers"; | ||
import { generateSettings } from "./generateSettings"; | ||
import { generateTypeComparison } from "./generateTypeComparison"; | ||
import { generateTypeGuards } from "./generateTypeGuards"; | ||
import { generateTypeOptions } from "./generateTypeOptions"; | ||
import { generateTypeParsers } from "./generateTypeParsers"; | ||
@@ -102,2 +104,3 @@ import { | ||
import type { PartiallyOptional, PossiblyEmpty, ReadOptions, Sort } from "@embracesql/shared"; | ||
import { Geometry } from "@embracesql/shared"; | ||
@@ -125,9 +128,2 @@ `, | ||
handlers: { | ||
[ASTKind.Database]: { | ||
before: async () => { | ||
return [ | ||
// schema wide shared | ||
].join("\n"); | ||
}, | ||
}, | ||
[ASTKind.Schema]: NamespaceVisitor, | ||
@@ -174,3 +170,5 @@ [ASTKind.Types]: NamespaceVisitor, | ||
node.type.typescriptNamespacedName | ||
}, Optional & PrimaryKey>`, | ||
}, ${ | ||
node.optionalColumns.length ? "Optional &" : "" | ||
} PrimaryKey>`, | ||
// read options exist per table | ||
@@ -255,4 +253,6 @@ `export ${sortOptions(node.allColumns)};`, | ||
generationBuffer.push(await generateTypeComparison(context)); | ||
generationBuffer.push(await generateTypeOptions(context)); | ||
generationBuffer.push(await generateSettings(context)); | ||
return generationBuffer.join("\n"); | ||
}; |
@@ -23,6 +23,10 @@ import { | ||
// these are flattened names -- no namespacing | ||
context.handlers = { | ||
[ASTKind.Database]: { | ||
before: async () => { | ||
return ` | ||
return await context.database.visit({ | ||
...context, | ||
// include all schemas -- need those built in types | ||
skipSchemas: [], | ||
handlers: { | ||
[ASTKind.Database]: { | ||
before: async () => { | ||
return ` | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -35,15 +39,14 @@ type ArgumentToPostgres = any; | ||
`; | ||
}, | ||
after: async () => { | ||
return `}`; | ||
}, | ||
}, | ||
after: async () => { | ||
return `}`; | ||
}, | ||
[ASTKind.Type]: TypecastEntry, | ||
[ASTKind.Enum]: TypecastEntry, | ||
[ASTKind.CompositeType]: TypecastEntry, | ||
[ASTKind.DomainType]: TypecastEntry, | ||
[ASTKind.ArrayType]: TypecastEntry, | ||
}, | ||
[ASTKind.Type]: TypecastEntry, | ||
[ASTKind.Enum]: TypecastEntry, | ||
[ASTKind.CompositeType]: TypecastEntry, | ||
[ASTKind.DomainType]: TypecastEntry, | ||
[ASTKind.ArrayType]: TypecastEntry, | ||
}; | ||
// include all schemas -- need those built in types | ||
return await context.database.visit({ ...context, skipSchemas: [] }); | ||
}); | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
133854
66
3936
Updated@embracesql/shared@^0.1.1