Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sql): add sql standard interfaces #5

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e5458d8
feat(collections): add deferred stack
halvardssm May 30, 2024
933e358
feat(sql): add sql standard interfaces
halvardssm May 30, 2024
e12113e
cleanup
halvardssm May 30, 2024
8d2d6ba
Removed SqlBase with dedicated version
halvardssm Jun 6, 2024
babbcd5
fix(collections): added release and remove callbacks
halvardssm Jun 7, 2024
02e8947
Changed and simplified the structure for inheritance and flow
halvardssm Jun 7, 2024
64505a3
Updated inheritance logic and test cases
halvardssm Jun 20, 2024
55ec4b4
Cleaned up test names
halvardssm Jun 20, 2024
a307add
added coverage to exclude for lint and coverage
halvardssm Jun 20, 2024
a5586af
updated asserts and testing helpers
halvardssm Jun 22, 2024
15be3cd
Updated docs
halvardssm Jun 28, 2024
c6356bf
Updated readme, and added constructor restrictions for clients
halvardssm Jul 13, 2024
152773c
Fixed workspace breaking update
halvardssm Jul 13, 2024
54ad380
fixed type issues
halvardssm Jul 13, 2024
3f022b3
Added deallocated to prepared statement
halvardssm Jul 30, 2024
ae7fc9b
Updated readme
halvardssm Jul 30, 2024
85605ad
Merge branch 'main' of github.com:halvardssm/deno_stdext into feat/sql
halvardssm Aug 10, 2024
1207bcb
renamed directory from sql to database/sql
halvardssm Oct 2, 2024
9627edb
updated readmes and deno.json
halvardssm Oct 2, 2024
9ab2ded
Added local workspaces to imports
halvardssm Oct 2, 2024
ad1db40
updated tests
halvardssm Oct 2, 2024
2bc309d
Updated generics and types
halvardssm Oct 3, 2024
a9718db
Updated names and type signatures
halvardssm Oct 6, 2024
5fa2053
Merge branch 'main' of github.com:halvardssm/deno_stdext into feat/sql
halvardssm Oct 15, 2024
633ba26
Improved readme
halvardssm Oct 15, 2024
4646cce
Added override to inherited class properties
halvardssm Oct 15, 2024
614475c
Added version contraints for packages
halvardssm Oct 15, 2024
e824791
Merge branch 'main' of github.com:halvardssm/deno_stdext into feat/sql
halvardssm Oct 15, 2024
a2b0817
feat(types): added type and improved documentation
halvardssm Oct 16, 2024
ec2c55e
fix(assert): Added message as option argument to asserts, and added o…
halvardssm Oct 16, 2024
ecf2c53
chore(crypto): change ts-ignore to ts-expect-error
halvardssm Oct 16, 2024
87a1f4b
fix(database/sql): cleaned up asserts, improved interfaces, and impro…
halvardssm Oct 16, 2024
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,14 @@ console.log(dump(buffer));

## Packages

