From c09314d7e90af0ea6b0cbaa89f7cd8a8c06a3c9c Mon Sep 17 00:00:00 2001 From: j3lte Date: Thu, 13 Apr 2023 04:00:50 +0200 Subject: [PATCH] Better typing --- src/Field.ts | 47 ++++++++++++++++++++++++++++----------------- src/Select.ts | 28 ++++++++++++++++----------- src/Where.ts | 38 ++++++++++++++++++------------------ src/mod.ts | 4 ++-- src/types.ts | 43 ++++++++++++++++++++++------------------- test/Field.test.ts | 24 +++++++++++++---------- test/Select.test.ts | 8 ++------ 7 files changed, 106 insertions(+), 86 deletions(-) diff --git a/src/Field.ts b/src/Field.ts index ab4bdb4..7463194 100644 --- a/src/Field.ts +++ b/src/Field.ts @@ -1,31 +1,42 @@ -import { DataType } from "./types.ts"; -import type { Field, FieldImpl } from "./types.ts"; +import { DataType, FieldImpl } from "./types.ts"; export const testFieldImpl = (field: FieldImpl | null, ...types: DataType[]): boolean => - field === null || types.includes(field.type); + field === null || field?.type === DataType._Unknown || types.includes(field.type); export const getFieldName = (field: string | FieldImpl): string => { return typeof field === "string" ? field : field.name; }; +export class FieldObject { + readonly name: string; + readonly type: T; + + constructor(name: string, type: T) { + this.name = name; + this.type = type; + } + + toString(): string { + return this.name; + } +} + +function Field(name: string): FieldObject; +function Field(name: string, type: T): FieldObject; +function Field(name: string, type?: T): FieldObject { + return new FieldObject(name, type ?? DataType._Unknown); +} + +export { Field }; export const SystemFields: { - Id: Field; - CreatedAt: Field; - UpdatedAt: Field; + Id: FieldObject; + CreatedAt: FieldObject; + UpdatedAt: FieldObject; } = { /** System field: **:id**, Only works in 2.1 */ - Id: { - name: ":id", - type: DataType.RowIdentifier, - }, + Id: Field(":id", DataType.RowIdentifier), /** System field: **:created_at**, Only works in 2.1 */ - CreatedAt: { - name: ":created_at", - type: DataType.FixedTimestamp, - }, + CreatedAt: Field(":created_at", DataType.FixedTimestamp), /** System field: **:updated_at**, Only works in 2.1 */ - UpdatedAt: { - name: ":updated_at", - type: DataType.FixedTimestamp, - }, + UpdatedAt: Field(":updated_at", DataType.FixedTimestamp), }; diff --git a/src/Select.ts b/src/Select.ts index 25ef973..f7b0dda 100644 --- a/src/Select.ts +++ b/src/Select.ts @@ -1,7 +1,7 @@ -import type { Field, FieldImpl } from "./types.ts"; +import type { FieldImpl } from "./types.ts"; import { DataType } from "./types.ts"; -import { getFieldName, testFieldImpl } from "./Field.ts"; +import { FieldObject, getFieldName, testFieldImpl } from "./Field.ts"; import { SelectFunction, SelectImpl } from "./SelectImpl.ts"; /** @@ -38,7 +38,10 @@ function SelectMultipleFunc( */ export function SelectGreatest( ...fields: Array< - string | Field | Field | Field + | string + | FieldObject + | FieldObject + | FieldObject > ): SelectImpl { return SelectMultipleFunc( @@ -56,7 +59,10 @@ export function SelectGreatest( */ export function SelectLeast( ...fields: Array< - string | Field | Field | Field + | string + | FieldObject + | FieldObject + | FieldObject > ): SelectImpl { return SelectMultipleFunc( @@ -73,8 +79,8 @@ export function SelectLeast( * Docs: https://dev.socrata.com/docs/functions/regr_intercept.html */ export function SelectRegrIntercept( - xField: string | Field, - yField: string | Field, + xField: string | FieldObject, + yField: string | FieldObject, ): SelectImpl { return SelectMultipleFunc( SelectFunction.RegrIntercept, @@ -91,8 +97,8 @@ export function SelectRegrIntercept( * Docs: https://dev.socrata.com/docs/functions/regr_r2.html */ export function SelectRegrR2( - xField: string | Field, - yField: string | Field, + xField: string | FieldObject, + yField: string | FieldObject, ): SelectImpl { return SelectMultipleFunc( SelectFunction.RegrR2, @@ -109,8 +115,8 @@ export function SelectRegrR2( * Docs: https://dev.socrata.com/docs/functions/regr_slope.html */ export function SelectRegrSlope( - xField: string | Field, - yField: string | Field, + xField: string | FieldObject, + yField: string | FieldObject, ): SelectImpl { return SelectMultipleFunc( SelectFunction.RegrSlope, @@ -124,7 +130,7 @@ export function SelectRegrSlope( function Select(): SelectImpl; function Select(field: T): SelectImpl; function Select(field: T): SelectImpl; -function Select(field: Field): SelectImpl; +function Select(field: FieldObject): SelectImpl; function Select(field?: string | FieldImpl): SelectImpl { return new SelectImpl(field); } diff --git a/src/Where.ts b/src/Where.ts index 5682e4b..376a286 100644 --- a/src/Where.ts +++ b/src/Where.ts @@ -1,10 +1,10 @@ // TODO(@j3lte) - Fix the 'any' types in this file // deno-lint-ignore-file no-explicit-any -import type { Field, FieldImpl } from "./types.ts"; +import type { FieldImpl } from "./types.ts"; import { replaceParams, SupportTypeElement } from "./utils/param.ts"; -import { getFieldName } from "./Field.ts"; +import { FieldObject, getFieldName } from "./Field.ts"; import { DataType } from "./types.ts"; type BasicType = Exclude; @@ -123,10 +123,10 @@ export class Where { static between( field: | string - | Field - | Field - | Field - | Field, + | FieldObject + | FieldObject + | FieldObject + | FieldObject, startValue: any, endValue: any, ): Where { @@ -141,10 +141,10 @@ export class Where { static notBetween( field: | string - | Field - | Field - | Field - | Field, + | FieldObject + | FieldObject + | FieldObject + | FieldObject, startValue: any, endValue: any, ): Where { @@ -214,7 +214,7 @@ export class Where { * @param lonSE The longitude of the southeast corner of the box */ static withinBox( - field: string | Field, + field: string | FieldObject, latNW: number, lonNW: number, latSE: number, @@ -238,7 +238,7 @@ export class Where { * @param radius The radius of the circle in meters */ static withinCircle( - field: string | Field, + field: string | FieldObject, lat: number, lon: number, radius: number, @@ -257,7 +257,7 @@ export class Where { * @param field The field to search * @param value The value to search for */ - static startsWith(field: string | Field, value: string): Where { + static startsWith(field: string | FieldObject, value: string): Where { return this.expr("starts_with(??, ?)", getFieldName(field), value); } @@ -274,12 +274,12 @@ export class Where { static intersects( field: | string - | Field - | Field - | Field - | Field - | Field - | Field, + | FieldObject + | FieldObject + | FieldObject + | FieldObject + | FieldObject + | FieldObject, value: string, ): Where { return this.expr("intersects(??, ?)", getFieldName(field), value); diff --git a/src/mod.ts b/src/mod.ts index cc95ad0..fc62a71 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -1,4 +1,4 @@ -export type { AuthOpts, DataResponse, Field, FieldImpl, Options, QueryObj } from "./types.ts"; +export type { AuthOpts, DataResponse, FieldImpl, Options, QueryObj } from "./types.ts"; export { DataType } from "./types.ts"; export { createQueryWithDataset, SodaQuery } from "./Query.ts"; @@ -20,4 +20,4 @@ export { Order } from "./Order.ts"; export { expr } from "./utils/expr.ts"; -export { SystemFields } from "./Field.ts"; +export { Field, FieldObject, SystemFields } from "./Field.ts"; diff --git a/src/types.ts b/src/types.ts index 4099f8b..98a7ef0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,4 @@ +import { FieldObject } from "./Field.ts"; /** * The different types of data that can be used in a field */ @@ -34,6 +35,8 @@ export enum DataType { _Unknown = "_unknown", } +export type FieldImpl = FieldObject; + export interface Options { /** Strict mode. If enabled, this prevents the Query from changing the dataset ID after it has been set once */ strict?: boolean; @@ -83,27 +86,27 @@ export interface AuthOpts { accessToken?: string; } -export type Field = { - name: string; - type: T; -}; +// export type Field = { +// name: string; +// type: T; +// }; -export type FieldImpl = - | Field - | Field - | Field - | Field - | Field - | Field - | Field - | Field - | Field - | Field - | Field - | Field - | Field - | Field - | Field; +// export type FieldImpl = +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field +// | Field; export type QueryObj = Record; export type DataResponse = Promise<{ error: Error | null; status: number; data: T }>; diff --git a/test/Field.test.ts b/test/Field.test.ts index ccdb42e..6eefb8b 100644 --- a/test/Field.test.ts +++ b/test/Field.test.ts @@ -1,14 +1,11 @@ -import type { Field } from "../src/types.ts"; +// import type { Field } from "../src/types.ts"; import { assertEquals } from "../dev_deps.ts"; -import { getFieldName, testFieldImpl } from "../src/Field.ts"; +import { Field, getFieldName, testFieldImpl } from "../src/Field.ts"; import { DataType } from "../src/types.ts"; Deno.test("(Field.)testFieldImpl", () => { - const field: Field = { - name: "test", - type: DataType.Checkbox, - }; + const field = Field("test", DataType.Checkbox); assertEquals(testFieldImpl(null), true); assertEquals(testFieldImpl(null, DataType.Checkbox), true); assertEquals(testFieldImpl(field, DataType.Checkbox), true); @@ -19,10 +16,17 @@ Deno.test("(Field.)testFieldImpl", () => { Deno.test("(Field.)getFieldName", () => { assertEquals(getFieldName("test"), "test"); assertEquals( - getFieldName({ - name: "field", - type: DataType.Checkbox, - }), + getFieldName(Field("field", DataType.Checkbox)), "field", ); }); + +Deno.test("(Field.)Field", () => { + const field = Field("test", DataType.Checkbox); + assertEquals(field.name, "test"); + assertEquals(field.type, DataType.Checkbox); + assertEquals(field.toString(), "test"); + + const field2 = Field("test2"); + assertEquals(field2.type, DataType._Unknown); +}); diff --git a/test/Select.test.ts b/test/Select.test.ts index 18f3edf..693e266 100644 --- a/test/Select.test.ts +++ b/test/Select.test.ts @@ -9,13 +9,9 @@ import { SelectRegrSlope, } from "../src/Select.ts"; import { DataType } from "../src/types.ts"; -import type { Field } from "../src/types.ts"; +import { Field } from "../src/Field.ts"; -const createField = (type: T, name = "test"): Field => - ({ - name, - type, - }) as const; +const createField = (type: T, name = "test") => Field(name, type); Deno.test("Select (empty)", () => { const select = Select();