Skip to content

Commit

Permalink
Export list of query types (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
leo authored Feb 27, 2025
1 parent 9cf7d1b commit 26b1f05
Show file tree
Hide file tree
Showing 20 changed files with 127 additions and 98 deletions.
13 changes: 11 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,5 +578,14 @@ const CLEAN_ROOT_MODEL = omit(ROOT_MODEL, ['system']) as PublicModel;
// Expose the main `Transaction` entrypoint and the root model
export { Transaction, CLEAN_ROOT_MODEL as ROOT_MODEL };

// Expose the main error class and query symbols
export { RoninError, QUERY_SYMBOLS, getQuerySymbol } from '@/src/utils/helpers';
// Expose the main error class and helper functions
export { RoninError, getQuerySymbol } from '@/src/utils/helpers';

// Expose constants
export {
QUERY_SYMBOLS,
DML_READ_QUERY_TYPES,
DML_WRITE_QUERY_TYPES,
DML_QUERY_TYPES,
DDL_QUERY_TYPES,
} from '@/src/utils/constants';
4 changes: 1 addition & 3 deletions src/instructions/selecting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import { getFieldFromModel, getModelBySlug } from '@/src/model';
import type { InternalModelField, Model, ModelField } from '@/src/types/model';
import type { Instructions } from '@/src/types/query';
import { compileQueryInput } from '@/src/utils';
import { QUERY_SYMBOLS, RAW_FIELD_TYPES, type RawFieldType } from '@/src/utils/constants';
import {
QUERY_SYMBOLS,
RAW_FIELD_TYPES,
type RawFieldType,
composeMountingPath,
flatten,
getQuerySymbol,
Expand Down
9 changes: 2 additions & 7 deletions src/instructions/to.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,8 @@ import type {
InternalDependencyStatement,
SetInstructions,
} from '@/src/types/query';
import {
CURRENT_TIME_EXPRESSION,
flatten,
getQuerySymbol,
isObject,
splitQuery,
} from '@/src/utils/helpers';
import { CURRENT_TIME_EXPRESSION } from '@/src/utils/constants';
import { flatten, getQuerySymbol, isObject, splitQuery } from '@/src/utils/helpers';
import { compileQueryInput } from '@/src/utils/index';
import { composeConditions, filterSelectedFields } from '@/src/utils/statement';

Expand Down
3 changes: 2 additions & 1 deletion src/instructions/using.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Model, ModelField, ModelPreset } from '@/src/types/model';
import type { Instructions, SetInstructions } from '@/src/types/query';
import { QUERY_SYMBOLS, RoninError, findInObject, isObject } from '@/src/utils/helpers';
import { QUERY_SYMBOLS } from '@/src/utils/constants';
import { RoninError, findInObject, isObject } from '@/src/utils/helpers';

/**
* Generates the SQL syntax for the `using` query instruction, which allows for quickly
Expand Down
3 changes: 2 additions & 1 deletion src/model/defaults.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getModelBySlug, getSystemFields } from '@/src/model';
import type { Model, ModelField, ModelPreset, PartialModel } from '@/src/types/model';
import { QUERY_SYMBOLS, convertToSnakeCase } from '@/src/utils/helpers';
import { QUERY_SYMBOLS } from '@/src/utils/constants';
import { convertToSnakeCase } from '@/src/utils/helpers';
import title from 'title';

/**
Expand Down
7 changes: 5 additions & 2 deletions src/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ import type {
} from '@/src/types/query';
import {
CURRENT_TIME_EXPRESSION,
MODEL_ENTITY_ERROR_CODES,
type DDL_QUERY_TYPES,
QUERY_SYMBOLS,
} from '@/src/utils/constants';
import {
MODEL_ENTITY_ERROR_CODES,
RoninError,
convertToCamelCase,
convertToSnakeCase,
Expand Down Expand Up @@ -470,7 +473,7 @@ export const PLURAL_MODEL_ENTITIES_VALUES = Object.values(PLURAL_MODEL_ENTITIES)
const handleSystemModel = (
models: Array<Model>,
dependencyStatements: Array<InternalDependencyStatement>,
action: 'create' | 'alter' | 'drop',
action: (typeof DDL_QUERY_TYPES)[number],
inlineDefaults: boolean,
systemModel: PartialModel,
newModel?: PartialModel,
Expand Down
2 changes: 1 addition & 1 deletion src/types/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {
Query,
WithInstruction,
} from '@/src/types/query';
import type { QUERY_SYMBOLS } from '@/src/utils/helpers';
import type { QUERY_SYMBOLS } from '@/src/utils/constants';

type ModelFieldCollation = 'BINARY' | 'NOCASE' | 'RTRIM';

Expand Down
10 changes: 7 additions & 3 deletions src/types/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import type {
Model as PrivateModel,
PublicModel,
} from '@/src/types/model';
import { QUERY_SYMBOLS } from '@/src/utils/helpers';
import {
type DDL_QUERY_TYPES,
type DML_QUERY_TYPES,
QUERY_SYMBOLS,
} from '@/src/utils/constants';

// Query Types
export type QueryTypeEnum = 'get' | 'set' | 'add' | 'remove' | 'count';
export type ModelQueryTypeEnum = 'create' | 'alter' | 'drop';
export type QueryTypeEnum = (typeof DML_QUERY_TYPES)[number];
export type ModelQueryTypeEnum = (typeof DDL_QUERY_TYPES)[number];
export type ModelEntityEnum = 'field' | 'index' | 'trigger' | 'preset';

// Field and Expressions
Expand Down
67 changes: 67 additions & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/** Query types used for reading data. */
export const DML_READ_QUERY_TYPES = ['get', 'count'] as const;

/** Query types used for writing data. */
export const DML_WRITE_QUERY_TYPES = ['set', 'add', 'remove'] as const;

/** Query types used for interacting with data. */
export const DML_QUERY_TYPES = [
...DML_READ_QUERY_TYPES,
...DML_WRITE_QUERY_TYPES,
] as const;

/** Query types used for interacting with the database schema. */
export const DDL_QUERY_TYPES = ['create', 'alter', 'drop'] as const;

/**
* A list of placeholders that can be located inside queries after those queries were
* serialized into JSON objects.
*
* These placeholders are used to represent special keys and values. For example, if a
* query is nested into a query, the nested query will be marked with `__RONIN_QUERY`,
* which allows for distinguishing that nested query from an object of instructions.
*/
export const QUERY_SYMBOLS = {
// Represents a sub query.
QUERY: '__RONIN_QUERY',

// Represents an expression that should be evaluated.
EXPRESSION: '__RONIN_EXPRESSION',

// Represents the value of a field in the model.
FIELD: '__RONIN_FIELD_',

// Represents the value of a field in the model of a parent query.
FIELD_PARENT: '__RONIN_FIELD_PARENT_',

// Represents the old value of a field in the parent model. Used for triggers.
FIELD_PARENT_OLD: '__RONIN_FIELD_PARENT_OLD_',

// Represents the new value of a field in the parent model. Used for triggers.
FIELD_PARENT_NEW: '__RONIN_FIELD_PARENT_NEW_',

// Represents a value provided to a query preset.
VALUE: '__RONIN_VALUE',
} as const;

/**
* A regular expression for matching the symbol that represents a field of a model.
*/
export const RONIN_MODEL_FIELD_REGEX = new RegExp(
`${QUERY_SYMBOLS.FIELD}[_a-zA-Z0-9.]+`,
'g',
);

// JavaScript types that can directly be used as field types in RONIN.
export const RAW_FIELD_TYPES = ['string', 'number', 'boolean'] as const;
export type RawFieldType = (typeof RAW_FIELD_TYPES)[number];

// An expression that produces a timestamp in the format "YYYY-MM-DDTHH:MM:SS.SSSZ",
// which matches the output of `new Date().toISOString()` in JavaScript (ISO 8601).
export const CURRENT_TIME_EXPRESSION = {
[QUERY_SYMBOLS.EXPRESSION]: `strftime('%Y-%m-%dT%H:%M:%f', 'now') || 'Z'`,
};

// A regular expression for splitting up the components of a field mounting path, meaning
// the path within a record under which a particular field's value should be mounted.
export const MOUNTING_PATH_SUFFIX = /(.*?)(\{(\d+)\})?$/;
54 changes: 1 addition & 53 deletions src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,7 @@ import type {
QuerySchemaType,
QueryType,
} from '@/src/types/query';

/**
* A list of placeholders that can be located inside queries after those queries were
* serialized into JSON objects.
*
* These placeholders are used to represent special keys and values. For example, if a
* query is nested into a query, the nested query will be marked with `__RONIN_QUERY`,
* which allows for distinguishing that nested query from an object of instructions.
*/
export const QUERY_SYMBOLS = {
// Represents a sub query.
QUERY: '__RONIN_QUERY',

// Represents an expression that should be evaluated.
EXPRESSION: '__RONIN_EXPRESSION',

// Represents the value of a field in the model.
FIELD: '__RONIN_FIELD_',

// Represents the value of a field in the model of a parent query.
FIELD_PARENT: '__RONIN_FIELD_PARENT_',

// Represents the old value of a field in the parent model. Used for triggers.
FIELD_PARENT_OLD: '__RONIN_FIELD_PARENT_OLD_',

// Represents the new value of a field in the parent model. Used for triggers.
FIELD_PARENT_NEW: '__RONIN_FIELD_PARENT_NEW_',

// Represents a value provided to a query preset.
VALUE: '__RONIN_VALUE',
} as const;

/**
* A regular expression for matching the symbol that represents a field of a model.
*/
export const RONIN_MODEL_FIELD_REGEX = new RegExp(
`${QUERY_SYMBOLS.FIELD}[_a-zA-Z0-9.]+`,
'g',
);

// JavaScript types that can directly be used as field types in RONIN.
export const RAW_FIELD_TYPES = ['string', 'number', 'boolean'] as const;
export type RawFieldType = (typeof RAW_FIELD_TYPES)[number];

// An expression that produces a timestamp in the format "YYYY-MM-DDTHH:MM:SS.SSSZ",
// which matches the output of `new Date().toISOString()` in JavaScript (ISO 8601).
export const CURRENT_TIME_EXPRESSION = {
[QUERY_SYMBOLS.EXPRESSION]: `strftime('%Y-%m-%dT%H:%M:%f', 'now') || 'Z'`,
};

// A regular expression for splitting up the components of a field mounting path, meaning
// the path within a record under which a particular field's value should be mounted.
const MOUNTING_PATH_SUFFIX = /(.*?)(\{(\d+)\})?$/;
import { MOUNTING_PATH_SUFFIX, QUERY_SYMBOLS } from '@/src/utils/constants';

/**
* Determines the mounting path and table alias for a sub query.
Expand Down
5 changes: 3 additions & 2 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import type {
SetInstructions,
Statement,
} from '@/src/types/query';
import { QUERY_SYMBOLS, RoninError, isObject, splitQuery } from '@/src/utils/helpers';
import { DML_WRITE_QUERY_TYPES, QUERY_SYMBOLS } from '@/src/utils/constants';
import { RoninError, isObject, splitQuery } from '@/src/utils/helpers';
import { formatIdentifiers } from '@/src/utils/statement';

/**
Expand Down Expand Up @@ -321,7 +322,7 @@ export const compileQueryInput = (

// For queries that modify records, we want to make sure that the modified record is
// returned after the modification has been performed.
if (['add', 'set', 'remove'].includes(queryType) && returning) {
if ((DML_WRITE_QUERY_TYPES as ReadonlyArray<string>).includes(queryType) && returning) {
statement += `RETURNING ${columns}`;
}

Expand Down
9 changes: 2 additions & 7 deletions src/utils/statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,8 @@ import type {
SetInstructions,
WithInstruction,
} from '@/src/types/query';
import {
QUERY_SYMBOLS,
RONIN_MODEL_FIELD_REGEX,
RoninError,
getQuerySymbol,
isObject,
} from '@/src/utils/helpers';
import { QUERY_SYMBOLS, RONIN_MODEL_FIELD_REGEX } from '@/src/utils/constants';
import { RoninError, getQuerySymbol, isObject } from '@/src/utils/helpers';
import { compileQueryInput } from '@/src/utils/index';

/**
Expand Down
4 changes: 1 addition & 3 deletions tests/errors.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { expect, test } from 'bun:test';
import { type Model, type Query, Transaction } from '@/src/index';

import { RoninError } from '@/src/utils/helpers';
import { type Model, type Query, RoninError, Transaction } from '@/src/index';

test('get single record with non-existing field', () => {
const queries: Array<Query> = [
Expand Down
3 changes: 1 addition & 2 deletions tests/instructions/before-after.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import {
RECORD_TIMESTAMP_REGEX,
queryEphemeralDatabase,
} from '@/fixtures/utils';
import { type Model, type Query, Transaction } from '@/src/index';
import { type Model, type Query, RoninError, Transaction } from '@/src/index';
import type { AmountResult, MultipleRecordResult } from '@/src/types/result';
import { RoninError } from '@/src/utils/helpers';
import { CURSOR_NULL_PLACEHOLDER } from '@/src/utils/pagination';

test('get multiple records before cursor', async () => {
Expand Down
3 changes: 1 addition & 2 deletions tests/instructions/including.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { expect, test } from 'bun:test';
import { type Model, type Query, Transaction } from '@/src/index';
import { type Model, QUERY_SYMBOLS, type Query, Transaction } from '@/src/index';

import {
RECORD_ID_REGEX,
RECORD_TIMESTAMP_REGEX,
queryEphemeralDatabase,
} from '@/fixtures/utils';
import type { MultipleRecordResult, SingleRecordResult } from '@/src/types/result';
import { QUERY_SYMBOLS } from '@/src/utils/helpers';

test('get single record including unrelated record without filter', async () => {
const queries: Array<Query> = [
Expand Down
3 changes: 1 addition & 2 deletions tests/instructions/ordered-by.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { expect, test } from 'bun:test';
import { queryEphemeralDatabase } from '@/fixtures/utils';
import { type Model, type Query, Transaction } from '@/src/index';
import { type Model, QUERY_SYMBOLS, type Query, Transaction } from '@/src/index';
import type { MultipleRecordResult } from '@/src/types/result';
import { QUERY_SYMBOLS } from '@/src/utils/helpers';

test('get multiple records ordered by field', async () => {
const queries: Array<Query> = [
Expand Down
10 changes: 8 additions & 2 deletions tests/instructions/to.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { expect, test } from 'bun:test';
import { type Model, type Query, type StoredObject, Transaction } from '@/src/index';
import {
type Model,
QUERY_SYMBOLS,
type Query,
RoninError,
type StoredObject,
Transaction,
} from '@/src/index';

import { RECORD_TIMESTAMP_REGEX, queryEphemeralDatabase } from '@/fixtures/utils';
import type { MultipleRecordResult, SingleRecordResult } from '@/src/types/result';
import { QUERY_SYMBOLS, RoninError } from '@/src/utils/helpers';

test('set single record to new string field', async () => {
const queries: Array<Query> = [
Expand Down
9 changes: 7 additions & 2 deletions tests/instructions/using.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { expect, test } from 'bun:test';
import { type Model, type Query, Transaction } from '@/src/index';
import {
type Model,
QUERY_SYMBOLS,
type Query,
RoninError,
Transaction,
} from '@/src/index';

import {
RECORD_ID_REGEX,
RECORD_TIMESTAMP_REGEX,
queryEphemeralDatabase,
} from '@/fixtures/utils';
import type { SingleRecordResult } from '@/src/types/result';
import { QUERY_SYMBOLS, RoninError } from '@/src/utils/helpers';

test('get single record using preset', async () => {
const queries: Array<Query> = [
Expand Down
4 changes: 3 additions & 1 deletion tests/meta.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import {
type ModelIndex,
type ModelPreset,
type ModelTrigger,
QUERY_SYMBOLS,
type Query,
ROOT_MODEL,
RoninError,
Transaction,
} from '@/src/index';

Expand All @@ -18,7 +20,7 @@ import {
import { getSystemFields } from '@/src/model';
import { slugToName } from '@/src/model/defaults';
import type { MultipleRecordResult } from '@/src/types/result';
import { QUERY_SYMBOLS, RoninError, omit } from '@/src/utils/helpers';
import { omit } from '@/src/utils/helpers';

test('create new model', () => {
const fields: Model['fields'] = {
Expand Down
3 changes: 1 addition & 2 deletions tests/options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import {
RECORD_TIMESTAMP_REGEX,
queryEphemeralDatabase,
} from '@/fixtures/utils';
import { type Model, type Query, Transaction } from '@/src/index';
import { type Model, QUERY_SYMBOLS, type Query, Transaction } from '@/src/index';
import { getSystemFields } from '@/src/model';
import type { SingleRecordResult } from '@/src/types/result';
import { QUERY_SYMBOLS } from '@/src/utils/helpers';

test('inline statement parameters', async () => {
const queries: Array<Query> = [
Expand Down

0 comments on commit 26b1f05

Please sign in to comment.