- [assert](https://jsr.io/@stdext/assert): The assert package, contains
validators and assertions
- [collections](https://jsr.io/@stdext/collections): The collections package
contains commonly used utilities and structures
- [crypto](https://jsr.io/@stdext/crypto): The crypto package contains utility
for crypto and hashing
- [database](https://jsr.io/@stdext/database): The database package contains
interfaces and helpers for interracting with databases
- [encoding](https://jsr.io/@stdext/encoding): The encoding package contains
utility for text encoding.
- [http](https://jsr.io/@stdext/http): The http package contains utility for
Expand Down
9 changes: 7 additions & 2 deletions assert/is_number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ export function isNumber(value: unknown): value is number {
/**
* Asserts that a value is a number
*/
export function assertIsNumber(value: unknown): asserts value is number {
export function assertIsNumber(
value: unknown,
msg?: string,
): asserts value is number {
if (!isNumber(value)) {
throw new AssertionError(`Value is not a number, was '${value}'`);
const msgSuffix = msg ? `: ${msg}` : ".";
const message = `Value is not a number, was '${value}'${msgSuffix}`;
throw new AssertionError(message);
}
}
9 changes: 7 additions & 2 deletions assert/is_numeric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ export function isNumeric(value: unknown): value is number {
/**
* Asserts that a value is a number and not NaN
*/
export function assertIsNumeric(value: unknown): asserts value is number {
export function assertIsNumeric(
value: unknown,
msg?: string,
): asserts value is number {
if (!isNumeric(value)) {
throw new AssertionError(`Value is not a numeric, was '${value}'`);
const msgSuffix = msg ? `: ${msg}` : ".";
const message = `Value is not a numeric, was '${value}'${msgSuffix}`;
throw new AssertionError(message);
}
}
42 changes: 42 additions & 0 deletions assert/is_object.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { assert, assertFalse, AssertionError, assertThrows } from "@std/assert";
import { assertIsObject, isObject } from "./is_object.ts";

const VALID = [
{},
{ a: 1 },
{ 1: "a" },
{ [Symbol.dispose]: "" },
];

const INVALID = [
"",
1,
undefined,
null,
[],
[""],
new Map(),
];

Deno.test("isObject > can detect records", () => {
for (const v of VALID) {
assert(isObject(v), `Value of '${v}' is not valid`);
}
for (const v of INVALID) {
assertFalse(isObject(v), `Value of '${v}' is not invalid`);
}
});

Deno.test("assertIsObject > can detect records", () => {
for (const v of VALID) {
assertIsObject(v);
}
for (const v of INVALID) {
assertThrows(
() => assertIsObject(v),
AssertionError,
undefined,
`Value of '${v}' did not throw`,
);
}
});
27 changes: 27 additions & 0 deletions assert/is_object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AssertionError } from "@std/assert";
import { objectToStringEquals } from "./utils.ts";

/**
* Checks if a value is an object
*/
export function isObject(value: unknown): value is object {
if (!objectToStringEquals("Object", value)) {
return false;
}

return true;
}

/**
* Asserts that a value is an object
*/
export function assertIsObject(
value: unknown,
msg?: string,
): asserts value is object {
if (!isObject(value)) {
const msgSuffix = msg ? `: ${msg}` : ".";
const message = `Value is not a object, was '${value}'${msgSuffix}`;
throw new AssertionError(message);
}
}
13 changes: 6 additions & 7 deletions assert/is_record.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { AssertionError } from "@std/assert";
import { objectToStringEquals } from "./utils.ts";
import { isObject } from "./is_object.ts";

/**
* Checks if a value is a Record<string, unknown>
*/
export function isRecord(value: unknown): value is Record<string, unknown> {
if (!objectToStringEquals("Object", value)) {
return false;
}

if (typeof value !== "object") {
if (!isObject(value)) {
return false;
}

Expand All @@ -29,8 +25,11 @@ export function isRecord(value: unknown): value is Record<string, unknown> {
*/
export function assertIsRecord(
value: unknown,
msg?: string,
): asserts value is Record<string, unknown> {
if (!isRecord(value)) {
throw new AssertionError(`Value is not a Record, was '${value}'`);
const msgSuffix = msg ? `: ${msg}` : ".";
const message = `Value is not a Record, was '${value}'${msgSuffix}`;
throw new AssertionError(message);
}
}
9 changes: 7 additions & 2 deletions assert/is_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ export function isString(value: unknown): value is string {
/**
* Asserts that a value is a string
*/
export function assertIsString(value: unknown): asserts value is string {
export function assertIsString(
value: unknown,
msg?: string,
): asserts value is string {
if (!isString(value)) {
throw new AssertionError(`Value is not a string, was '${value}'`);
const msgSuffix = msg ? `: ${msg}` : ".";
const message = `Value is not a string, was '${value}'${msgSuffix}`;
throw new AssertionError(message);
}
}
2 changes: 2 additions & 0 deletions assert/mod.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from "./is_number.ts";
export * from "./is_numeric.ts";
export * from "./is_object.ts";
export * from "./is_record.ts";
export * from "./is_string.ts";
export * from "./object_has_properties.ts";
93 changes: 93 additions & 0 deletions assert/object_has_properties.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { assert, assertFalse, AssertionError, assertThrows } from "@std/assert";
import {
assertObjectHasProperties,
assertObjectHasPropertiesDeep,
objectHasProperties,
objectHasPropertiesDeep,
} from "./object_has_properties.ts";

const VALID: Array<[object, Array<PropertyKey>]> = [
[{ [Symbol.for("test")]: 0 }, [Symbol.for("test")]],
[{ 1: 0 }, [1]],
[{ 0: 0 }, [0]],
[{ "": 0 }, [""]],
[{ "test": 0 }, ["test"]],
];

const INVALID: Array<[object, Array<PropertyKey>]> = [
[{}, [Symbol.for("test")]],
[{ [Symbol.for("test2")]: 0 }, [Symbol.for("test")]],
[{}, [1]],
[{}, [""]],
[{}, ["test"]],
];

class NestedClass extends (class {
get test() {
return "test";
}
}) {}
const nestedClass = new NestedClass();

const INVALID_NOT_DEEP: Array<[object, Array<PropertyKey>]> = [
...INVALID,
[nestedClass, ["test"]],
];
const VALID_DEEP: Array<[object, Array<PropertyKey>]> = [
...VALID,
[nestedClass, ["test"]],
];

Deno.test("objectHasProperties > can detect all property keys", () => {
for (const v of VALID) {
assert(
objectHasProperties(v[0], v[1]),
`Value of '${JSON.stringify(v)}' is not valid`,
);
}
for (const v of INVALID_NOT_DEEP) {
assertFalse(
objectHasProperties(v[0], v[1]),
`Value of '${JSON.stringify(v)}' is not invalid`,
);
}
});

Deno.test("assertObjectHasProperties > can detect all property keys", () => {
for (const v of VALID) {
assertObjectHasProperties(v[0], v[1]);
}
for (const v of INVALID) {
assertThrows(
() => assertObjectHasProperties(v[0], v[1]),
AssertionError,
);
}
});

Deno.test("objectHasPropertiesDeep > can detect all property keys", () => {
for (const v of VALID_DEEP) {
assert(
objectHasPropertiesDeep(v[0], v[1]),
`Value of '${JSON.stringify(v)}' is not valid`,
);
}
for (const v of INVALID) {
assertFalse(
objectHasPropertiesDeep(v[0], v[1]),
`Value of '${JSON.stringify(v)}' is not invalid`,
);
}
});

Deno.test("assertObjectHasPropertiesDeep > can detect all property keys", () => {
for (const v of VALID) {
assertObjectHasPropertiesDeep(v[0], v[1]);
}
for (const v of INVALID) {
assertThrows(
() => assertObjectHasPropertiesDeep(v[0], v[1]),
AssertionError,
);
}
});
130 changes: 130 additions & 0 deletions assert/object_has_properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { AssertionError } from "@std/assert";
import { assertIsObject, isObject } from "./is_object.ts";

/**
* Check if an object has a property
*/
function hasProperty<T>(
obj: T,
property: PropertyKey,
deep: boolean,
): boolean {
let currentProto = obj;

while (currentProto !== null && currentProto !== undefined) {
if (Object.hasOwn(currentProto, property)) {
return true;
}
const descriptor = Object.getOwnPropertyDescriptor(
currentProto,
property,
);
if (descriptor !== undefined) {
return true;
}
if (!deep) {
return false;
}
currentProto = Object.getPrototypeOf(currentProto);
}

return false;
}

export function getKeyDiff(
value: object,
keys: Array<PropertyKey>,
deep: boolean,
): Array<PropertyKey> {
const diff: PropertyKey[] = [];

for (const key of keys) {
if (!hasProperty(value, key, deep)) {
diff.push(key);
}
}

return diff;
}

/**
* Checks if an object has given property keys
*/
export function objectHasProperties<T extends PropertyKey = PropertyKey>(
value: unknown,
keys: Array<T>,
): value is Record<T, unknown> {
if (!isObject(value)) {
return false;
}

const diff = getKeyDiff(value, keys, false);

return diff.length < 1;
}

/**
* Asserts that an object has given property keys
*/
export function assertObjectHasProperties<T extends PropertyKey = PropertyKey>(
value: unknown,
keys: Array<T>,
msg?: string,
): asserts value is Record<T, unknown> {
assertIsObject(value);

const diff = getKeyDiff(value, keys, false);

if (diff.length > 0) {
const msgSuffix = msg ? `: ${msg}` : ".";
const message = `The object is missing the following keys: [${
keys.map(String).join(",")
}]${msgSuffix}`;
throw new AssertionError(message);
}
}

/**
* Checks deeply if an object has given property keys
*
* Use when wanting to check for getters and other prototype
* properties on multilevel inheritance
*/
export function objectHasPropertiesDeep<T extends PropertyKey = PropertyKey>(
value: unknown,
keys: Array<T>,
): value is Record<T, unknown> {
if (!isObject(value)) {
return false;
}

const diff = getKeyDiff(value, keys, true);

return diff.length < 1;
}

/**
* Asserts that an object has given property keys
*
* Use when wanting to check for getters and other prototype
* properties on multilevel inheritance
*/
export function assertObjectHasPropertiesDeep<
T extends PropertyKey = PropertyKey,
>(
value: unknown,
keys: Array<T>,
msg?: string,
): asserts value is Record<T, unknown> {
assertIsObject(value);

const diff = getKeyDiff(value, keys, true);

if (diff.length > 0) {
const msgSuffix = msg ? `: ${msg}` : ".";
const message = `The object is missing the following keys: [${
keys.map(String).join(",")
}]${msgSuffix}`;
throw new AssertionError(message);
}
}
Loading